1 /* 2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 3 * 4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License (not later!) 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 */ 21 #define _FILE_OFFSET_BITS 64 22 23 #include <dirent.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <getopt.h> 28 #include <stdarg.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/wait.h> 32 #include <sys/mman.h> 33 #include <pthread.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <errno.h> 37 38 #include "../perf.h" 39 #include "util.h" 40 #include "trace-event.h" 41 42 static int input_fd; 43 44 static int read_page; 45 46 int file_bigendian; 47 int host_bigendian; 48 static int long_size; 49 50 static unsigned long page_size; 51 52 static ssize_t calc_data_size; 53 static bool repipe; 54 55 static int do_read(int fd, void *buf, int size) 56 { 57 int rsize = size; 58 59 while (size) { 60 int ret = read(fd, buf, size); 61 62 if (ret <= 0) 63 return -1; 64 65 if (repipe) { 66 int retw = write(STDOUT_FILENO, buf, ret); 67 68 if (retw <= 0 || retw != ret) 69 die("repiping input file"); 70 } 71 72 size -= ret; 73 buf += ret; 74 } 75 76 return rsize; 77 } 78 79 static int read_or_die(void *data, int size) 80 { 81 int r; 82 83 r = do_read(input_fd, data, size); 84 if (r <= 0) 85 die("reading input file (size expected=%d received=%d)", 86 size, r); 87 88 if (calc_data_size) 89 calc_data_size += r; 90 91 return r; 92 } 93 94 /* If it fails, the next read will report it */ 95 static void skip(int size) 96 { 97 char buf[BUFSIZ]; 98 int r; 99 100 while (size) { 101 r = size > BUFSIZ ? BUFSIZ : size; 102 read_or_die(buf, r); 103 size -= r; 104 }; 105 } 106 107 static unsigned int read4(void) 108 { 109 unsigned int data; 110 111 read_or_die(&data, 4); 112 return __data2host4(data); 113 } 114 115 static unsigned long long read8(void) 116 { 117 unsigned long long data; 118 119 read_or_die(&data, 8); 120 return __data2host8(data); 121 } 122 123 static char *read_string(void) 124 { 125 char buf[BUFSIZ]; 126 char *str = NULL; 127 int size = 0; 128 off_t r; 129 char c; 130 131 for (;;) { 132 r = read(input_fd, &c, 1); 133 if (r < 0) 134 die("reading input file"); 135 136 if (!r) 137 die("no data"); 138 139 if (repipe) { 140 int retw = write(STDOUT_FILENO, &c, 1); 141 142 if (retw <= 0 || retw != r) 143 die("repiping input file string"); 144 } 145 146 buf[size++] = c; 147 148 if (!c) 149 break; 150 } 151 152 if (calc_data_size) 153 calc_data_size += size; 154 155 str = malloc_or_die(size); 156 memcpy(str, buf, size); 157 158 return str; 159 } 160 161 static void read_proc_kallsyms(void) 162 { 163 unsigned int size; 164 char *buf; 165 166 size = read4(); 167 if (!size) 168 return; 169 170 buf = malloc_or_die(size + 1); 171 read_or_die(buf, size); 172 buf[size] = '\0'; 173 174 parse_proc_kallsyms(buf, size); 175 176 free(buf); 177 } 178 179 static void read_ftrace_printk(void) 180 { 181 unsigned int size; 182 char *buf; 183 184 size = read4(); 185 if (!size) 186 return; 187 188 buf = malloc_or_die(size); 189 read_or_die(buf, size); 190 191 parse_ftrace_printk(buf, size); 192 193 free(buf); 194 } 195 196 static void read_header_files(void) 197 { 198 unsigned long long size; 199 char *header_event; 200 char buf[BUFSIZ]; 201 202 read_or_die(buf, 12); 203 204 if (memcmp(buf, "header_page", 12) != 0) 205 die("did not read header page"); 206 207 size = read8(); 208 skip(size); 209 210 /* 211 * The size field in the page is of type long, 212 * use that instead, since it represents the kernel. 213 */ 214 long_size = header_page_size_size; 215 216 read_or_die(buf, 13); 217 if (memcmp(buf, "header_event", 13) != 0) 218 die("did not read header event"); 219 220 size = read8(); 221 header_event = malloc_or_die(size); 222 read_or_die(header_event, size); 223 free(header_event); 224 } 225 226 static void read_ftrace_file(unsigned long long size) 227 { 228 char *buf; 229 230 buf = malloc_or_die(size); 231 read_or_die(buf, size); 232 parse_ftrace_file(buf, size); 233 free(buf); 234 } 235 236 static void read_event_file(char *sys, unsigned long long size) 237 { 238 char *buf; 239 240 buf = malloc_or_die(size); 241 read_or_die(buf, size); 242 parse_event_file(buf, size, sys); 243 free(buf); 244 } 245 246 static void read_ftrace_files(void) 247 { 248 unsigned long long size; 249 int count; 250 int i; 251 252 count = read4(); 253 254 for (i = 0; i < count; i++) { 255 size = read8(); 256 read_ftrace_file(size); 257 } 258 } 259 260 static void read_event_files(void) 261 { 262 unsigned long long size; 263 char *sys; 264 int systems; 265 int count; 266 int i,x; 267 268 systems = read4(); 269 270 for (i = 0; i < systems; i++) { 271 sys = read_string(); 272 273 count = read4(); 274 for (x=0; x < count; x++) { 275 size = read8(); 276 read_event_file(sys, size); 277 } 278 } 279 } 280 281 struct cpu_data { 282 unsigned long long offset; 283 unsigned long long size; 284 unsigned long long timestamp; 285 struct record *next; 286 char *page; 287 int cpu; 288 int index; 289 int page_size; 290 }; 291 292 static struct cpu_data *cpu_data; 293 294 static void update_cpu_data_index(int cpu) 295 { 296 cpu_data[cpu].offset += page_size; 297 cpu_data[cpu].size -= page_size; 298 cpu_data[cpu].index = 0; 299 } 300 301 static void get_next_page(int cpu) 302 { 303 off_t save_seek; 304 off_t ret; 305 306 if (!cpu_data[cpu].page) 307 return; 308 309 if (read_page) { 310 if (cpu_data[cpu].size <= page_size) { 311 free(cpu_data[cpu].page); 312 cpu_data[cpu].page = NULL; 313 return; 314 } 315 316 update_cpu_data_index(cpu); 317 318 /* other parts of the code may expect the pointer to not move */ 319 save_seek = lseek(input_fd, 0, SEEK_CUR); 320 321 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); 322 if (ret == (off_t)-1) 323 die("failed to lseek"); 324 ret = read(input_fd, cpu_data[cpu].page, page_size); 325 if (ret < 0) 326 die("failed to read page"); 327 328 /* reset the file pointer back */ 329 lseek(input_fd, save_seek, SEEK_SET); 330 331 return; 332 } 333 334 munmap(cpu_data[cpu].page, page_size); 335 cpu_data[cpu].page = NULL; 336 337 if (cpu_data[cpu].size <= page_size) 338 return; 339 340 update_cpu_data_index(cpu); 341 342 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, 343 input_fd, cpu_data[cpu].offset); 344 if (cpu_data[cpu].page == MAP_FAILED) 345 die("failed to mmap cpu %d at offset 0x%llx", 346 cpu, cpu_data[cpu].offset); 347 } 348 349 static unsigned int type_len4host(unsigned int type_len_ts) 350 { 351 if (file_bigendian) 352 return (type_len_ts >> 27) & ((1 << 5) - 1); 353 else 354 return type_len_ts & ((1 << 5) - 1); 355 } 356 357 static unsigned int ts4host(unsigned int type_len_ts) 358 { 359 if (file_bigendian) 360 return type_len_ts & ((1 << 27) - 1); 361 else 362 return type_len_ts >> 5; 363 } 364 365 static int calc_index(void *ptr, int cpu) 366 { 367 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 368 } 369 370 struct record *trace_peek_data(int cpu) 371 { 372 struct record *data; 373 void *page = cpu_data[cpu].page; 374 int idx = cpu_data[cpu].index; 375 void *ptr = page + idx; 376 unsigned long long extend; 377 unsigned int type_len_ts; 378 unsigned int type_len; 379 unsigned int delta; 380 unsigned int length = 0; 381 382 if (cpu_data[cpu].next) 383 return cpu_data[cpu].next; 384 385 if (!page) 386 return NULL; 387 388 if (!idx) { 389 /* FIXME: handle header page */ 390 if (header_page_ts_size != 8) 391 die("expected a long long type for timestamp"); 392 cpu_data[cpu].timestamp = data2host8(ptr); 393 ptr += 8; 394 switch (header_page_size_size) { 395 case 4: 396 cpu_data[cpu].page_size = data2host4(ptr); 397 ptr += 4; 398 break; 399 case 8: 400 cpu_data[cpu].page_size = data2host8(ptr); 401 ptr += 8; 402 break; 403 default: 404 die("bad long size"); 405 } 406 ptr = cpu_data[cpu].page + header_page_data_offset; 407 } 408 409 read_again: 410 idx = calc_index(ptr, cpu); 411 412 if (idx >= cpu_data[cpu].page_size) { 413 get_next_page(cpu); 414 return trace_peek_data(cpu); 415 } 416 417 type_len_ts = data2host4(ptr); 418 ptr += 4; 419 420 type_len = type_len4host(type_len_ts); 421 delta = ts4host(type_len_ts); 422 423 switch (type_len) { 424 case RINGBUF_TYPE_PADDING: 425 if (!delta) 426 die("error, hit unexpected end of page"); 427 length = data2host4(ptr); 428 ptr += 4; 429 length *= 4; 430 ptr += length; 431 goto read_again; 432 433 case RINGBUF_TYPE_TIME_EXTEND: 434 extend = data2host4(ptr); 435 ptr += 4; 436 extend <<= TS_SHIFT; 437 extend += delta; 438 cpu_data[cpu].timestamp += extend; 439 goto read_again; 440 441 case RINGBUF_TYPE_TIME_STAMP: 442 ptr += 12; 443 break; 444 case 0: 445 length = data2host4(ptr); 446 ptr += 4; 447 die("here! length=%d", length); 448 break; 449 default: 450 length = type_len * 4; 451 break; 452 } 453 454 cpu_data[cpu].timestamp += delta; 455 456 data = malloc_or_die(sizeof(*data)); 457 memset(data, 0, sizeof(*data)); 458 459 data->ts = cpu_data[cpu].timestamp; 460 data->size = length; 461 data->data = ptr; 462 ptr += length; 463 464 cpu_data[cpu].index = calc_index(ptr, cpu); 465 cpu_data[cpu].next = data; 466 467 return data; 468 } 469 470 struct record *trace_read_data(int cpu) 471 { 472 struct record *data; 473 474 data = trace_peek_data(cpu); 475 cpu_data[cpu].next = NULL; 476 477 return data; 478 } 479 480 ssize_t trace_report(int fd, bool __repipe) 481 { 482 char buf[BUFSIZ]; 483 char test[] = { 23, 8, 68 }; 484 char *version; 485 int show_version = 0; 486 int show_funcs = 0; 487 int show_printk = 0; 488 ssize_t size; 489 490 calc_data_size = 1; 491 repipe = __repipe; 492 493 input_fd = fd; 494 495 read_or_die(buf, 3); 496 if (memcmp(buf, test, 3) != 0) 497 die("no trace data in the file"); 498 499 read_or_die(buf, 7); 500 if (memcmp(buf, "tracing", 7) != 0) 501 die("not a trace file (missing 'tracing' tag)"); 502 503 version = read_string(); 504 if (show_version) 505 printf("version = %s\n", version); 506 free(version); 507 508 read_or_die(buf, 1); 509 file_bigendian = buf[0]; 510 host_bigendian = bigendian(); 511 512 read_or_die(buf, 1); 513 long_size = buf[0]; 514 515 page_size = read4(); 516 517 read_header_files(); 518 519 read_ftrace_files(); 520 read_event_files(); 521 read_proc_kallsyms(); 522 read_ftrace_printk(); 523 524 size = calc_data_size - 1; 525 calc_data_size = 0; 526 repipe = false; 527 528 if (show_funcs) { 529 print_funcs(); 530 return size; 531 } 532 if (show_printk) { 533 print_printk(); 534 return size; 535 } 536 537 return size; 538 } 539