Perf already captures the tracing metadata as a part of
data section in perf.data

When trace_dat_fp is set, write trace.dat compatible metadata
sections using the perf provided raw buffers.

Sections written:
- Initial format header (magic, version, endian, long_size,
  page_size, compression, options_offset placeholder)
- Section 16: HEADER INFO (header_page + header_event)
- Section 17: FTRACE EVENT FORMATS
- Section 18: EVENT FORMATS (per system/event format files)
- Section 19: KALLSYMS
- Section 21: CMDLINES
- Section 15: STRINGS (written last after all sections)

Signed-off-by: Tanushree Shah <[email protected]>
---
 tools/perf/util/trace-event-read.c | 259 ++++++++++++++++++++++++++++-
 1 file changed, 252 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/trace-event-read.c 
b/tools/perf/util/trace-event-read.c
index ecbbb93f0185..815577703c2e 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -19,6 +19,7 @@
 #include "trace-event.h"
 #include "debug.h"
 #include "util.h"
+#include "trace-dat.h"
 
 static int input_fd;
 
@@ -145,10 +146,9 @@ static char *read_string(void)
 static int read_proc_kallsyms(struct tep_handle *pevent)
 {
        unsigned int size;
+       char *buf;
 
        size = read4(pevent);
-       if (!size)
-               return 0;
        /*
         * Just skip it, now that we configure libtraceevent to use the
         * tools/perf/ symbol resolver.
@@ -160,11 +160,56 @@ static int read_proc_kallsyms(struct tep_handle *pevent)
         * payload", so that older tools can continue reading it and interpret
         * it as "no kallsyms payload is present".
         */
-       lseek(input_fd, size, SEEK_CUR);
+       /* Write kallsyms section with empty payload if no data */
+       if (!size) {
+               if (trace_dat_fp) {
+                       unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS;
+                       unsigned short flags = 0;
+                       unsigned long long section_size = sizeof(unsigned int);
+                       unsigned int kallsyms_data = 0;
+                       unsigned int string_id = STRID_KALLSYMS;
+
+                       trace_dat_kallsyms_offset = ftell(trace_dat_fp);
+                       if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                           !fwrite(&flags, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                           !fwrite(&string_id, sizeof(unsigned int), 1, 
trace_dat_fp) ||
+                           !fwrite(&section_size, sizeof(unsigned long long), 
1, trace_dat_fp) ||
+                           !fwrite(&kallsyms_data, sizeof(unsigned int), 1, 
trace_dat_fp))
+                               return -EIO;
+               }
+               return 0;
+       }
+       buf = malloc(size);
+       if (buf == NULL)
+               return -1;
+       if (read(input_fd, buf, size) < 0) {
+               free(buf);
+               return -1;
+       }
        trace_data_size += size;
+       /* Write kallsyms section with data */
+       if (trace_dat_fp) {
+               unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS;
+               unsigned int string_id = STRID_KALLSYMS;
+               unsigned long long section_size = sizeof(unsigned int) + size;
+               unsigned short flags = 0;
+
+               trace_dat_kallsyms_offset = ftell(trace_dat_fp);
+               if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                   !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+                   !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) 
||
+                   !fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp) ||
+                   !fwrite(&size, sizeof(unsigned int), 1, trace_dat_fp) ||
+                   !fwrite(buf, 1, size, trace_dat_fp)) {
+                       free(buf);
+                       return -EIO;
+               }
+       }
+       free(buf);
        return 0;
 }
 
