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