root/tools/perf/util/trace-event-info.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bigendian
  2. record_file
  3. record_header_files
  4. name_in_tp_list
  5. copy_event_system
  6. record_ftrace_files
  7. system_in_tp_list
  8. record_event_files
  9. record_proc_kallsyms
  10. record_ftrace_printk
  11. record_saved_cmdline
  12. put_tracepoints_path
  13. get_tracepoints_path
  14. have_tracepoints
  15. tracing_data_header
  16. tracing_data_get
  17. tracing_data_put
  18. read_tracing_data

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
   4  */
   5 #include <dirent.h>
   6 #include <mntent.h>
   7 #include <stdio.h>
   8 #include <stdlib.h>
   9 #include <string.h>
  10 #include <stdarg.h>
  11 #include <sys/types.h>
  12 #include <sys/stat.h>
  13 #include <sys/wait.h>
  14 #include <fcntl.h>
  15 #include <unistd.h>
  16 #include <errno.h>
  17 #include <stdbool.h>
  18 #include <linux/list.h>
  19 #include <linux/kernel.h>
  20 #include <linux/zalloc.h>
  21 #include <internal/lib.h> // page_size
  22 
  23 #include "trace-event.h"
  24 #include <api/fs/tracing_path.h>
  25 #include "evsel.h"
  26 #include "debug.h"
  27 
  28 #define VERSION "0.6"
  29 
  30 static int output_fd;
  31 
  32 
  33 int bigendian(void)
  34 {
  35         unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
  36         unsigned int *ptr;
  37 
  38         ptr = (unsigned int *)(void *)str;
  39         return *ptr == 0x01020304;
  40 }
  41 
  42 /* unfortunately, you can not stat debugfs or proc files for size */
  43 static int record_file(const char *file, ssize_t hdr_sz)
  44 {
  45         unsigned long long size = 0;
  46         char buf[BUFSIZ], *sizep;
  47         off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
  48         int r, fd;
  49         int err = -EIO;
  50 
  51         fd = open(file, O_RDONLY);
  52         if (fd < 0) {
  53                 pr_debug("Can't read '%s'", file);
  54                 return -errno;
  55         }
  56 
  57         /* put in zeros for file size, then fill true size later */
  58         if (hdr_sz) {
  59                 if (write(output_fd, &size, hdr_sz) != hdr_sz)
  60                         goto out;
  61         }
  62 
  63         do {
  64                 r = read(fd, buf, BUFSIZ);
  65                 if (r > 0) {
  66                         size += r;
  67                         if (write(output_fd, buf, r) != r)
  68                                 goto out;
  69                 }
  70         } while (r > 0);
  71 
  72         /* ugh, handle big-endian hdr_size == 4 */
  73         sizep = (char*)&size;
  74         if (bigendian())
  75                 sizep += sizeof(u64) - hdr_sz;
  76 
  77         if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
  78                 pr_debug("writing file size failed\n");
  79                 goto out;
  80         }
  81 
  82         err = 0;
  83 out:
  84         close(fd);
  85         return err;
  86 }
  87 
  88 static int record_header_files(void)
  89 {
  90         char *path = get_events_file("header_page");
  91         struct stat st;
  92         int err = -EIO;
  93 
  94         if (!path) {
  95                 pr_debug("can't get tracing/events/header_page");
  96                 return -ENOMEM;
  97         }
  98 
  99         if (stat(path, &st) < 0) {
 100                 pr_debug("can't read '%s'", path);
 101                 goto out;
 102         }
 103 
 104         if (write(output_fd, "header_page", 12) != 12) {
 105                 pr_debug("can't write header_page\n");
 106                 goto out;
 107         }
 108 
 109         if (record_file(path, 8) < 0) {
 110                 pr_debug("can't record header_page file\n");
 111                 goto out;
 112         }
 113 
 114         put_events_file(path);
 115 
 116         path = get_events_file("header_event");
 117         if (!path) {
 118                 pr_debug("can't get tracing/events/header_event");
 119                 err = -ENOMEM;
 120                 goto out;
 121         }
 122 
 123         if (stat(path, &st) < 0) {
 124                 pr_debug("can't read '%s'", path);
 125                 goto out;
 126         }
 127 
 128         if (write(output_fd, "header_event", 13) != 13) {
 129                 pr_debug("can't write header_event\n");
 130                 goto out;
 131         }
 132 
 133         if (record_file(path, 8) < 0) {
 134                 pr_debug("can't record header_event file\n");
 135                 goto out;
 136         }
 137 
 138         err = 0;
 139 out:
 140         put_events_file(path);
 141         return err;
 142 }
 143 
 144 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
 145 {
 146         while (tps) {
 147                 if (!strcmp(sys, tps->name))
 148                         return true;
 149                 tps = tps->next;
 150         }
 151 
 152         return false;
 153 }
 154 
 155 #define for_each_event(dir, dent, tps)                          \
 156         while ((dent = readdir(dir)))                           \
 157                 if (dent->d_type == DT_DIR &&                   \
 158                     (strcmp(dent->d_name, ".")) &&              \
 159                     (strcmp(dent->d_name, "..")))               \
 160 
 161 static int copy_event_system(const char *sys, struct tracepoint_path *tps)
 162 {
 163         struct dirent *dent;
 164         struct stat st;
 165         char *format;
 166         DIR *dir;
 167         int count = 0;
 168         int ret;
 169         int err;
 170 
 171         dir = opendir(sys);
 172         if (!dir) {
 173                 pr_debug("can't read directory '%s'", sys);
 174                 return -errno;
 175         }
 176 
 177         for_each_event(dir, dent, tps) {
 178                 if (!name_in_tp_list(dent->d_name, tps))
 179                         continue;
 180 
 181                 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
 182                         err = -ENOMEM;
 183                         goto out;
 184                 }
 185                 ret = stat(format, &st);
 186                 free(format);
 187                 if (ret < 0)
 188                         continue;
 189                 count++;
 190         }
 191 
 192         if (write(output_fd, &count, 4) != 4) {
 193                 err = -EIO;
 194                 pr_debug("can't write count\n");
 195                 goto out;
 196         }
 197 
 198         rewinddir(dir);
 199         for_each_event(dir, dent, tps) {
 200                 if (!name_in_tp_list(dent->d_name, tps))
 201                         continue;
 202 
 203                 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
 204                         err = -ENOMEM;
 205                         goto out;
 206                 }
 207                 ret = stat(format, &st);
 208 
 209                 if (ret >= 0) {
 210                         err = record_file(format, 8);
 211                         if (err) {
 212                                 free(format);
 213                                 goto out;
 214                         }
 215                 }
 216                 free(format);
 217         }
 218         err = 0;
 219 out:
 220         closedir(dir);
 221         return err;
 222 }
 223 
 224 static int record_ftrace_files(struct tracepoint_path *tps)
 225 {
 226         char *path;
 227         int ret;
 228 
 229         path = get_events_file("ftrace");
 230         if (!path) {
 231                 pr_debug("can't get tracing/events/ftrace");
 232                 return -ENOMEM;
 233         }
 234 
 235         ret = copy_event_system(path, tps);
 236 
 237         put_tracing_file(path);
 238 
 239         return ret;
 240 }
 241 
 242 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
 243 {
 244         while (tps) {
 245                 if (!strcmp(sys, tps->system))
 246                         return true;
 247                 tps = tps->next;
 248         }
 249 
 250         return false;
 251 }
 252 
 253 static int record_event_files(struct tracepoint_path *tps)
 254 {
 255         struct dirent *dent;
 256         struct stat st;
 257         char *path;
 258         char *sys;
 259         DIR *dir;
 260         int count = 0;
 261         int ret;
 262         int err;
 263 
 264         path = get_tracing_file("events");
 265         if (!path) {
 266                 pr_debug("can't get tracing/events");
 267                 return -ENOMEM;
 268         }
 269 
 270         dir = opendir(path);
 271         if (!dir) {
 272                 err = -errno;
 273                 pr_debug("can't read directory '%s'", path);
 274                 goto out;
 275         }
 276 
 277         for_each_event(dir, dent, tps) {
 278                 if (strcmp(dent->d_name, "ftrace") == 0 ||
 279                     !system_in_tp_list(dent->d_name, tps))
 280                         continue;
 281 
 282                 count++;
 283         }
 284 
 285         if (write(output_fd, &count, 4) != 4) {
 286                 err = -EIO;
 287                 pr_debug("can't write count\n");
 288                 goto out;
 289         }
 290 
 291         rewinddir(dir);
 292         for_each_event(dir, dent, tps) {
 293                 if (strcmp(dent->d_name, "ftrace") == 0 ||
 294                     !system_in_tp_list(dent->d_name, tps))
 295                         continue;
 296 
 297                 if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
 298                         err = -ENOMEM;
 299                         goto out;
 300                 }
 301                 ret = stat(sys, &st);
 302                 if (ret >= 0) {
 303                         ssize_t size = strlen(dent->d_name) + 1;
 304 
 305                         if (write(output_fd, dent->d_name, size) != size ||
 306                             copy_event_system(sys, tps) < 0) {
 307                                 err = -EIO;
 308                                 free(sys);
 309                                 goto out;
 310                         }
 311                 }
 312                 free(sys);
 313         }
 314         err = 0;
 315 out:
 316         closedir(dir);
 317         put_tracing_file(path);
 318 
 319         return err;
 320 }
 321 
 322 static int record_proc_kallsyms(void)
 323 {
 324         unsigned long long size = 0;
 325         /*
 326          * Just to keep older perf.data file parsers happy, record a zero
 327          * sized kallsyms file, i.e. do the same thing that was done when
 328          * /proc/kallsyms (or something specified via --kallsyms, in a
 329          * different path) couldn't be read.
 330          */
 331         return write(output_fd, &size, 4) != 4 ? -EIO : 0;
 332 }
 333 
 334 static int record_ftrace_printk(void)
 335 {
 336         unsigned int size;
 337         char *path;
 338         struct stat st;
 339         int ret, err = 0;
 340 
 341         path = get_tracing_file("printk_formats");
 342         if (!path) {
 343                 pr_debug("can't get tracing/printk_formats");
 344                 return -ENOMEM;
 345         }
 346 
 347         ret = stat(path, &st);
 348         if (ret < 0) {
 349                 /* not found */
 350                 size = 0;
 351                 if (write(output_fd, &size, 4) != 4)
 352                         err = -EIO;
 353                 goto out;
 354         }
 355         err = record_file(path, 4);
 356 
 357 out:
 358         put_tracing_file(path);
 359         return err;
 360 }
 361 
 362 static int record_saved_cmdline(void)
 363 {
 364         unsigned long long size;
 365         char *path;
 366         struct stat st;
 367         int ret, err = 0;
 368 
 369         path = get_tracing_file("saved_cmdlines");
 370         if (!path) {
 371                 pr_debug("can't get tracing/saved_cmdline");
 372                 return -ENOMEM;
 373         }
 374 
 375         ret = stat(path, &st);
 376         if (ret < 0) {
 377                 /* not found */
 378                 size = 0;
 379                 if (write(output_fd, &size, 8) != 8)
 380                         err = -EIO;
 381                 goto out;
 382         }
 383         err = record_file(path, 8);
 384 
 385 out:
 386         put_tracing_file(path);
 387         return err;
 388 }
 389 
 390 static void
 391 put_tracepoints_path(struct tracepoint_path *tps)
 392 {
 393         while (tps) {
 394                 struct tracepoint_path *t = tps;
 395 
 396                 tps = tps->next;
 397                 zfree(&t->name);
 398                 zfree(&t->system);
 399                 free(t);
 400         }
 401 }
 402 
 403 static struct tracepoint_path *
 404 get_tracepoints_path(struct list_head *pattrs)
 405 {
 406         struct tracepoint_path path, *ppath = &path;
 407         struct evsel *pos;
 408         int nr_tracepoints = 0;
 409 
 410         list_for_each_entry(pos, pattrs, core.node) {
 411                 if (pos->core.attr.type != PERF_TYPE_TRACEPOINT)
 412                         continue;
 413                 ++nr_tracepoints;
 414 
 415                 if (pos->name) {
 416                         ppath->next = tracepoint_name_to_path(pos->name);
 417                         if (ppath->next)
 418                                 goto next;
 419 
 420                         if (strchr(pos->name, ':') == NULL)
 421                                 goto try_id;
 422 
 423                         goto error;
 424                 }
 425 
 426 try_id:
 427                 ppath->next = tracepoint_id_to_path(pos->core.attr.config);
 428                 if (!ppath->next) {
 429 error:
 430                         pr_debug("No memory to alloc tracepoints list\n");
 431                         put_tracepoints_path(&path);
 432                         return NULL;
 433                 }
 434 next:
 435                 ppath = ppath->next;
 436         }
 437 
 438         return nr_tracepoints > 0 ? path.next : NULL;
 439 }
 440 
 441 bool have_tracepoints(struct list_head *pattrs)
 442 {
 443         struct evsel *pos;
 444 
 445         list_for_each_entry(pos, pattrs, core.node)
 446                 if (pos->core.attr.type == PERF_TYPE_TRACEPOINT)
 447                         return true;
 448 
 449         return false;
 450 }
 451 
 452 static int tracing_data_header(void)
 453 {
 454         char buf[20];
 455         ssize_t size;
 456 
 457         /* just guessing this is someone's birthday.. ;) */
 458         buf[0] = 23;
 459         buf[1] = 8;
 460         buf[2] = 68;
 461         memcpy(buf + 3, "tracing", 7);
 462 
 463         if (write(output_fd, buf, 10) != 10)
 464                 return -1;
 465 
 466         size = strlen(VERSION) + 1;
 467         if (write(output_fd, VERSION, size) != size)
 468                 return -1;
 469 
 470         /* save endian */
 471         if (bigendian())
 472                 buf[0] = 1;
 473         else
 474                 buf[0] = 0;
 475 
 476         if (write(output_fd, buf, 1) != 1)
 477                 return -1;
 478 
 479         /* save size of long */
 480         buf[0] = sizeof(long);
 481         if (write(output_fd, buf, 1) != 1)
 482                 return -1;
 483 
 484         /* save page_size */
 485         if (write(output_fd, &page_size, 4) != 4)
 486                 return -1;
 487 
 488         return 0;
 489 }
 490 
 491 struct tracing_data *tracing_data_get(struct list_head *pattrs,
 492                                       int fd, bool temp)
 493 {
 494         struct tracepoint_path *tps;
 495         struct tracing_data *tdata;
 496         int err;
 497 
 498         output_fd = fd;
 499 
 500         tps = get_tracepoints_path(pattrs);
 501         if (!tps)
 502                 return NULL;
 503 
 504         tdata = malloc(sizeof(*tdata));
 505         if (!tdata)
 506                 return NULL;
 507 
 508         tdata->temp = temp;
 509         tdata->size = 0;
 510 
 511         if (temp) {
 512                 int temp_fd;
 513 
 514                 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
 515                          "/tmp/perf-XXXXXX");
 516                 if (!mkstemp(tdata->temp_file)) {
 517                         pr_debug("Can't make temp file");
 518                         free(tdata);
 519                         return NULL;
 520                 }
 521 
 522                 temp_fd = open(tdata->temp_file, O_RDWR);
 523                 if (temp_fd < 0) {
 524                         pr_debug("Can't read '%s'", tdata->temp_file);
 525                         free(tdata);
 526                         return NULL;
 527                 }
 528 
 529                 /*
 530                  * Set the temp file the default output, so all the
 531                  * tracing data are stored into it.
 532                  */
 533                 output_fd = temp_fd;
 534         }
 535 
 536         err = tracing_data_header();
 537         if (err)
 538                 goto out;
 539         err = record_header_files();
 540         if (err)
 541                 goto out;
 542         err = record_ftrace_files(tps);
 543         if (err)
 544                 goto out;
 545         err = record_event_files(tps);
 546         if (err)
 547                 goto out;
 548         err = record_proc_kallsyms();
 549         if (err)
 550                 goto out;
 551         err = record_ftrace_printk();
 552         if (err)
 553                 goto out;
 554         err = record_saved_cmdline();
 555 
 556 out:
 557         /*
 558          * All tracing data are stored by now, we can restore
 559          * the default output file in case we used temp file.
 560          */
 561         if (temp) {
 562                 tdata->size = lseek(output_fd, 0, SEEK_CUR);
 563                 close(output_fd);
 564                 output_fd = fd;
 565         }
 566 
 567         if (err)
 568                 zfree(&tdata);
 569 
 570         put_tracepoints_path(tps);
 571         return tdata;
 572 }
 573 
 574 int tracing_data_put(struct tracing_data *tdata)
 575 {
 576         int err = 0;
 577 
 578         if (tdata->temp) {
 579                 err = record_file(tdata->temp_file, 0);
 580                 unlink(tdata->temp_file);
 581         }
 582 
 583         free(tdata);
 584         return err;
 585 }
 586 
 587 int read_tracing_data(int fd, struct list_head *pattrs)
 588 {
 589         int err;
 590         struct tracing_data *tdata;
 591 
 592         /*
 593          * We work over the real file, so we can write data
 594          * directly, no temp file is needed.
 595          */
 596         tdata = tracing_data_get(pattrs, fd, false);
 597         if (!tdata)
 598                 return -ENOMEM;
 599 
 600         err = tracing_data_put(tdata);
 601         return err;
 602 }

/* [<][>][^][v][top][bottom][index][help] */