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