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 #include <dirent.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <getopt.h> 26 #include <stdarg.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/wait.h> 30 #include <sys/mman.h> 31 #include <pthread.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <errno.h> 35 36 #include "../perf.h" 37 #include "util.h" 38 #include "trace-event.h" 39 40 static int input_fd; 41 42 static ssize_t trace_data_size; 43 static bool repipe; 44 45 static int __do_read(int fd, void *buf, int size) 46 { 47 int rsize = size; 48 49 while (size) { 50 int ret = read(fd, buf, size); 51 52 if (ret <= 0) 53 return -1; 54 55 if (repipe) { 56 int retw = write(STDOUT_FILENO, buf, ret); 57 58 if (retw <= 0 || retw != ret) { 59 pr_debug("repiping input file"); 60 return -1; 61 } 62 } 63 64 size -= ret; 65 buf += ret; 66 } 67 68 return rsize; 69 } 70 71 static int do_read(void *data, int size) 72 { 73 int r; 74 75 r = __do_read(input_fd, data, size); 76 if (r <= 0) { 77 pr_debug("reading input file (size expected=%d received=%d)", 78 size, r); 79 return -1; 80 } 81 82 trace_data_size += r; 83 84 return r; 85 } 86 87 /* If it fails, the next read will report it */ 88 static void skip(int size) 89 { 90 char buf[BUFSIZ]; 91 int r; 92 93 while (size) { 94 r = size > BUFSIZ ? BUFSIZ : size; 95 do_read(buf, r); 96 size -= r; 97 }; 98 } 99 100 static unsigned int read4(struct pevent *pevent) 101 { 102 unsigned int data; 103 104 if (do_read(&data, 4) < 0) 105 return 0; 106 return __data2host4(pevent, data); 107 } 108 109 static unsigned long long read8(struct pevent *pevent) 110 { 111 unsigned long long data; 112 113 if (do_read(&data, 8) < 0) 114 return 0; 115 return __data2host8(pevent, data); 116 } 117 118 static char *read_string(void) 119 { 120 char buf[BUFSIZ]; 121 char *str = NULL; 122 int size = 0; 123 off_t r; 124 char c; 125 126 for (;;) { 127 r = read(input_fd, &c, 1); 128 if (r < 0) { 129 pr_debug("reading input file"); 130 goto out; 131 } 132 133 if (!r) { 134 pr_debug("no data"); 135 goto out; 136 } 137 138 if (repipe) { 139 int retw = write(STDOUT_FILENO, &c, 1); 140 141 if (retw <= 0 || retw != r) { 142 pr_debug("repiping input file string"); 143 goto out; 144 } 145 } 146 147 buf[size++] = c; 148 149 if (!c) 150 break; 151 } 152 153 trace_data_size += size; 154 155 str = malloc(size); 156 if (str) 157 memcpy(str, buf, size); 158 out: 159 return str; 160 } 161 162 static int read_proc_kallsyms(struct pevent *pevent) 163 { 164 unsigned int size; 165 char *buf; 166 167 size = read4(pevent); 168 if (!size) 169 return 0; 170 171 buf = malloc(size + 1); 172 if (buf == NULL) 173 return -1; 174 175 if (do_read(buf, size) < 0) { 176 free(buf); 177 return -1; 178 } 179 buf[size] = '\0'; 180 181 parse_proc_kallsyms(pevent, buf, size); 182 183 free(buf); 184 return 0; 185 } 186 187 static int read_ftrace_printk(struct pevent *pevent) 188 { 189 unsigned int size; 190 char *buf; 191 192 /* it can have 0 size */ 193 size = read4(pevent); 194 if (!size) 195 return 0; 196 197 buf = malloc(size); 198 if (buf == NULL) 199 return -1; 200 201 if (do_read(buf, size) < 0) { 202 free(buf); 203 return -1; 204 } 205 206 parse_ftrace_printk(pevent, buf, size); 207 208 free(buf); 209 return 0; 210 } 211 212 static int read_header_files(struct pevent *pevent) 213 { 214 unsigned long long size; 215 char *header_page; 216 char buf[BUFSIZ]; 217 int ret = 0; 218 219 if (do_read(buf, 12) < 0) 220 return -1; 221 222 if (memcmp(buf, "header_page", 12) != 0) { 223 pr_debug("did not read header page"); 224 return -1; 225 } 226 227 size = read8(pevent); 228 229 header_page = malloc(size); 230 if (header_page == NULL) 231 return -1; 232 233 if (do_read(header_page, size) < 0) { 234 pr_debug("did not read header page"); 235 free(header_page); 236 return -1; 237 } 238 239 if (!pevent_parse_header_page(pevent, header_page, size, 240 pevent_get_long_size(pevent))) { 241 /* 242 * The commit field in the page is of type long, 243 * use that instead, since it represents the kernel. 244 */ 245 pevent_set_long_size(pevent, pevent->header_page_size_size); 246 } 247 free(header_page); 248 249 if (do_read(buf, 13) < 0) 250 return -1; 251 252 if (memcmp(buf, "header_event", 13) != 0) { 253 pr_debug("did not read header event"); 254 return -1; 255 } 256 257 size = read8(pevent); 258 skip(size); 259 260 return ret; 261 } 262 263 static int read_ftrace_file(struct pevent *pevent, unsigned long long size) 264 { 265 char *buf; 266 267 buf = malloc(size); 268 if (buf == NULL) 269 return -1; 270 271 if (do_read(buf, size) < 0) { 272 free(buf); 273 return -1; 274 } 275 276 parse_ftrace_file(pevent, buf, size); 277 free(buf); 278 return 0; 279 } 280 281 static int read_event_file(struct pevent *pevent, char *sys, 282 unsigned long long size) 283 { 284 char *buf; 285 286 buf = malloc(size); 287 if (buf == NULL) 288 return -1; 289 290 if (do_read(buf, size) < 0) { 291 free(buf); 292 return -1; 293 } 294 295 parse_event_file(pevent, buf, size, sys); 296 free(buf); 297 return 0; 298 } 299 300 static int read_ftrace_files(struct pevent *pevent) 301 { 302 unsigned long long size; 303 int count; 304 int i; 305 int ret; 306 307 count = read4(pevent); 308 309 for (i = 0; i < count; i++) { 310 size = read8(pevent); 311 ret = read_ftrace_file(pevent, size); 312 if (ret) 313 return ret; 314 } 315 return 0; 316 } 317 318 static int read_event_files(struct pevent *pevent) 319 { 320 unsigned long long size; 321 char *sys; 322 int systems; 323 int count; 324 int i,x; 325 int ret; 326 327 systems = read4(pevent); 328 329 for (i = 0; i < systems; i++) { 330 sys = read_string(); 331 if (sys == NULL) 332 return -1; 333 334 count = read4(pevent); 335 336 for (x=0; x < count; x++) { 337 size = read8(pevent); 338 ret = read_event_file(pevent, sys, size); 339 if (ret) 340 return ret; 341 } 342 } 343 return 0; 344 } 345 346 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 347 { 348 char buf[BUFSIZ]; 349 char test[] = { 23, 8, 68 }; 350 char *version; 351 int show_version = 0; 352 int show_funcs = 0; 353 int show_printk = 0; 354 ssize_t size = -1; 355 int file_bigendian; 356 int host_bigendian; 357 int file_long_size; 358 int file_page_size; 359 struct pevent *pevent; 360 int err; 361 362 *ppevent = NULL; 363 364 repipe = __repipe; 365 input_fd = fd; 366 367 if (do_read(buf, 3) < 0) 368 return -1; 369 if (memcmp(buf, test, 3) != 0) { 370 pr_debug("no trace data in the file"); 371 return -1; 372 } 373 374 if (do_read(buf, 7) < 0) 375 return -1; 376 if (memcmp(buf, "tracing", 7) != 0) { 377 pr_debug("not a trace file (missing 'tracing' tag)"); 378 return -1; 379 } 380 381 version = read_string(); 382 if (version == NULL) 383 return -1; 384 if (show_version) 385 printf("version = %s\n", version); 386 free(version); 387 388 if (do_read(buf, 1) < 0) 389 return -1; 390 file_bigendian = buf[0]; 391 host_bigendian = bigendian(); 392 393 pevent = read_trace_init(file_bigendian, host_bigendian); 394 if (pevent == NULL) { 395 pr_debug("read_trace_init failed"); 396 goto out; 397 } 398 399 if (do_read(buf, 1) < 0) 400 goto out; 401 file_long_size = buf[0]; 402 403 file_page_size = read4(pevent); 404 if (!file_page_size) 405 goto out; 406 407 pevent_set_long_size(pevent, file_long_size); 408 pevent_set_page_size(pevent, file_page_size); 409 410 err = read_header_files(pevent); 411 if (err) 412 goto out; 413 err = read_ftrace_files(pevent); 414 if (err) 415 goto out; 416 err = read_event_files(pevent); 417 if (err) 418 goto out; 419 err = read_proc_kallsyms(pevent); 420 if (err) 421 goto out; 422 err = read_ftrace_printk(pevent); 423 if (err) 424 goto out; 425 426 size = trace_data_size; 427 repipe = false; 428 429 if (show_funcs) { 430 pevent_print_funcs(pevent); 431 } else if (show_printk) { 432 pevent_print_printk(pevent); 433 } 434 435 *ppevent = pevent; 436 pevent = NULL; 437 438 out: 439 if (pevent) 440 pevent_free(pevent); 441 return size; 442 } 443