+
 static int read_ftrace_printk(struct tep_handle *pevent)
 {
        unsigned int size;
@@ -195,6 +240,13 @@ static int read_ftrace_printk(struct tep_handle *pevent)
 static int read_header_files(struct tep_handle *pevent)
 {
        unsigned long long size;
+       unsigned long long header_page_size;
+       unsigned long long header_event_size;
+       char *header_event;
+       unsigned short section_id;
+       unsigned short flags;
+       unsigned int string_id;
+       unsigned long long section_size;
        char *header_page;
        char buf[BUFSIZ];
        int ret = 0;
@@ -209,6 +261,7 @@ static int read_header_files(struct tep_handle *pevent)
 
        size = read8(pevent);
 
+       header_page_size = size;
        header_page = malloc(size);
        if (header_page == NULL)
                return -1;
@@ -227,19 +280,59 @@ static int read_header_files(struct tep_handle *pevent)
                 */
                tep_set_long_size(pevent, tep_get_header_page_size(pevent));
        }
-       free(header_page);
 
-       if (do_read(buf, 13) < 0)
+       if (do_read(buf, 13) < 0) {
+               free(header_page);
                return -1;
+       }
 
        if (memcmp(buf, "header_event", 13) != 0) {
                pr_debug("did not read header event");
+               free(header_page);
                return -1;
        }
 
        size = read8(pevent);
-       skip(size);
+       if (trace_dat_fp) {
+               header_event_size = size;
+               header_event = malloc(size);
+               if (header_event == NULL) {
+                       free(header_page);
+                       return -1;
+               }
+               if (do_read(header_event, size) < 0) {
+                       free(header_page);
+                       free(header_event);
+                       return -1;
+               }
+               /* Write header_page and header_event to trace.dat */
+               section_id = TRACE_DAT_SECTION_HEADER;
+               flags = 0;
+               string_id = STRID_HEADERS;
+               section_size = 12 + 8 + header_page_size + 13 + 8 +
+                               header_event_size;
+
+               trace_dat_header_info_offset = ftell(trace_dat_fp);
+               if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                   !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+                   !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) 
||
+                   !fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp) ||
+                   !fwrite("header_page\0", 1, 12, trace_dat_fp) ||
+                   !fwrite(&header_page_size, sizeof(unsigned long long), 1, 
trace_dat_fp) ||
+                   !fwrite(header_page, 1, header_page_size, trace_dat_fp) ||
+                   !fwrite("header_event\0", 1, 13, trace_dat_fp) ||
+                   !fwrite(&header_event_size, sizeof(unsigned long long), 1, 
trace_dat_fp) ||
+                   !fwrite(header_event, 1, header_event_size, trace_dat_fp)) {
+                       free(header_page);
+                       free(header_event);
+                       return -EIO;
+               }
+               free(header_event);
+       } else {
+               skip(size);
+       }
 
+       free(header_page);
        return ret;
 }
 
@@ -259,6 +352,13 @@ static int read_ftrace_file(struct tep_handle *pevent, 
unsigned long long size)
                pr_debug("error reading ftrace file.\n");
                goto out;
        }
+       if (trace_dat_fp) {
+               if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) 
||
+                   !fwrite(buf, 1, size, trace_dat_fp)) {
+                       free(buf);
+                       return -EIO;
+               }
+       }
 
        ret = parse_ftrace_file(pevent, buf, size);
        if (ret < 0)
@@ -283,6 +383,13 @@ static int read_event_file(struct tep_handle *pevent, char 
*sys,
        ret = do_read(buf, size);
        if (ret < 0)
                goto out;
+       if (trace_dat_fp) {
+               if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) 
||
+                   !fwrite(buf, 1, size, trace_dat_fp)) {
+                       free(buf);
+                       return -EIO;
+               }
+       }
 
        ret = parse_event_file(pevent, buf, size, sys);
        if (ret < 0)
@@ -298,8 +405,31 @@ static int read_ftrace_files(struct tep_handle *pevent)
        int count;
        int i;
        int ret;
+       long section_size_pos = 0;
+       long count_pos = 0;
+       unsigned long long section_size = 0;
+       long end_pos;
 
        count = read4(pevent);
+       /* Write ftrace formats section to trace.dat output file */
+       if (trace_dat_fp) {
+               unsigned short section_id = TRACE_DAT_SECTION_FTRACE;
+               unsigned short flags = 0;
+               unsigned int string_id = STRID_FTRACE_FORMATS;
+
+               trace_dat_ftrace_format_offset = ftell(trace_dat_fp);
+
+               if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                   !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+                   !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp))
+                       return -EIO;
+               section_size_pos = ftell(trace_dat_fp);
+               if (!fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp))
+                       return -EIO;
+               count_pos = ftell(trace_dat_fp);
+               if (!fwrite(&count, sizeof(unsigned int), 1, trace_dat_fp))
+                       return -EIO;
+       }
 
        for (i = 0; i < count; i++) {
                size = read8(pevent);
@@ -307,6 +437,16 @@ static int read_ftrace_files(struct tep_handle *pevent)
                if (ret)
                        return ret;
        }
