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