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