+       /* Fill in section size after writing all ftrace files */
+       if (trace_dat_fp) {
+               end_pos = ftell(trace_dat_fp);
+               section_size = end_pos - count_pos;
+               fseek(trace_dat_fp, section_size_pos, SEEK_SET);
+               if (!fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp))
+                       return -EIO;
+               fseek(trace_dat_fp, end_pos, SEEK_SET);
+       }
+
        return 0;
 }
 
@@ -318,8 +458,30 @@ static int read_event_files(struct tep_handle *pevent)
        int count;
        int i,x;
        int ret;
+       long section_size_pos = 0;
+       long sys_count_pos = 0;
+       unsigned long long section_size = 0;
+       long end_pos;
 
        systems = read4(pevent);
+       /* Write event formats section to trace.dat output file */
+       if (trace_dat_fp) {
+               unsigned short section_id = TRACE_DAT_SECTION_EVENTS;
+               unsigned short flags = 0;
+               unsigned int string_id = STRID_EVENT_FORMATS;
+
+               trace_dat_events_format_offset = ftell(trace_dat_fp);
+               if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                   !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+                   !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp))
+                       return -EIO;
+               section_size_pos = ftell(trace_dat_fp);
+               if (!fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp))
+                       return -EIO;
+               sys_count_pos = ftell(trace_dat_fp);
+               if (!fwrite(&systems, sizeof(unsigned int), 1, trace_dat_fp))
+                       return -EIO;
+       }
 
        for (i = 0; i < systems; i++) {
                sys = read_string();
@@ -327,6 +489,11 @@ static int read_event_files(struct tep_handle *pevent)
                        return -1;
 
                count = read4(pevent);
+               if (trace_dat_fp) {
+                       if (!fwrite(sys, 1, strlen(sys) + 1, trace_dat_fp) ||
+                          !fwrite(&count, sizeof(unsigned int), 1, 
trace_dat_fp))
+                               return -EIO;
+               }
 
                for (x=0; x < count; x++) {
                        size = read8(pevent);
@@ -338,6 +505,16 @@ static int read_event_files(struct tep_handle *pevent)
                }
                free(sys);
        }
+       /* Fill in section size after writing all event files */
+       if (trace_dat_fp) {
+               end_pos = ftell(trace_dat_fp);
+               section_size = end_pos - sys_count_pos;
+               fseek(trace_dat_fp, section_size_pos, SEEK_SET);
+               if (!fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp))
+                       return -EIO;
+               fseek(trace_dat_fp, end_pos, SEEK_SET);
+       }
+
        return 0;
 }
 
@@ -349,8 +526,25 @@ static int read_saved_cmdline(struct tep_handle *pevent)
 
        /* it can have 0 size */
        size = read8(pevent);
-       if (!size)
+       /* Write cmdlines section with empty payload if no data */
+       if (!size) {
+               if (trace_dat_fp) {
+                       unsigned short section_id = TRACE_DAT_SECTION_CMDLINE;
+                       unsigned short flags = 0;
+                       unsigned int string_id = STRID_CMDLINES;
+                       unsigned long long section_size = sizeof(unsigned long 
long);
+                       unsigned long long section_data = 0;
+
+                       trace_dat_cmdline_offset = ftell(trace_dat_fp);
+                       if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                           !fwrite(&flags, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                           !fwrite(&string_id, sizeof(unsigned int), 1, 
trace_dat_fp) ||
+                           !fwrite(&section_size, sizeof(unsigned long long), 
1, trace_dat_fp) ||
+                           !fwrite(&section_data, sizeof(unsigned long long), 
1, trace_dat_fp))
+                               return -EIO;
+               }
                return 0;
+       }
 
        buf = malloc(size + 1);
        if (buf == NULL) {
@@ -363,6 +557,23 @@ static int read_saved_cmdline(struct tep_handle *pevent)
                pr_debug("error reading saved cmdlines\n");
                goto out;
        }
