linux/tools/perf/util/trace-event-info.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008,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#define _GNU_SOURCE
  22#include <dirent.h>
  23#include <mntent.h>
  24#include <stdio.h>
  25#include <stdlib.h>
  26#include <string.h>
  27#include <stdarg.h>
  28#include <sys/types.h>
  29#include <sys/stat.h>
  30#include <sys/wait.h>
  31#include <pthread.h>
  32#include <fcntl.h>
  33#include <unistd.h>
  34#include <ctype.h>
  35#include <errno.h>
  36#include <stdbool.h>
  37#include <linux/list.h>
  38#include <linux/kernel.h>
  39
  40#include "../perf.h"
  41#include "trace-event.h"
  42#include "debugfs.h"
  43#include "evsel.h"
  44
  45#define VERSION "0.5"
  46
  47#define _STR(x) #x
  48#define STR(x) _STR(x)
  49#define MAX_PATH 256
  50
  51#define TRACE_CTRL      "tracing_on"
  52#define TRACE           "trace"
  53#define AVAILABLE       "available_tracers"
  54#define CURRENT         "current_tracer"
  55#define ITER_CTRL       "trace_options"
  56#define MAX_LATENCY     "tracing_max_latency"
  57
  58unsigned int page_size;
  59
  60static const char *output_file = "trace.info";
  61static int output_fd;
  62
  63struct event_list {
  64        struct event_list *next;
  65        const char *event;
  66};
  67
  68struct events {
  69        struct events *sibling;
  70        struct events *children;
  71        struct events *next;
  72        char *name;
  73};
  74
  75
  76
  77static void die(const char *fmt, ...)
  78{
  79        va_list ap;
  80        int ret = errno;
  81
  82        if (errno)
  83                perror("trace-cmd");
  84        else
  85                ret = -1;
  86
  87        va_start(ap, fmt);
  88        fprintf(stderr, "  ");
  89        vfprintf(stderr, fmt, ap);
  90        va_end(ap);
  91
  92        fprintf(stderr, "\n");
  93        exit(ret);
  94}
  95
  96void *malloc_or_die(unsigned int size)
  97{
  98        void *data;
  99
 100        data = malloc(size);
 101        if (!data)
 102                die("malloc");
 103        return data;
 104}
 105
 106static const char *find_debugfs(void)
 107{
 108        const char *path = debugfs_mount(NULL);
 109
 110        if (!path)
 111                die("Your kernel not support debugfs filesystem");
 112
 113        return path;
 114}
 115
 116/*
 117 * Finds the path to the debugfs/tracing
 118 * Allocates the string and stores it.
 119 */
 120static const char *find_tracing_dir(void)
 121{
 122        static char *tracing;
 123        static int tracing_found;
 124        const char *debugfs;
 125
 126        if (tracing_found)
 127                return tracing;
 128
 129        debugfs = find_debugfs();
 130
 131        tracing = malloc_or_die(strlen(debugfs) + 9);
 132
 133        sprintf(tracing, "%s/tracing", debugfs);
 134
 135        tracing_found = 1;
 136        return tracing;
 137}
 138
 139static char *get_tracing_file(const char *name)
 140{
 141        const char *tracing;
 142        char *file;
 143
 144        tracing = find_tracing_dir();
 145        if (!tracing)
 146                return NULL;
 147
 148        file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
 149
 150        sprintf(file, "%s/%s", tracing, name);
 151        return file;
 152}
 153
 154static void put_tracing_file(char *file)
 155{
 156        free(file);
 157}
 158
 159static ssize_t calc_data_size;
 160
 161static ssize_t write_or_die(const void *buf, size_t len)
 162{
 163        int ret;
 164
 165        if (calc_data_size) {
 166                calc_data_size += len;
 167                return len;
 168        }
 169
 170        ret = write(output_fd, buf, len);
 171        if (ret < 0)
 172                die("writing to '%s'", output_file);
 173
 174        return ret;
 175}
 176
 177int bigendian(void)
 178{
 179        unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
 180        unsigned int *ptr;
 181
 182        ptr = (unsigned int *)(void *)str;
 183        return *ptr == 0x01020304;
 184}
 185
 186static unsigned long long copy_file_fd(int fd)
 187{
 188        unsigned long long size = 0;
 189        char buf[BUFSIZ];
 190        int r;
 191
 192        do {
 193                r = read(fd, buf, BUFSIZ);
 194                if (r > 0) {
 195                        size += r;
 196                        write_or_die(buf, r);
 197                }
 198        } while (r > 0);
 199
 200        return size;
 201}
 202
 203static unsigned long long copy_file(const char *file)
 204{
 205        unsigned long long size = 0;
 206        int fd;
 207
 208        fd = open(file, O_RDONLY);
 209        if (fd < 0)
 210                die("Can't read '%s'", file);
 211        size = copy_file_fd(fd);
 212        close(fd);
 213
 214        return size;
 215}
 216
 217static unsigned long get_size_fd(int fd)
 218{
 219        unsigned long long size = 0;
 220        char buf[BUFSIZ];
 221        int r;
 222
 223        do {
 224                r = read(fd, buf, BUFSIZ);
 225                if (r > 0)
 226                        size += r;
 227        } while (r > 0);
 228
 229        lseek(fd, 0, SEEK_SET);
 230
 231        return size;
 232}
 233
 234static unsigned long get_size(const char *file)
 235{
 236        unsigned long long size = 0;
 237        int fd;
 238
 239        fd = open(file, O_RDONLY);
 240        if (fd < 0)
 241                die("Can't read '%s'", file);
 242        size = get_size_fd(fd);
 243        close(fd);
 244
 245        return size;
 246}
 247
 248static void read_header_files(void)
 249{
 250        unsigned long long size, check_size;
 251        char *path;
 252        int fd;
 253
 254        path = get_tracing_file("events/header_page");
 255        fd = open(path, O_RDONLY);
 256        if (fd < 0)
 257                die("can't read '%s'", path);
 258
 259        /* unfortunately, you can not stat debugfs files for size */
 260        size = get_size_fd(fd);
 261
 262        write_or_die("header_page", 12);
 263        write_or_die(&size, 8);
 264        check_size = copy_file_fd(fd);
 265        close(fd);
 266
 267        if (size != check_size)
 268                die("wrong size for '%s' size=%lld read=%lld",
 269                    path, size, check_size);
 270        put_tracing_file(path);
 271
 272        path = get_tracing_file("events/header_event");
 273        fd = open(path, O_RDONLY);
 274        if (fd < 0)
 275                die("can't read '%s'", path);
 276
 277        size = get_size_fd(fd);
 278
 279        write_or_die("header_event", 13);
 280        write_or_die(&size, 8);
 281        check_size = copy_file_fd(fd);
 282        if (size != check_size)
 283                die("wrong size for '%s'", path);
 284        put_tracing_file(path);
 285        close(fd);
 286}
 287
 288static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
 289{
 290        while (tps) {
 291                if (!strcmp(sys, tps->name))
 292                        return true;
 293                tps = tps->next;
 294        }
 295
 296        return false;
 297}
 298
 299static void copy_event_system(const char *sys, struct tracepoint_path *tps)
 300{
 301        unsigned long long size, check_size;
 302        struct dirent *dent;
 303        struct stat st;
 304        char *format;
 305        DIR *dir;
 306        int count = 0;
 307        int ret;
 308
 309        dir = opendir(sys);
 310        if (!dir)
 311                die("can't read directory '%s'", sys);
 312
 313        while ((dent = readdir(dir))) {
 314                if (dent->d_type != DT_DIR ||
 315                    strcmp(dent->d_name, ".") == 0 ||
 316                    strcmp(dent->d_name, "..") == 0 ||
 317                    !name_in_tp_list(dent->d_name, tps))
 318                        continue;
 319                format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
 320                sprintf(format, "%s/%s/format", sys, dent->d_name);
 321                ret = stat(format, &st);
 322                free(format);
 323                if (ret < 0)
 324                        continue;
 325                count++;
 326        }
 327
 328        write_or_die(&count, 4);
 329
 330        rewinddir(dir);
 331        while ((dent = readdir(dir))) {
 332                if (dent->d_type != DT_DIR ||
 333                    strcmp(dent->d_name, ".") == 0 ||
 334                    strcmp(dent->d_name, "..") == 0 ||
 335                    !name_in_tp_list(dent->d_name, tps))
 336                        continue;
 337                format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
 338                sprintf(format, "%s/%s/format", sys, dent->d_name);
 339                ret = stat(format, &st);
 340
 341                if (ret >= 0) {
 342                        /* unfortunately, you can not stat debugfs files for size */
 343                        size = get_size(format);
 344                        write_or_die(&size, 8);
 345                        check_size = copy_file(format);
 346                        if (size != check_size)
 347                                die("error in size of file '%s'", format);
 348                }
 349
 350                free(format);
 351        }
 352        closedir(dir);
 353}
 354
 355static void read_ftrace_files(struct tracepoint_path *tps)
 356{
 357        char *path;
 358
 359        path = get_tracing_file("events/ftrace");
 360
 361        copy_event_system(path, tps);
 362
 363        put_tracing_file(path);
 364}
 365
 366static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
 367{
 368        while (tps) {
 369                if (!strcmp(sys, tps->system))
 370                        return true;
 371                tps = tps->next;
 372        }
 373
 374        return false;
 375}
 376
 377static void read_event_files(struct tracepoint_path *tps)
 378{
 379        struct dirent *dent;
 380        struct stat st;
 381        char *path;
 382        char *sys;
 383        DIR *dir;
 384        int count = 0;
 385        int ret;
 386
 387        path = get_tracing_file("events");
 388
 389        dir = opendir(path);
 390        if (!dir)
 391                die("can't read directory '%s'", path);
 392
 393        while ((dent = readdir(dir))) {
 394                if (dent->d_type != DT_DIR ||
 395                    strcmp(dent->d_name, ".") == 0 ||
 396                    strcmp(dent->d_name, "..") == 0 ||
 397                    strcmp(dent->d_name, "ftrace") == 0 ||
 398                    !system_in_tp_list(dent->d_name, tps))
 399                        continue;
 400                count++;
 401        }
 402
 403        write_or_die(&count, 4);
 404
 405        rewinddir(dir);
 406        while ((dent = readdir(dir))) {
 407                if (dent->d_type != DT_DIR ||
 408                    strcmp(dent->d_name, ".") == 0 ||
 409                    strcmp(dent->d_name, "..") == 0 ||
 410                    strcmp(dent->d_name, "ftrace") == 0 ||
 411                    !system_in_tp_list(dent->d_name, tps))
 412                        continue;
 413                sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
 414                sprintf(sys, "%s/%s", path, dent->d_name);
 415                ret = stat(sys, &st);
 416                if (ret >= 0) {
 417                        write_or_die(dent->d_name, strlen(dent->d_name) + 1);
 418                        copy_event_system(sys, tps);
 419                }
 420                free(sys);
 421        }
 422
 423        closedir(dir);
 424        put_tracing_file(path);
 425}
 426
 427static void read_proc_kallsyms(void)
 428{
 429        unsigned int size, check_size;
 430        const char *path = "/proc/kallsyms";
 431        struct stat st;
 432        int ret;
 433
 434        ret = stat(path, &st);
 435        if (ret < 0) {
 436                /* not found */
 437                size = 0;
 438                write_or_die(&size, 4);
 439                return;
 440        }
 441        size = get_size(path);
 442        write_or_die(&size, 4);
 443        check_size = copy_file(path);
 444        if (size != check_size)
 445                die("error in size of file '%s'", path);
 446
 447}
 448
 449static void read_ftrace_printk(void)
 450{
 451        unsigned int size, check_size;
 452        char *path;
 453        struct stat st;
 454        int ret;
 455
 456        path = get_tracing_file("printk_formats");
 457        ret = stat(path, &st);
 458        if (ret < 0) {
 459                /* not found */
 460                size = 0;
 461                write_or_die(&size, 4);
 462                goto out;
 463        }
 464        size = get_size(path);
 465        write_or_die(&size, 4);
 466        check_size = copy_file(path);
 467        if (size != check_size)
 468                die("error in size of file '%s'", path);
 469out:
 470        put_tracing_file(path);
 471}
 472
 473static struct tracepoint_path *
 474get_tracepoints_path(struct list_head *pattrs)
 475{
 476        struct tracepoint_path path, *ppath = &path;
 477        struct perf_evsel *pos;
 478        int nr_tracepoints = 0;
 479
 480        list_for_each_entry(pos, pattrs, node) {
 481                if (pos->attr.type != PERF_TYPE_TRACEPOINT)
 482                        continue;
 483                ++nr_tracepoints;
 484                ppath->next = tracepoint_id_to_path(pos->attr.config);
 485                if (!ppath->next)
 486                        die("%s\n", "No memory to alloc tracepoints list");
 487                ppath = ppath->next;
 488        }
 489
 490        return nr_tracepoints > 0 ? path.next : NULL;
 491}
 492
 493bool have_tracepoints(struct list_head *pattrs)
 494{
 495        struct perf_evsel *pos;
 496
 497        list_for_each_entry(pos, pattrs, node)
 498                if (pos->attr.type == PERF_TYPE_TRACEPOINT)
 499                        return true;
 500
 501        return false;
 502}
 503
 504int read_tracing_data(int fd, struct list_head *pattrs)
 505{
 506        char buf[BUFSIZ];
 507        struct tracepoint_path *tps = get_tracepoints_path(pattrs);
 508
 509        /*
 510         * What? No tracepoints? No sense writing anything here, bail out.
 511         */
 512        if (tps == NULL)
 513                return -1;
 514
 515        output_fd = fd;
 516
 517        buf[0] = 23;
 518        buf[1] = 8;
 519        buf[2] = 68;
 520        memcpy(buf + 3, "tracing", 7);
 521
 522        write_or_die(buf, 10);
 523
 524        write_or_die(VERSION, strlen(VERSION) + 1);
 525
 526        /* save endian */
 527        if (bigendian())
 528                buf[0] = 1;
 529        else
 530                buf[0] = 0;
 531
 532        write_or_die(buf, 1);
 533
 534        /* save size of long */
 535        buf[0] = sizeof(long);
 536        write_or_die(buf, 1);
 537
 538        /* save page_size */
 539        page_size = sysconf(_SC_PAGESIZE);
 540        write_or_die(&page_size, 4);
 541
 542        read_header_files();
 543        read_ftrace_files(tps);
 544        read_event_files(tps);
 545        read_proc_kallsyms();
 546        read_ftrace_printk();
 547
 548        return 0;
 549}
 550
 551ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
 552{
 553        ssize_t size;
 554        int err = 0;
 555
 556        calc_data_size = 1;
 557        err = read_tracing_data(fd, pattrs);
 558        size = calc_data_size - 1;
 559        calc_data_size = 0;
 560
 561        if (err < 0)
 562                return err;
 563
 564        return size;
 565}
 566