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