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