1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 4 */ 5 #include <dirent.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <stdarg.h> 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <sys/wait.h> 13 #include <sys/mman.h> 14 #include <event-parse.h> 15 #include <fcntl.h> 16 #include <unistd.h> 17 #include <errno.h> 18 #include <limits.h> 19 20 #include "trace-event.h" 21 #include "debug.h" 22 #include "util.h" 23 24 static int input_fd; 25 26 static ssize_t trace_data_size; 27 static bool repipe; 28 29 static ssize_t __do_read(int fd, void *buf, size_t size) 30 { 31 size_t rsize = size; 32 33 while (size) { 34 ssize_t ret = read(fd, buf, size); 35 36 if (ret <= 0) 37 return -1; 38 39 if (repipe) { 40 ssize_t retw = write(STDOUT_FILENO, buf, ret); 41 42 if (retw <= 0 || retw != ret) { 43 pr_debug("repiping input file"); 44 return -1; 45 } 46 } 47 48 size -= ret; 49 buf += ret; 50 } 51 52 return rsize; 53 } 54 55 static ssize_t do_read(void *data, size_t size) 56 { 57 ssize_t r; 58 59 r = __do_read(input_fd, data, size); 60 if (r <= 0) { 61 pr_debug("reading input file (size expected=%zu received=%zd)", 62 size, r); 63 return -1; 64 } 65 66 trace_data_size += r; 67 68 return r; 69 } 70 71 /* If it fails, the next read will report it */ 72 static void skip(size_t size) 73 { 74 char buf[BUFSIZ]; 75 ssize_t ret; 76 77 while (size) { 78 size_t len = size > BUFSIZ ? BUFSIZ : size; 79 80 ret = do_read(buf, len); 81 if (ret <= 0) 82 break; 83 84 size -= ret; 85 } 86 } 87 88 static unsigned int read4(struct tep_handle *pevent) 89 { 90 unsigned int data; 91 92 if (do_read(&data, 4) < 0) 93 return 0; 94 return tep_read_number(pevent, &data, 4); 95 } 96 97 static unsigned long long read8(struct tep_handle *pevent) 98 { 99 unsigned long long data; 100 101 if (do_read(&data, 8) < 0) 102 return 0; 103 return tep_read_number(pevent, &data, 8); 104 } 105 106 static char *read_string(void) 107 { 108 char buf[BUFSIZ]; 109 char *str = NULL; 110 int size = 0; 111 off_t r; 112 char c; 113 114 for (;;) { 115 r = read(input_fd, &c, 1); 116 if (r < 0) { 117 pr_debug("reading input file"); 118 goto out; 119 } 120 121 if (!r) { 122 pr_debug("no data"); 123 goto out; 124 } 125 126 if (repipe) { 127 int retw = write(STDOUT_FILENO, &c, 1); 128 129 if (retw <= 0 || retw != r) { 130 pr_debug("repiping input file string"); 131 goto out; 132 } 133 } 134 135 if (size >= (int)sizeof(buf) - 1) { 136 pr_debug("string too long (max %zu bytes)", sizeof(buf) - 1); 137 goto out; 138 } 139 140 buf[size++] = c; 141 142 if (!c) 143 break; 144 } 145 146 trace_data_size += size; 147 148 str = malloc(size); 149 if (str) 150 memcpy(str, buf, size); 151 out: 152 return str; 153 } 154 155 static int read_proc_kallsyms(struct tep_handle *pevent) 156 { 157 unsigned int size; 158 159 size = read4(pevent); 160 if (!size) 161 return 0; 162 /* 163 * Just skip it, now that we configure libtraceevent to use the 164 * tools/perf/ symbol resolver. 165 * 166 * We need to skip it so that we can continue parsing old perf.data 167 * files, that contains this /proc/kallsyms payload. 168 * 169 * Newer perf.data files will have just the 4-bytes zeros "kallsyms 170 * payload", so that older tools can continue reading it and interpret 171 * it as "no kallsyms payload is present". 172 */ 173 lseek(input_fd, size, SEEK_CUR); 174 trace_data_size += size; 175 return 0; 176 } 177 178 static int read_ftrace_printk(struct tep_handle *pevent) 179 { 180 unsigned int size; 181 char *buf; 182 183 /* it can have 0 size */ 184 size = read4(pevent); 185 if (!size) 186 return 0; 187 188 if (size == UINT_MAX) { 189 pr_debug("invalid ftrace printk size\n"); 190 return -1; 191 } 192 193 buf = malloc(size + 1); 194 if (buf == NULL) 195 return -1; 196 197 if (do_read(buf, size) < 0) { 198 free(buf); 199 return -1; 200 } 201 202 buf[size] = '\0'; 203 204 parse_ftrace_printk(pevent, buf, size); 205 206 free(buf); 207 return 0; 208 } 209 210 static int read_header_files(struct tep_handle *pevent) 211 { 212 unsigned long long size; 213 char *header_page; 214 char buf[BUFSIZ]; 215 ssize_t ret = 0; 216 217 if (do_read(buf, 12) < 0) 218 return -1; 219 220 if (memcmp(buf, "header_page", 12) != 0) { 221 pr_debug("did not read header page"); 222 return -1; 223 } 224 225 size = read8(pevent); 226 227 header_page = malloc(size); 228 if (header_page == NULL) 229 return -1; 230 231 if (do_read(header_page, size) < 0) { 232 pr_debug("did not read header page"); 233 free(header_page); 234 return -1; 235 } 236 237 if (!tep_parse_header_page(pevent, header_page, size, 238 tep_get_long_size(pevent))) { 239 /* 240 * The commit field in the page is of type long, 241 * use that instead, since it represents the kernel. 242 */ 243 tep_set_long_size(pevent, tep_get_header_page_size(pevent)); 244 } 245 free(header_page); 246 247 if (do_read(buf, 13) < 0) 248 return -1; 249 250 if (memcmp(buf, "header_event", 13) != 0) { 251 pr_debug("did not read header event"); 252 return -1; 253 } 254 255 size = read8(pevent); 256 skip(size); 257 258 return ret; 259 } 260 261 static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) 262 { 263 ssize_t ret; 264 char *buf; 265 266 buf = malloc(size); 267 if (buf == NULL) { 268 pr_debug("memory allocation failure\n"); 269 return -1; 270 } 271 272 ret = do_read(buf, size); 273 if (ret < 0) { 274 pr_debug("error reading ftrace file.\n"); 275 goto out; 276 } 277 278 ret = parse_ftrace_file(pevent, buf, size); 279 if (ret < 0) 280 pr_debug("error parsing ftrace file.\n"); 281 out: 282 free(buf); 283 return ret; 284 } 285 286 static int read_event_file(struct tep_handle *pevent, char *sys, 287 unsigned long long size) 288 { 289 ssize_t ret; 290 char *buf; 291 292 buf = malloc(size); 293 if (buf == NULL) { 294 pr_debug("memory allocation failure\n"); 295 return -1; 296 } 297 298 ret = do_read(buf, size); 299 if (ret < 0) 300 goto out; 301 302 ret = parse_event_file(pevent, buf, size, sys); 303 if (ret < 0) 304 pr_debug("error parsing event file.\n"); 305 out: 306 free(buf); 307 return ret; 308 } 309 310 static int read_ftrace_files(struct tep_handle *pevent) 311 { 312 unsigned long long size; 313 int count; 314 int i; 315 int ret; 316 317 count = read4(pevent); 318 319 for (i = 0; i < count; i++) { 320 size = read8(pevent); 321 ret = read_ftrace_file(pevent, size); 322 if (ret) 323 return ret; 324 } 325 return 0; 326 } 327 328 static int read_event_files(struct tep_handle *pevent) 329 { 330 unsigned long long size; 331 char *sys; 332 int systems; 333 int count; 334 int i,x; 335 ssize_t ret; 336 337 systems = read4(pevent); 338 339 for (i = 0; i < systems; i++) { 340 sys = read_string(); 341 if (sys == NULL) 342 return -1; 343 344 count = read4(pevent); 345 346 for (x=0; x < count; x++) { 347 size = read8(pevent); 348 ret = read_event_file(pevent, sys, size); 349 if (ret) { 350 free(sys); 351 return ret; 352 } 353 } 354 free(sys); 355 } 356 return 0; 357 } 358 359 static int read_saved_cmdline(struct tep_handle *pevent) 360 { 361 unsigned long long size; 362 char *buf; 363 ssize_t ret; 364 365 /* it can have 0 size */ 366 size = read8(pevent); 367 if (!size) 368 return 0; 369 370 if (size == ULLONG_MAX) { 371 pr_debug("invalid saved cmdline size"); 372 return -1; 373 } 374 375 buf = malloc(size + 1); 376 if (buf == NULL) { 377 pr_debug("memory allocation failure\n"); 378 return -1; 379 } 380 381 ret = do_read(buf, size); 382 if (ret < 0) { 383 pr_debug("error reading saved cmdlines\n"); 384 goto out; 385 } 386 buf[ret] = '\0'; 387 388 parse_saved_cmdline(pevent, buf, size); 389 ret = 0; 390 out: 391 free(buf); 392 return ret; 393 } 394 395 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) 396 { 397 char buf[BUFSIZ]; 398 char test[] = { 23, 8, 68 }; 399 char *version; 400 int show_version = 0; 401 int show_funcs = 0; 402 int show_printk = 0; 403 ssize_t size = -1; 404 int file_bigendian; 405 int host_bigendian; 406 int file_long_size; 407 int file_page_size; 408 struct tep_handle *pevent = NULL; 409 int err; 410 411 repipe = __repipe; 412 input_fd = fd; 413 414 if (do_read(buf, 3) < 0) 415 return -1; 416 if (memcmp(buf, test, 3) != 0) { 417 pr_debug("no trace data in the file"); 418 return -1; 419 } 420 421 if (do_read(buf, 7) < 0) 422 return -1; 423 if (memcmp(buf, "tracing", 7) != 0) { 424 pr_debug("not a trace file (missing 'tracing' tag)"); 425 return -1; 426 } 427 428 version = read_string(); 429 if (version == NULL) 430 return -1; 431 if (show_version) 432 printf("version = %s\n", version); 433 434 if (do_read(buf, 1) < 0) { 435 free(version); 436 return -1; 437 } 438 file_bigendian = buf[0]; 439 host_bigendian = host_is_bigendian() ? 1 : 0; 440 441 if (trace_event__init(tevent)) { 442 pr_debug("trace_event__init failed"); 443 goto out; 444 } 445 446 pevent = tevent->pevent; 447 448 tep_set_flag(pevent, TEP_NSEC_OUTPUT); 449 tep_set_file_bigendian(pevent, file_bigendian); 450 tep_set_local_bigendian(pevent, host_bigendian); 451 452 if (do_read(buf, 1) < 0) 453 goto out; 454 file_long_size = buf[0]; 455 456 file_page_size = read4(pevent); 457 if (!file_page_size) 458 goto out; 459 460 tep_set_long_size(pevent, file_long_size); 461 tep_set_page_size(pevent, file_page_size); 462 463 err = read_header_files(pevent); 464 if (err) 465 goto out; 466 err = read_ftrace_files(pevent); 467 if (err) 468 goto out; 469 err = read_event_files(pevent); 470 if (err) 471 goto out; 472 err = read_proc_kallsyms(pevent); 473 if (err) 474 goto out; 475 err = read_ftrace_printk(pevent); 476 if (err) 477 goto out; 478 if (atof(version) >= 0.6) { 479 err = read_saved_cmdline(pevent); 480 if (err) 481 goto out; 482 } 483 484 size = trace_data_size; 485 repipe = false; 486 487 if (show_funcs) { 488 tep_print_funcs(pevent); 489 } else if (show_printk) { 490 tep_print_printk(pevent); 491 } 492 493 pevent = NULL; 494 495 out: 496 if (pevent) 497 trace_event__cleanup(tevent); 498 free(version); 499 return size; 500 } 501