Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
0004  */
0005 #include <dirent.h>
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <stdarg.h>
0010 #include <sys/types.h>
0011 #include <sys/stat.h>
0012 #include <sys/wait.h>
0013 #include <sys/mman.h>
0014 #include <fcntl.h>
0015 #include <unistd.h>
0016 #include <errno.h>
0017 
0018 #include "trace-event.h"
0019 #include "debug.h"
0020 
0021 static int input_fd;
0022 
0023 static ssize_t trace_data_size;
0024 static bool repipe;
0025 
0026 static int __do_read(int fd, void *buf, int size)
0027 {
0028     int rsize = size;
0029 
0030     while (size) {
0031         int ret = read(fd, buf, size);
0032 
0033         if (ret <= 0)
0034             return -1;
0035 
0036         if (repipe) {
0037             int retw = write(STDOUT_FILENO, buf, ret);
0038 
0039             if (retw <= 0 || retw != ret) {
0040                 pr_debug("repiping input file");
0041                 return -1;
0042             }
0043         }
0044 
0045         size -= ret;
0046         buf += ret;
0047     }
0048 
0049     return rsize;
0050 }
0051 
0052 static int do_read(void *data, int size)
0053 {
0054     int r;
0055 
0056     r = __do_read(input_fd, data, size);
0057     if (r <= 0) {
0058         pr_debug("reading input file (size expected=%d received=%d)",
0059              size, r);
0060         return -1;
0061     }
0062 
0063     trace_data_size += r;
0064 
0065     return r;
0066 }
0067 
0068 /* If it fails, the next read will report it */
0069 static void skip(int size)
0070 {
0071     char buf[BUFSIZ];
0072     int r;
0073 
0074     while (size) {
0075         r = size > BUFSIZ ? BUFSIZ : size;
0076         do_read(buf, r);
0077         size -= r;
0078     }
0079 }
0080 
0081 static unsigned int read4(struct tep_handle *pevent)
0082 {
0083     unsigned int data;
0084 
0085     if (do_read(&data, 4) < 0)
0086         return 0;
0087     return tep_read_number(pevent, &data, 4);
0088 }
0089 
0090 static unsigned long long read8(struct tep_handle *pevent)
0091 {
0092     unsigned long long data;
0093 
0094     if (do_read(&data, 8) < 0)
0095         return 0;
0096     return tep_read_number(pevent, &data, 8);
0097 }
0098 
0099 static char *read_string(void)
0100 {
0101     char buf[BUFSIZ];
0102     char *str = NULL;
0103     int size = 0;
0104     off_t r;
0105     char c;
0106 
0107     for (;;) {
0108         r = read(input_fd, &c, 1);
0109         if (r < 0) {
0110             pr_debug("reading input file");
0111             goto out;
0112         }
0113 
0114         if (!r) {
0115             pr_debug("no data");
0116             goto out;
0117         }
0118 
0119         if (repipe) {
0120             int retw = write(STDOUT_FILENO, &c, 1);
0121 
0122             if (retw <= 0 || retw != r) {
0123                 pr_debug("repiping input file string");
0124                 goto out;
0125             }
0126         }
0127 
0128         buf[size++] = c;
0129 
0130         if (!c)
0131             break;
0132     }
0133 
0134     trace_data_size += size;
0135 
0136     str = malloc(size);
0137     if (str)
0138         memcpy(str, buf, size);
0139 out:
0140     return str;
0141 }
0142 
0143 static int read_proc_kallsyms(struct tep_handle *pevent)
0144 {
0145     unsigned int size;
0146 
0147     size = read4(pevent);
0148     if (!size)
0149         return 0;
0150     /*
0151      * Just skip it, now that we configure libtraceevent to use the
0152      * tools/perf/ symbol resolver.
0153      *
0154      * We need to skip it so that we can continue parsing old perf.data
0155      * files, that contains this /proc/kallsyms payload.
0156      *
0157      * Newer perf.data files will have just the 4-bytes zeros "kallsyms
0158      * payload", so that older tools can continue reading it and interpret
0159      * it as "no kallsyms payload is present".
0160      */
0161     lseek(input_fd, size, SEEK_CUR);
0162     trace_data_size += size;
0163     return 0;
0164 }
0165 
0166 static int read_ftrace_printk(struct tep_handle *pevent)
0167 {
0168     unsigned int size;
0169     char *buf;
0170 
0171     /* it can have 0 size */
0172     size = read4(pevent);
0173     if (!size)
0174         return 0;
0175 
0176     buf = malloc(size + 1);
0177     if (buf == NULL)
0178         return -1;
0179 
0180     if (do_read(buf, size) < 0) {
0181         free(buf);
0182         return -1;
0183     }
0184 
0185     buf[size] = '\0';
0186 
0187     parse_ftrace_printk(pevent, buf, size);
0188 
0189     free(buf);
0190     return 0;
0191 }
0192 
0193 static int read_header_files(struct tep_handle *pevent)
0194 {
0195     unsigned long long size;
0196     char *header_page;
0197     char buf[BUFSIZ];
0198     int ret = 0;
0199 
0200     if (do_read(buf, 12) < 0)
0201         return -1;
0202 
0203     if (memcmp(buf, "header_page", 12) != 0) {
0204         pr_debug("did not read header page");
0205         return -1;
0206     }
0207 
0208     size = read8(pevent);
0209 
0210     header_page = malloc(size);
0211     if (header_page == NULL)
0212         return -1;
0213 
0214     if (do_read(header_page, size) < 0) {
0215         pr_debug("did not read header page");
0216         free(header_page);
0217         return -1;
0218     }
0219 
0220     if (!tep_parse_header_page(pevent, header_page, size,
0221                    tep_get_long_size(pevent))) {
0222         /*
0223          * The commit field in the page is of type long,
0224          * use that instead, since it represents the kernel.
0225          */
0226         tep_set_long_size(pevent, tep_get_header_page_size(pevent));
0227     }
0228     free(header_page);
0229 
0230     if (do_read(buf, 13) < 0)
0231         return -1;
0232 
0233     if (memcmp(buf, "header_event", 13) != 0) {
0234         pr_debug("did not read header event");
0235         return -1;
0236     }
0237 
0238     size = read8(pevent);
0239     skip(size);
0240 
0241     return ret;
0242 }
0243 
0244 static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
0245 {
0246     int ret;
0247     char *buf;
0248 
0249     buf = malloc(size);
0250     if (buf == NULL) {
0251         pr_debug("memory allocation failure\n");
0252         return -1;
0253     }
0254 
0255     ret = do_read(buf, size);
0256     if (ret < 0) {
0257         pr_debug("error reading ftrace file.\n");
0258         goto out;
0259     }
0260 
0261     ret = parse_ftrace_file(pevent, buf, size);
0262     if (ret < 0)
0263         pr_debug("error parsing ftrace file.\n");
0264 out:
0265     free(buf);
0266     return ret;
0267 }
0268 
0269 static int read_event_file(struct tep_handle *pevent, char *sys,
0270                unsigned long long size)
0271 {
0272     int ret;
0273     char *buf;
0274 
0275     buf = malloc(size);
0276     if (buf == NULL) {
0277         pr_debug("memory allocation failure\n");
0278         return -1;
0279     }
0280 
0281     ret = do_read(buf, size);
0282     if (ret < 0)
0283         goto out;
0284 
0285     ret = parse_event_file(pevent, buf, size, sys);
0286     if (ret < 0)
0287         pr_debug("error parsing event file.\n");
0288 out:
0289     free(buf);
0290     return ret;
0291 }
0292 
0293 static int read_ftrace_files(struct tep_handle *pevent)
0294 {
0295     unsigned long long size;
0296     int count;
0297     int i;
0298     int ret;
0299 
0300     count = read4(pevent);
0301 
0302     for (i = 0; i < count; i++) {
0303         size = read8(pevent);
0304         ret = read_ftrace_file(pevent, size);
0305         if (ret)
0306             return ret;
0307     }
0308     return 0;
0309 }
0310 
0311 static int read_event_files(struct tep_handle *pevent)
0312 {
0313     unsigned long long size;
0314     char *sys;
0315     int systems;
0316     int count;
0317     int i,x;
0318     int ret;
0319 
0320     systems = read4(pevent);
0321 
0322     for (i = 0; i < systems; i++) {
0323         sys = read_string();
0324         if (sys == NULL)
0325             return -1;
0326 
0327         count = read4(pevent);
0328 
0329         for (x=0; x < count; x++) {
0330             size = read8(pevent);
0331             ret = read_event_file(pevent, sys, size);
0332             if (ret) {
0333                 free(sys);
0334                 return ret;
0335             }
0336         }
0337         free(sys);
0338     }
0339     return 0;
0340 }
0341 
0342 static int read_saved_cmdline(struct tep_handle *pevent)
0343 {
0344     unsigned long long size;
0345     char *buf;
0346     int ret;
0347 
0348     /* it can have 0 size */
0349     size = read8(pevent);
0350     if (!size)
0351         return 0;
0352 
0353     buf = malloc(size + 1);
0354     if (buf == NULL) {
0355         pr_debug("memory allocation failure\n");
0356         return -1;
0357     }
0358 
0359     ret = do_read(buf, size);
0360     if (ret < 0) {
0361         pr_debug("error reading saved cmdlines\n");
0362         goto out;
0363     }
0364     buf[ret] = '\0';
0365 
0366     parse_saved_cmdline(pevent, buf, size);
0367     ret = 0;
0368 out:
0369     free(buf);
0370     return ret;
0371 }
0372 
0373 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
0374 {
0375     char buf[BUFSIZ];
0376     char test[] = { 23, 8, 68 };
0377     char *version;
0378     int show_version = 0;
0379     int show_funcs = 0;
0380     int show_printk = 0;
0381     ssize_t size = -1;
0382     int file_bigendian;
0383     int host_bigendian;
0384     int file_long_size;
0385     int file_page_size;
0386     struct tep_handle *pevent = NULL;
0387     int err;
0388 
0389     repipe = __repipe;
0390     input_fd = fd;
0391 
0392     if (do_read(buf, 3) < 0)
0393         return -1;
0394     if (memcmp(buf, test, 3) != 0) {
0395         pr_debug("no trace data in the file");
0396         return -1;
0397     }
0398 
0399     if (do_read(buf, 7) < 0)
0400         return -1;
0401     if (memcmp(buf, "tracing", 7) != 0) {
0402         pr_debug("not a trace file (missing 'tracing' tag)");
0403         return -1;
0404     }
0405 
0406     version = read_string();
0407     if (version == NULL)
0408         return -1;
0409     if (show_version)
0410         printf("version = %s\n", version);
0411 
0412     if (do_read(buf, 1) < 0) {
0413         free(version);
0414         return -1;
0415     }
0416     file_bigendian = buf[0];
0417     host_bigendian = bigendian();
0418 
0419     if (trace_event__init(tevent)) {
0420         pr_debug("trace_event__init failed");
0421         goto out;
0422     }
0423 
0424     pevent = tevent->pevent;
0425 
0426     tep_set_flag(pevent, TEP_NSEC_OUTPUT);
0427     tep_set_file_bigendian(pevent, file_bigendian);
0428     tep_set_local_bigendian(pevent, host_bigendian);
0429 
0430     if (do_read(buf, 1) < 0)
0431         goto out;
0432     file_long_size = buf[0];
0433 
0434     file_page_size = read4(pevent);
0435     if (!file_page_size)
0436         goto out;
0437 
0438     tep_set_long_size(pevent, file_long_size);
0439     tep_set_page_size(pevent, file_page_size);
0440 
0441     err = read_header_files(pevent);
0442     if (err)
0443         goto out;
0444     err = read_ftrace_files(pevent);
0445     if (err)
0446         goto out;
0447     err = read_event_files(pevent);
0448     if (err)
0449         goto out;
0450     err = read_proc_kallsyms(pevent);
0451     if (err)
0452         goto out;
0453     err = read_ftrace_printk(pevent);
0454     if (err)
0455         goto out;
0456     if (atof(version) >= 0.6) {
0457         err = read_saved_cmdline(pevent);
0458         if (err)
0459             goto out;
0460     }
0461 
0462     size = trace_data_size;
0463     repipe = false;
0464 
0465     if (show_funcs) {
0466         tep_print_funcs(pevent);
0467     } else if (show_printk) {
0468         tep_print_printk(pevent);
0469     }
0470 
0471     pevent = NULL;
0472 
0473 out:
0474     if (pevent)
0475         trace_event__cleanup(tevent);
0476     free(version);
0477     return size;
0478 }