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(void) 118 { 119 unsigned int data; 120 121 read_or_die(&data, 4); 122 return __data2host4(perf_pevent, data); 123 } 124 125 static unsigned long long read8(void) 126 { 127 unsigned long long data; 128 129 read_or_die(&data, 8); 130 return __data2host8(perf_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(void) 172 { 173 unsigned int size; 174 char *buf; 175 176 size = read4(); 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(buf, size); 185 186 free(buf); 187 } 188 189 static void read_ftrace_printk(void) 190 { 191 unsigned int size; 192 char *buf; 193 194 size = read4(); 195 if (!size) 196 return; 197 198 buf = malloc_or_die(size); 199 read_or_die(buf, size); 200 201 parse_ftrace_printk(buf, size); 202 203 free(buf); 204 } 205 206 static void read_header_files(void) 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(); 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(); 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(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(buf, size); 243 free(buf); 244 } 245 246 static void read_event_file(char *sys, unsigned long long size) 247 { 248 char *buf; 249 250 buf = malloc_or_die(size); 251 read_or_die(buf, size); 252 parse_event_file(buf, size, sys); 253 free(buf); 254 } 255 256 static void read_ftrace_files(void) 257 { 258 unsigned long long size; 259 int count; 260 int i; 261 262 count = read4(); 263 264 for (i = 0; i < count; i++) { 265 size = read8(); 266 read_ftrace_file(size); 267 } 268 } 269 270 static void read_event_files(void) 271 { 272 unsigned long long size; 273 char *sys; 274 int systems; 275 int count; 276 int i,x; 277 278 systems = read4(); 279 280 for (i = 0; i < systems; i++) { 281 sys = read_string(); 282 283 count = read4(); 284 for (x=0; x < count; x++) { 285 size = read8(); 286 read_event_file(sys, size); 287 } 288 } 289 } 290 291 struct cpu_data { 292 unsigned long long offset; 293 unsigned long long size; 294 unsigned long long timestamp; 295 struct pevent_record *next; 296 char *page; 297 int cpu; 298 int index; 299 int page_size; 300 }; 301 302 static struct cpu_data *cpu_data; 303 304 static void update_cpu_data_index(int cpu) 305 { 306 cpu_data[cpu].offset += page_size; 307 cpu_data[cpu].size -= page_size; 308 cpu_data[cpu].index = 0; 309 } 310 311 static void get_next_page(int cpu) 312 { 313 off_t save_seek; 314 off_t ret; 315 316 if (!cpu_data[cpu].page) 317 return; 318 319 if (read_page) { 320 if (cpu_data[cpu].size <= page_size) { 321 free(cpu_data[cpu].page); 322 cpu_data[cpu].page = NULL; 323 return; 324 } 325 326 update_cpu_data_index(cpu); 327 328 /* other parts of the code may expect the pointer to not move */ 329 save_seek = lseek(input_fd, 0, SEEK_CUR); 330 331 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); 332 if (ret == (off_t)-1) 333 die("failed to lseek"); 334 ret = read(input_fd, cpu_data[cpu].page, page_size); 335 if (ret < 0) 336 die("failed to read page"); 337 338 /* reset the file pointer back */ 339 lseek(input_fd, save_seek, SEEK_SET); 340 341 return; 342 } 343 344 munmap(cpu_data[cpu].page, page_size); 345 cpu_data[cpu].page = NULL; 346 347 if (cpu_data[cpu].size <= page_size) 348 return; 349 350 update_cpu_data_index(cpu); 351 352 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, 353 input_fd, cpu_data[cpu].offset); 354 if (cpu_data[cpu].page == MAP_FAILED) 355 die("failed to mmap cpu %d at offset 0x%llx", 356 cpu, cpu_data[cpu].offset); 357 } 358 359 static unsigned int type_len4host(unsigned int type_len_ts) 360 { 361 if (file_bigendian) 362 return (type_len_ts >> 27) & ((1 << 5) - 1); 363 else 364 return type_len_ts & ((1 << 5) - 1); 365 } 366 367 static unsigned int ts4host(unsigned int type_len_ts) 368 { 369 if (file_bigendian) 370 return type_len_ts & ((1 << 27) - 1); 371 else 372 return type_len_ts >> 5; 373 } 374 375 static int calc_index(void *ptr, int cpu) 376 { 377 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 378 } 379 380 struct pevent_record *trace_peek_data(int cpu) 381 { 382 struct pevent_record *data; 383 void *page = cpu_data[cpu].page; 384 int idx = cpu_data[cpu].index; 385 void *ptr = page + idx; 386 unsigned long long extend; 387 unsigned int type_len_ts; 388 unsigned int type_len; 389 unsigned int delta; 390 unsigned int length = 0; 391 392 if (cpu_data[cpu].next) 393 return cpu_data[cpu].next; 394 395 if (!page) 396 return NULL; 397 398 if (!idx) { 399 /* FIXME: handle header page */ 400 if (header_page_ts_size != 8) 401 die("expected a long long type for timestamp"); 402 cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr); 403 ptr += 8; 404 switch (header_page_size_size) { 405 case 4: 406 cpu_data[cpu].page_size = data2host4(perf_pevent, ptr); 407 ptr += 4; 408 break; 409 case 8: 410 cpu_data[cpu].page_size = data2host8(perf_pevent, ptr); 411 ptr += 8; 412 break; 413 default: 414 die("bad long size"); 415 } 416 ptr = cpu_data[cpu].page + header_page_data_offset; 417 } 418 419 read_again: 420 idx = calc_index(ptr, cpu); 421 422 if (idx >= cpu_data[cpu].page_size) { 423 get_next_page(cpu); 424 return trace_peek_data(cpu); 425 } 426 427 type_len_ts = data2host4(perf_pevent, ptr); 428 ptr += 4; 429 430 type_len = type_len4host(type_len_ts); 431 delta = ts4host(type_len_ts); 432 433 switch (type_len) { 434 case RINGBUF_TYPE_PADDING: 435 if (!delta) 436 die("error, hit unexpected end of page"); 437 length = data2host4(perf_pevent, ptr); 438 ptr += 4; 439 length *= 4; 440 ptr += length; 441 goto read_again; 442 443 case RINGBUF_TYPE_TIME_EXTEND: 444 extend = data2host4(perf_pevent, ptr); 445 ptr += 4; 446 extend <<= TS_SHIFT; 447 extend += delta; 448 cpu_data[cpu].timestamp += extend; 449 goto read_again; 450 451 case RINGBUF_TYPE_TIME_STAMP: 452 ptr += 12; 453 break; 454 case 0: 455 length = data2host4(perf_pevent, ptr); 456 ptr += 4; 457 die("here! length=%d", length); 458 break; 459 default: 460 length = type_len * 4; 461 break; 462 } 463 464 cpu_data[cpu].timestamp += delta; 465 466 data = malloc_or_die(sizeof(*data)); 467 memset(data, 0, sizeof(*data)); 468 469 data->ts = cpu_data[cpu].timestamp; 470 data->size = length; 471 data->data = ptr; 472 ptr += length; 473 474 cpu_data[cpu].index = calc_index(ptr, cpu); 475 cpu_data[cpu].next = data; 476 477 return data; 478 } 479 480 struct pevent_record *trace_read_data(int cpu) 481 { 482 struct pevent_record *data; 483 484 data = trace_peek_data(cpu); 485 cpu_data[cpu].next = NULL; 486 487 return data; 488 } 489 490 ssize_t trace_report(int fd, bool __repipe) 491 { 492 char buf[BUFSIZ]; 493 char test[] = { 23, 8, 68 }; 494 char *version; 495 int show_version = 0; 496 int show_funcs = 0; 497 int show_printk = 0; 498 ssize_t size; 499 500 calc_data_size = 1; 501 repipe = __repipe; 502 503 input_fd = fd; 504 505 read_or_die(buf, 3); 506 if (memcmp(buf, test, 3) != 0) 507 die("no trace data in the file"); 508 509 read_or_die(buf, 7); 510 if (memcmp(buf, "tracing", 7) != 0) 511 die("not a trace file (missing 'tracing' tag)"); 512 513 version = read_string(); 514 if (show_version) 515 printf("version = %s\n", version); 516 free(version); 517 518 read_or_die(buf, 1); 519 file_bigendian = buf[0]; 520 host_bigendian = bigendian(); 521 522 read_trace_init(file_bigendian, host_bigendian); 523 524 read_or_die(buf, 1); 525 long_size = buf[0]; 526 527 page_size = read4(); 528 529 read_header_files(); 530 531 read_ftrace_files(); 532 read_event_files(); 533 read_proc_kallsyms(); 534 read_ftrace_printk(); 535 536 size = calc_data_size - 1; 537 calc_data_size = 0; 538 repipe = false; 539 540 if (show_funcs) { 541 pevent_print_funcs(perf_pevent); 542 return size; 543 } 544 if (show_printk) { 545 pevent_print_printk(perf_pevent); 546 return size; 547 } 548 549 return size; 550 } 551