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