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