+       /* Write cmdlines section with data */
+       if (trace_dat_fp) {
+               unsigned short section_id = TRACE_DAT_SECTION_CMDLINE;
+               unsigned short flags = 0;
+               unsigned int string_id = STRID_CMDLINES;
+               unsigned long long section_size = sizeof(unsigned long long) + 
size;
+
+               trace_dat_cmdline_offset = ftell(trace_dat_fp);
+               if (!fwrite(&section_id, sizeof(unsigned short), 1, 
trace_dat_fp) ||
+                   !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+                   !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) 
||
+                   !fwrite(&section_size, sizeof(unsigned long long), 1, 
trace_dat_fp) ||
+                   !fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) 
||
+                   !fwrite(buf, 1, size, trace_dat_fp))
+                       return -EIO;
+       }
+
        buf[ret] = '\0';
 
        parse_saved_cmdline(pevent, buf, size);
@@ -387,6 +598,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, 
bool __repipe)
        int file_page_size;
        struct tep_handle *pevent = NULL;
        int err;
+       char magic_buf[10];
 
        repipe = __repipe;
        input_fd = fd;
@@ -398,12 +610,17 @@ ssize_t trace_report(int fd, struct trace_event *tevent, 
bool __repipe)
                return -1;
        }
 
+       if (trace_dat_fp)
+               memcpy(magic_buf, buf, 3);
+
        if (do_read(buf, 7) < 0)
                return -1;
        if (memcmp(buf, "tracing", 7) != 0) {
                pr_debug("not a trace file (missing 'tracing' tag)");
                return -1;
        }
+       if (trace_dat_fp)
+               memcpy(magic_buf + 3, buf, 7);
 
        version = read_string();
        if (version == NULL)
@@ -440,6 +657,28 @@ ssize_t trace_report(int fd, struct trace_event *tevent, 
bool __repipe)
        tep_set_long_size(pevent, file_long_size);
        tep_set_page_size(pevent, file_page_size);
 
+       /* Write initial file header to trace.dat */
+       if (trace_dat_fp) {
+               unsigned char endian = file_bigendian;
+               unsigned char long_size = file_long_size;
+               unsigned int page_size = file_page_size;
+               unsigned long long placeholder = 0;
+               char trace_dat_version = TRACE_DAT_VERSION;
+
+               if (!fwrite(magic_buf, 1, 10, trace_dat_fp) ||    /* magic + 
"tracing" */
+                   !fwrite(&trace_dat_version, 1, 2, trace_dat_fp) ||
+                   !fwrite(&endian, 1, 1, trace_dat_fp) ||
+                   !fwrite(&long_size, 1, 1, trace_dat_fp) ||
+                   !fwrite(&page_size, sizeof(unsigned int), 1, trace_dat_fp) 
||
+                   !fwrite("none", 1, 4, trace_dat_fp) ||
+                   !fwrite("\0", 1, 1, trace_dat_fp) ||
+                   !fwrite("\0", 1, 1, trace_dat_fp))
+                       return -EIO;
+               trace_dat_options_offset = ftell(trace_dat_fp);
+               if (!fwrite(&placeholder, sizeof(unsigned long long), 1, 
trace_dat_fp))
+                       return -EIO;
+       }
+
        err = read_header_files(pevent);
        if (err)
                goto out;
@@ -460,6 +699,12 @@ ssize_t trace_report(int fd, struct trace_event *tevent, 
bool __repipe)
                if (err)
                        goto out;
        }
+       /* Write strings section to trace.dat output file */
+       if (trace_dat_fp) {
+               err = trace_dat__write_strings_section();
+               if (err)
+                       goto out;
+       }
 
        size = trace_data_size;
        repipe = false;
-- 
2.53.0


Reply via email to