1538bafb5SSteven Rostedt /* 2538bafb5SSteven Rostedt * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 3538bafb5SSteven Rostedt * 4538bafb5SSteven Rostedt * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5538bafb5SSteven Rostedt * 6538bafb5SSteven Rostedt * This program is free software; you can redistribute it and/or modify 7538bafb5SSteven Rostedt * it under the terms of the GNU General Public License as published by 8538bafb5SSteven Rostedt * the Free Software Foundation; version 2 of the License (not later!) 9538bafb5SSteven Rostedt * 10538bafb5SSteven Rostedt * This program is distributed in the hope that it will be useful, 11538bafb5SSteven Rostedt * but WITHOUT ANY WARRANTY; without even the implied warranty of 12538bafb5SSteven Rostedt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13538bafb5SSteven Rostedt * GNU General Public License for more details. 14538bafb5SSteven Rostedt * 15538bafb5SSteven Rostedt * You should have received a copy of the GNU General Public License 16538bafb5SSteven Rostedt * along with this program; if not, write to the Free Software 17538bafb5SSteven Rostedt * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18538bafb5SSteven Rostedt * 19538bafb5SSteven Rostedt * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20538bafb5SSteven Rostedt */ 21538bafb5SSteven Rostedt #include <dirent.h> 22538bafb5SSteven Rostedt #include <stdio.h> 23538bafb5SSteven Rostedt #include <stdlib.h> 24538bafb5SSteven Rostedt #include <string.h> 25538bafb5SSteven Rostedt #include <getopt.h> 26538bafb5SSteven Rostedt #include <stdarg.h> 27538bafb5SSteven Rostedt #include <sys/types.h> 28538bafb5SSteven Rostedt #include <sys/stat.h> 29538bafb5SSteven Rostedt #include <sys/wait.h> 30538bafb5SSteven Rostedt #include <sys/mman.h> 31538bafb5SSteven Rostedt #include <pthread.h> 32538bafb5SSteven Rostedt #include <fcntl.h> 33538bafb5SSteven Rostedt #include <unistd.h> 34538bafb5SSteven Rostedt #include <errno.h> 35538bafb5SSteven Rostedt 361ef2ed10SFrederic Weisbecker #include "../perf.h" 37538bafb5SSteven Rostedt #include "util.h" 38538bafb5SSteven Rostedt #include "trace-event.h" 39538bafb5SSteven Rostedt 40538bafb5SSteven Rostedt static int input_fd; 41538bafb5SSteven Rostedt 42538bafb5SSteven Rostedt int file_bigendian; 43538bafb5SSteven Rostedt int host_bigendian; 44538bafb5SSteven Rostedt static int long_size; 45538bafb5SSteven Rostedt 469215545eSTom Zanussi static ssize_t calc_data_size; 47454c407eSTom Zanussi static bool repipe; 489215545eSTom Zanussi 49aaf045f7SSteven Rostedt static void *malloc_or_die(int size) 50aaf045f7SSteven Rostedt { 51aaf045f7SSteven Rostedt void *ret; 52aaf045f7SSteven Rostedt 53aaf045f7SSteven Rostedt ret = malloc(size); 54aaf045f7SSteven Rostedt if (!ret) 55aaf045f7SSteven Rostedt die("malloc"); 56aaf045f7SSteven Rostedt return ret; 57aaf045f7SSteven Rostedt } 58aaf045f7SSteven Rostedt 599215545eSTom Zanussi static int do_read(int fd, void *buf, int size) 609215545eSTom Zanussi { 619215545eSTom Zanussi int rsize = size; 629215545eSTom Zanussi 639215545eSTom Zanussi while (size) { 649215545eSTom Zanussi int ret = read(fd, buf, size); 659215545eSTom Zanussi 669215545eSTom Zanussi if (ret <= 0) 679215545eSTom Zanussi return -1; 689215545eSTom Zanussi 69454c407eSTom Zanussi if (repipe) { 70454c407eSTom Zanussi int retw = write(STDOUT_FILENO, buf, ret); 71454c407eSTom Zanussi 72454c407eSTom Zanussi if (retw <= 0 || retw != ret) 73454c407eSTom Zanussi die("repiping input file"); 74454c407eSTom Zanussi } 75454c407eSTom Zanussi 769215545eSTom Zanussi size -= ret; 779215545eSTom Zanussi buf += ret; 789215545eSTom Zanussi } 799215545eSTom Zanussi 809215545eSTom Zanussi return rsize; 819215545eSTom Zanussi } 829215545eSTom Zanussi 83538bafb5SSteven Rostedt static int read_or_die(void *data, int size) 84538bafb5SSteven Rostedt { 85538bafb5SSteven Rostedt int r; 86538bafb5SSteven Rostedt 879215545eSTom Zanussi r = do_read(input_fd, data, size); 889215545eSTom Zanussi if (r <= 0) 89538bafb5SSteven Rostedt die("reading input file (size expected=%d received=%d)", 90538bafb5SSteven Rostedt size, r); 919215545eSTom Zanussi 929215545eSTom Zanussi if (calc_data_size) 939215545eSTom Zanussi calc_data_size += r; 949215545eSTom Zanussi 95538bafb5SSteven Rostedt return r; 96538bafb5SSteven Rostedt } 97538bafb5SSteven Rostedt 98cbb5cf7fSTom Zanussi /* If it fails, the next read will report it */ 99cbb5cf7fSTom Zanussi static void skip(int size) 100cbb5cf7fSTom Zanussi { 101cbb5cf7fSTom Zanussi char buf[BUFSIZ]; 102cbb5cf7fSTom Zanussi int r; 103cbb5cf7fSTom Zanussi 104cbb5cf7fSTom Zanussi while (size) { 105cbb5cf7fSTom Zanussi r = size > BUFSIZ ? BUFSIZ : size; 106cbb5cf7fSTom Zanussi read_or_die(buf, r); 107cbb5cf7fSTom Zanussi size -= r; 108cbb5cf7fSTom Zanussi }; 109cbb5cf7fSTom Zanussi } 110cbb5cf7fSTom Zanussi 111da378962SArnaldo Carvalho de Melo static unsigned int read4(struct pevent *pevent) 112538bafb5SSteven Rostedt { 113538bafb5SSteven Rostedt unsigned int data; 114538bafb5SSteven Rostedt 115538bafb5SSteven Rostedt read_or_die(&data, 4); 116da378962SArnaldo Carvalho de Melo return __data2host4(pevent, data); 117538bafb5SSteven Rostedt } 118538bafb5SSteven Rostedt 119da378962SArnaldo Carvalho de Melo static unsigned long long read8(struct pevent *pevent) 120538bafb5SSteven Rostedt { 121538bafb5SSteven Rostedt unsigned long long data; 122538bafb5SSteven Rostedt 123538bafb5SSteven Rostedt read_or_die(&data, 8); 124da378962SArnaldo Carvalho de Melo return __data2host8(pevent, data); 125538bafb5SSteven Rostedt } 126538bafb5SSteven Rostedt 127538bafb5SSteven Rostedt static char *read_string(void) 128538bafb5SSteven Rostedt { 129538bafb5SSteven Rostedt char buf[BUFSIZ]; 130538bafb5SSteven Rostedt char *str = NULL; 131538bafb5SSteven Rostedt int size = 0; 132f887f301SXiao Guangrong off_t r; 1339215545eSTom Zanussi char c; 134538bafb5SSteven Rostedt 135538bafb5SSteven Rostedt for (;;) { 1369215545eSTom Zanussi r = read(input_fd, &c, 1); 137538bafb5SSteven Rostedt if (r < 0) 138538bafb5SSteven Rostedt die("reading input file"); 139538bafb5SSteven Rostedt 140538bafb5SSteven Rostedt if (!r) 141538bafb5SSteven Rostedt die("no data"); 142538bafb5SSteven Rostedt 143454c407eSTom Zanussi if (repipe) { 144454c407eSTom Zanussi int retw = write(STDOUT_FILENO, &c, 1); 145454c407eSTom Zanussi 146454c407eSTom Zanussi if (retw <= 0 || retw != r) 147454c407eSTom Zanussi die("repiping input file string"); 148454c407eSTom Zanussi } 149454c407eSTom Zanussi 1509215545eSTom Zanussi buf[size++] = c; 1519215545eSTom Zanussi 1529215545eSTom Zanussi if (!c) 153538bafb5SSteven Rostedt break; 154538bafb5SSteven Rostedt } 155538bafb5SSteven Rostedt 1569215545eSTom Zanussi if (calc_data_size) 1579215545eSTom Zanussi calc_data_size += size; 1589215545eSTom Zanussi 159538bafb5SSteven Rostedt str = malloc_or_die(size); 160538bafb5SSteven Rostedt memcpy(str, buf, size); 161538bafb5SSteven Rostedt 162538bafb5SSteven Rostedt return str; 163538bafb5SSteven Rostedt } 164538bafb5SSteven Rostedt 165da378962SArnaldo Carvalho de Melo static void read_proc_kallsyms(struct pevent *pevent) 166538bafb5SSteven Rostedt { 167538bafb5SSteven Rostedt unsigned int size; 168538bafb5SSteven Rostedt char *buf; 169538bafb5SSteven Rostedt 170da378962SArnaldo Carvalho de Melo size = read4(pevent); 171538bafb5SSteven Rostedt if (!size) 172538bafb5SSteven Rostedt return; 173538bafb5SSteven Rostedt 1747691b1ecSOGAWA Hirofumi buf = malloc_or_die(size + 1); 175538bafb5SSteven Rostedt read_or_die(buf, size); 1767691b1ecSOGAWA Hirofumi buf[size] = '\0'; 177538bafb5SSteven Rostedt 178da378962SArnaldo Carvalho de Melo parse_proc_kallsyms(pevent, buf, size); 179538bafb5SSteven Rostedt 180538bafb5SSteven Rostedt free(buf); 181538bafb5SSteven Rostedt } 182538bafb5SSteven Rostedt 183da378962SArnaldo Carvalho de Melo static void read_ftrace_printk(struct pevent *pevent) 184538bafb5SSteven Rostedt { 185538bafb5SSteven Rostedt unsigned int size; 186538bafb5SSteven Rostedt char *buf; 187538bafb5SSteven Rostedt 188da378962SArnaldo Carvalho de Melo size = read4(pevent); 189538bafb5SSteven Rostedt if (!size) 190538bafb5SSteven Rostedt return; 191538bafb5SSteven Rostedt 192538bafb5SSteven Rostedt buf = malloc_or_die(size); 193538bafb5SSteven Rostedt read_or_die(buf, size); 194538bafb5SSteven Rostedt 195da378962SArnaldo Carvalho de Melo parse_ftrace_printk(pevent, buf, size); 196538bafb5SSteven Rostedt 197538bafb5SSteven Rostedt free(buf); 198538bafb5SSteven Rostedt } 199538bafb5SSteven Rostedt 200da378962SArnaldo Carvalho de Melo static void read_header_files(struct pevent *pevent) 201538bafb5SSteven Rostedt { 202538bafb5SSteven Rostedt unsigned long long size; 203538bafb5SSteven Rostedt char *header_event; 204538bafb5SSteven Rostedt char buf[BUFSIZ]; 205538bafb5SSteven Rostedt 206538bafb5SSteven Rostedt read_or_die(buf, 12); 207538bafb5SSteven Rostedt 208538bafb5SSteven Rostedt if (memcmp(buf, "header_page", 12) != 0) 209538bafb5SSteven Rostedt die("did not read header page"); 210538bafb5SSteven Rostedt 211da378962SArnaldo Carvalho de Melo size = read8(pevent); 212d00a47ccSFrederic Weisbecker skip(size); 213538bafb5SSteven Rostedt 214538bafb5SSteven Rostedt /* 215538bafb5SSteven Rostedt * The size field in the page is of type long, 216538bafb5SSteven Rostedt * use that instead, since it represents the kernel. 217538bafb5SSteven Rostedt */ 218538bafb5SSteven Rostedt long_size = header_page_size_size; 219538bafb5SSteven Rostedt 220538bafb5SSteven Rostedt read_or_die(buf, 13); 221538bafb5SSteven Rostedt if (memcmp(buf, "header_event", 13) != 0) 222538bafb5SSteven Rostedt die("did not read header event"); 223538bafb5SSteven Rostedt 224da378962SArnaldo Carvalho de Melo size = read8(pevent); 225538bafb5SSteven Rostedt header_event = malloc_or_die(size); 226538bafb5SSteven Rostedt read_or_die(header_event, size); 227538bafb5SSteven Rostedt free(header_event); 228538bafb5SSteven Rostedt } 229538bafb5SSteven Rostedt 230da378962SArnaldo Carvalho de Melo static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 231538bafb5SSteven Rostedt { 232538bafb5SSteven Rostedt char *buf; 233538bafb5SSteven Rostedt 234538bafb5SSteven Rostedt buf = malloc_or_die(size); 235538bafb5SSteven Rostedt read_or_die(buf, size); 236da378962SArnaldo Carvalho de Melo parse_ftrace_file(pevent, buf, size); 237538bafb5SSteven Rostedt free(buf); 238538bafb5SSteven Rostedt } 239538bafb5SSteven Rostedt 240da378962SArnaldo Carvalho de Melo static void read_event_file(struct pevent *pevent, char *sys, 241da378962SArnaldo Carvalho de Melo unsigned long long size) 242538bafb5SSteven Rostedt { 243538bafb5SSteven Rostedt char *buf; 244538bafb5SSteven Rostedt 245538bafb5SSteven Rostedt buf = malloc_or_die(size); 246538bafb5SSteven Rostedt read_or_die(buf, size); 247da378962SArnaldo Carvalho de Melo parse_event_file(pevent, buf, size, sys); 248538bafb5SSteven Rostedt free(buf); 249538bafb5SSteven Rostedt } 250538bafb5SSteven Rostedt 251da378962SArnaldo Carvalho de Melo static void read_ftrace_files(struct pevent *pevent) 252538bafb5SSteven Rostedt { 253538bafb5SSteven Rostedt unsigned long long size; 254538bafb5SSteven Rostedt int count; 255538bafb5SSteven Rostedt int i; 256538bafb5SSteven Rostedt 257da378962SArnaldo Carvalho de Melo count = read4(pevent); 258538bafb5SSteven Rostedt 259538bafb5SSteven Rostedt for (i = 0; i < count; i++) { 260da378962SArnaldo Carvalho de Melo size = read8(pevent); 261da378962SArnaldo Carvalho de Melo read_ftrace_file(pevent, size); 262538bafb5SSteven Rostedt } 263538bafb5SSteven Rostedt } 264538bafb5SSteven Rostedt 265da378962SArnaldo Carvalho de Melo static void read_event_files(struct pevent *pevent) 266538bafb5SSteven Rostedt { 267538bafb5SSteven Rostedt unsigned long long size; 268538bafb5SSteven Rostedt char *sys; 269538bafb5SSteven Rostedt int systems; 270538bafb5SSteven Rostedt int count; 271538bafb5SSteven Rostedt int i,x; 272538bafb5SSteven Rostedt 273da378962SArnaldo Carvalho de Melo systems = read4(pevent); 274538bafb5SSteven Rostedt 275538bafb5SSteven Rostedt for (i = 0; i < systems; i++) { 276538bafb5SSteven Rostedt sys = read_string(); 277538bafb5SSteven Rostedt 278da378962SArnaldo Carvalho de Melo count = read4(pevent); 279538bafb5SSteven Rostedt for (x=0; x < count; x++) { 280da378962SArnaldo Carvalho de Melo size = read8(pevent); 281da378962SArnaldo Carvalho de Melo read_event_file(pevent, sys, size); 282538bafb5SSteven Rostedt } 283538bafb5SSteven Rostedt } 284538bafb5SSteven Rostedt } 285538bafb5SSteven Rostedt 286da378962SArnaldo Carvalho de Melo ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 287538bafb5SSteven Rostedt { 288538bafb5SSteven Rostedt char buf[BUFSIZ]; 289538bafb5SSteven Rostedt char test[] = { 23, 8, 68 }; 290538bafb5SSteven Rostedt char *version; 291d9340c1dSIngo Molnar int show_version = 0; 292538bafb5SSteven Rostedt int show_funcs = 0; 293538bafb5SSteven Rostedt int show_printk = 0; 2943dce2ce3SNamhyung Kim ssize_t size = -1; 2953dce2ce3SNamhyung Kim struct pevent *pevent; 2963dce2ce3SNamhyung Kim 2973dce2ce3SNamhyung Kim *ppevent = NULL; 2989215545eSTom Zanussi 2999215545eSTom Zanussi calc_data_size = 1; 300454c407eSTom Zanussi repipe = __repipe; 301538bafb5SSteven Rostedt 30203456a15SFrederic Weisbecker input_fd = fd; 303538bafb5SSteven Rostedt 304538bafb5SSteven Rostedt read_or_die(buf, 3); 305538bafb5SSteven Rostedt if (memcmp(buf, test, 3) != 0) 306e2561368SArnaldo Carvalho de Melo die("no trace data in the file"); 307538bafb5SSteven Rostedt 308538bafb5SSteven Rostedt read_or_die(buf, 7); 309538bafb5SSteven Rostedt if (memcmp(buf, "tracing", 7) != 0) 310e2561368SArnaldo Carvalho de Melo die("not a trace file (missing 'tracing' tag)"); 311538bafb5SSteven Rostedt 312538bafb5SSteven Rostedt version = read_string(); 313d9340c1dSIngo Molnar if (show_version) 314538bafb5SSteven Rostedt printf("version = %s\n", version); 315538bafb5SSteven Rostedt free(version); 316538bafb5SSteven Rostedt 317538bafb5SSteven Rostedt read_or_die(buf, 1); 318538bafb5SSteven Rostedt file_bigendian = buf[0]; 319538bafb5SSteven Rostedt host_bigendian = bigendian(); 320538bafb5SSteven Rostedt 3213dce2ce3SNamhyung Kim pevent = read_trace_init(file_bigendian, host_bigendian); 3223dce2ce3SNamhyung Kim if (pevent == NULL) { 3233dce2ce3SNamhyung Kim pr_debug("read_trace_init failed"); 3243dce2ce3SNamhyung Kim goto out; 3253dce2ce3SNamhyung Kim } 326aaf045f7SSteven Rostedt 327538bafb5SSteven Rostedt read_or_die(buf, 1); 328538bafb5SSteven Rostedt long_size = buf[0]; 329538bafb5SSteven Rostedt 3303dce2ce3SNamhyung Kim page_size = read4(pevent); 331538bafb5SSteven Rostedt 3323dce2ce3SNamhyung Kim read_header_files(pevent); 3333dce2ce3SNamhyung Kim read_ftrace_files(pevent); 3343dce2ce3SNamhyung Kim read_event_files(pevent); 3353dce2ce3SNamhyung Kim read_proc_kallsyms(pevent); 3363dce2ce3SNamhyung Kim read_ftrace_printk(pevent); 337538bafb5SSteven Rostedt 3389215545eSTom Zanussi size = calc_data_size - 1; 3399215545eSTom Zanussi calc_data_size = 0; 340454c407eSTom Zanussi repipe = false; 3419215545eSTom Zanussi 342538bafb5SSteven Rostedt if (show_funcs) { 3433dce2ce3SNamhyung Kim pevent_print_funcs(pevent); 3443dce2ce3SNamhyung Kim } else if (show_printk) { 3453dce2ce3SNamhyung Kim pevent_print_printk(pevent); 346538bafb5SSteven Rostedt } 347538bafb5SSteven Rostedt 3483dce2ce3SNamhyung Kim *ppevent = pevent; 3493dce2ce3SNamhyung Kim pevent = NULL; 3503dce2ce3SNamhyung Kim 3513dce2ce3SNamhyung Kim out: 3523dce2ce3SNamhyung Kim if (pevent) 3533dce2ce3SNamhyung Kim pevent_free(pevent); 3549215545eSTom Zanussi return size; 355538bafb5SSteven Rostedt } 356