[RFC PATCH v4 2/5] perf/trace-event: Write trace.dat metadata sections during parsing

Tanushree Shah <[email protected]>
Newsgroups org.ozlabs.lists.linuxppc-dev,org.kernel.vger.linux-perf-users
Message-ID <[email protected]>
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)

Introduce to_file_u16/u32/u64 helpers wrapping tep_read_number() to
write all trace.dat metadata in the recorded machine's byte
order, ensuring correct cross-platform compatibility.

Signed-off-by: Tanushree Shah <[email protected]>
---
 tools/perf/util/trace-dat.c        | 212 ++++++++++++--------
 tools/perf/util/trace-dat.h        |  40 +++-
 tools/perf/util/trace-event-read.c | 307 ++++++++++++++++++++++++++++-
 3 files changed, 465 insertions(+), 94 deletions(-)

diff --git a/tools/perf/util/trace-dat.c b/tools/perf/util/trace-dat.c
index 55a7bd982c6f..f71e03716e27 100644
--- a/tools/perf/util/trace-dat.c
+++ b/tools/perf/util/trace-dat.c
@@ -43,6 +43,7 @@
 /* Buffer size for reading trace_clock string from debugfs/tracefs */
 #define CLOCK_BUFFER_SIZE 256
 
+bool trace_dat_write_failed;
 FILE *trace_dat_fp;
 int trace_dat_page_size;
 int trace_dat_nr_cpus;
@@ -143,10 +144,12 @@ int trace_dat__collect_cpu_event(int cpu, unsigned long long ts,
 }
 
 /* Write a single page of trace records */
-static int trace_dat__write_page(FILE *fp, unsigned long long base_ts,
+static int trace_dat__write_page(FILE *fp, struct tep_handle *pevent, unsigned long long base_ts,
 			char **records, int *rec_sizes, int nr_recs)
 {
 	unsigned long long commit = 0;
+	unsigned long long ts_out;
+	unsigned long long commit_out;
 	int offset = TRACE_DAT_RECORD_HEADER_SIZE;
 	int i;
 	char *page;
@@ -161,8 +164,12 @@ static int trace_dat__write_page(FILE *fp, unsigned long long base_ts,
 		commit += rec_sizes[i];
 	}
 
-	memcpy(page, &base_ts, sizeof(base_ts));
-	memcpy(page + sizeof(base_ts), &commit, sizeof(commit));
+	/* Byte-swap page header for cross-arch compatibility */
+	ts_out = to_file_u64(pevent, base_ts);
+	commit_out = to_file_u64(pevent, commit);
+
+	memcpy(page, &ts_out, sizeof(ts_out));
+	memcpy(page + sizeof(ts_out), &commit_out, sizeof(commit_out));
 
 	if (!fwrite(page, 1, trace_dat_page_size, fp)) {
 		free(page);
@@ -174,7 +181,8 @@ static int trace_dat__write_page(FILE *fp, unsigned long long base_ts,
 }
 
 /* Write all trace data for a single CPU as trace.dat flyrecord pages */
-static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_offset_out)
+static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
+		int cpu, unsigned long long *file_offset_out)
 {
 	struct cpu_events *cpu_events = &trace_cpu_data[cpu];
 	unsigned long long base_ts;
@@ -229,11 +237,18 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 			if (!extend)
 				return -ENOMEM;
 
-			extend_hdr =
-				((time_delta & TRACE_DAT_RECORD_TIME_MASK) <<
-				 TRACE_DAT_RECORD_TIME_SHIFT) |
-				TRACE_DAT_RECORD_TYPE_TIME_EXTEND;
-			delta_upper = time_delta >> TRACE_DAT_RECORD_TIME_SHIFT;
+			if (tep_is_file_bigendian(pevent)) {
+				extend_hdr = (time_delta & TRACE_DAT_RECORD_TIME_MASK) |
+				     (TRACE_DAT_RECORD_TYPE_TIME_EXTEND << 27);
+				delta_upper = time_delta >> 27;
+			} else {
+				extend_hdr = ((time_delta & TRACE_DAT_RECORD_TIME_MASK) <<
+					TRACE_DAT_RECORD_TIME_SHIFT) |
+					TRACE_DAT_RECORD_TYPE_TIME_EXTEND;
+				delta_upper = time_delta >> TRACE_DAT_RECORD_TIME_SHIFT;
+			}
+			extend_hdr  = to_file_u32(pevent, extend_hdr);   /* still needed */
+			delta_upper = to_file_u32(pevent, delta_upper);   /* still needed */
 
 			memcpy(extend, &extend_hdr, TRACE_DAT_WORD_SIZE);
 			memcpy(extend + TRACE_DAT_WORD_SIZE, &delta_upper,
@@ -273,7 +288,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 		/* Check page fit BEFORE allocating data record */
 		if (page_size_used + needed_size >
 			trace_dat_page_size - TRACE_DAT_RECORD_HEADER_SIZE) {
-			ret = trace_dat__write_page(fp, base_ts,
+			ret = trace_dat__write_page(fp, pevent, base_ts,
 					page_records, page_rec_sizes,
 					nr_page_recs);
 
@@ -299,7 +314,13 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 			time_delta = 0;
 		}
 
-		hdr_word = (time_delta << TRACE_DAT_RECORD_TIME_SHIFT) | type_len;
+		if (tep_is_file_bigendian(pevent))
+			hdr_word = ((unsigned int)time_delta & TRACE_DAT_RECORD_TIME_MASK) |
+				(type_len << 27);
+		else
+			hdr_word = ((unsigned int)time_delta << TRACE_DAT_RECORD_TIME_SHIFT) |
+				type_len;
+		hdr_word = to_file_u32(pevent, hdr_word);
 
 		data_rec = calloc(1, data_rec_size);
 		if (!data_rec) {
@@ -311,8 +332,11 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 		memcpy(data_rec, &hdr_word, TRACE_DAT_WORD_SIZE);
 
 		/* Large events: write actual byte length after header */
-		if (type_len == 0)
-			memcpy(data_rec + TRACE_DAT_WORD_SIZE, &data_len, TRACE_DAT_WORD_SIZE);
+		if (type_len == 0) {
+			unsigned int data_len_out = to_file_u32(pevent, data_len);
+
+			memcpy(data_rec + TRACE_DAT_WORD_SIZE, &data_len_out, TRACE_DAT_WORD_SIZE);
+		}
 
 		memcpy(data_rec + payload_offset, event->raw, data_len);
 
@@ -366,7 +390,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 	}
 
 	if (nr_page_recs > 0) {
-		ret = trace_dat__write_page(fp, base_ts,
+		ret = trace_dat__write_page(fp, pevent, base_ts,
 				page_records, page_rec_sizes, nr_page_recs);
 	}
 out_free:
@@ -378,11 +402,11 @@ static int trace_dat__write_cpu_dat(FILE *fp, int cpu, unsigned long long *file_
 }
 
 /* Write the strings section containing section name lookup table */
-int trace_dat__write_strings_section(void)
+int trace_dat__write_strings_section(struct tep_handle *pevent)
 {
-	unsigned short section_id = TRACE_DAT_SECTION_STRINGS;
-	unsigned short flags = 0;
 	unsigned long long section_size = 0;
+	unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_STRINGS);
+	unsigned short flags = to_file_u16(pevent, 0);
 	static const char * const section_names[] = {
 		"headers",		/* offset 0 - strid for section 16  */
 		"ftrace event formats", /* offset 8 - strid for section 17  */
@@ -397,7 +421,7 @@ int trace_dat__write_strings_section(void)
 	};
 
 	/* string_id points to "strings" string itself */
-	unsigned int string_id = STRID_STRINGS;
+	unsigned int string_id = to_file_u32(pevent, STRID_STRINGS);
 	int i;
 
 	if (!trace_dat_fp)
@@ -405,47 +429,59 @@ int trace_dat__write_strings_section(void)
 
 	for (i = 0; section_names[i] != NULL; i++)
 		section_size += strlen(section_names[i]) + 1;
+	section_size = to_file_u64(pevent, section_size);
 
 	/* write section header */
 	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))
-		return -EIO;
+		       !fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp)) {
+		pr_warning("Failed to write strings section\n");
+		trace_dat_write_failed = true;
+	}
 
 	/* write strings */
 	for (i = 0; section_names[i] != NULL; i++)
-		if (!fwrite(section_names[i], 1, strlen(section_names[i]) + 1, trace_dat_fp))
-			return -EIO;
+		if (!fwrite(section_names[i], 1, strlen(section_names[i]) + 1, trace_dat_fp)) {
+			pr_warning("Failed to write strings section\n");
+			trace_dat_write_failed = true;
+		}
 	return 0;
 }
 
 /* Writes options section containing CPUCOUNT, TRACECLOCK, EVENT_FORMAT, HEADER_INFO,
  * FTRACE_EVENTS, KALLSYMS, CMDLINES options, ending with DONE option pointing to next section.
  */
-int trace_dat__write_options_section1(void)
+int trace_dat__write_options_section1(struct tep_handle *pevent)
 {
-	unsigned short section_id = TRACE_DAT_SECTION_OPTIONS;
-	unsigned short flags = 0;
-	unsigned int string_id = STRID_OPTIONS_1;
+	unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_OPTIONS);
+	unsigned short flags = to_file_u16(pevent, 0);
+	unsigned int string_id = to_file_u32(pevent, STRID_OPTIONS_1);
 	unsigned long long section_size = 0;
 	long section_size_pos;
 	long payload_start;
 	unsigned long long section_start;
 	unsigned short opt_id;
 	unsigned int opt_size;
+	unsigned int raw_opt_size;
+	unsigned int nr_cpus;
 	char clock_buf[CLOCK_BUFFER_SIZE];
 	FILE *clock_file;
 	size_t bytes_read;
 	char *path;
 	unsigned long long next_offset;
+	unsigned long long events_off;
+	unsigned long long header_off;
+	unsigned long long ftrace_off;
+	unsigned long long kallsyms_off;
+	unsigned long long cmdline_off;
 	long end_pos;
 
 	if (!trace_dat_fp)
 		return -EBADF;
 
 	/* fill options_offset in initial format */
-	section_start = ftell(trace_dat_fp);
+	section_start = to_file_u64(pevent, ftell(trace_dat_fp));
 
 	if (fseek(trace_dat_fp, trace_dat_options_offset, SEEK_SET) < 0 ||
 	   !fwrite(&section_start, sizeof(unsigned long long), 1, trace_dat_fp) ||
@@ -464,16 +500,17 @@ int trace_dat__write_options_section1(void)
 	payload_start = ftell(trace_dat_fp);
 
 	/* CPUCOUNT option */
-	opt_id = TRACE_DAT_OPTION_CPUCOUNT;
-	opt_size = sizeof(unsigned int);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_CPUCOUNT);
+	opt_size = to_file_u32(pevent, sizeof(unsigned int));
+	nr_cpus = to_file_u32(pevent, trace_dat_nr_cpus);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_nr_cpus, sizeof(unsigned int), 1, trace_dat_fp))
+	    !fwrite(&nr_cpus, sizeof(unsigned int), 1, trace_dat_fp))
 		return -EIO;
 
 	/* TRACECLOCK option */
-	opt_id = TRACE_DAT_OPTION_TRACECLOCK;
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_TRACECLOCK);
 
 	path = get_tracing_file("trace_clock");
 	if (path) {
@@ -490,66 +527,72 @@ int trace_dat__write_options_section1(void)
 		strcpy(clock_buf, "local\n");
 		bytes_read = strlen(clock_buf);
 	}
-	opt_size = bytes_read + 1;
+	raw_opt_size = bytes_read + 1;
+	opt_size = to_file_u32(pevent, bytes_read + 1);
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(clock_buf, 1, opt_size, trace_dat_fp))
+	    !fwrite(clock_buf, 1, raw_opt_size, trace_dat_fp))
 		return -EIO;
 
 	/* EVENT option */
-	opt_id = TRACE_DAT_OPTION_EVENT;
-	opt_size = sizeof(unsigned long long);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_EVENT);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	events_off = to_file_u64(pevent, trace_dat_events_format_offset);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	   !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	   !fwrite(&trace_dat_events_format_offset, sizeof(unsigned long long),
+	   !fwrite(&events_off, sizeof(unsigned long long),
 		   1, trace_dat_fp))
 		return -EIO;
 
 	/* HEADER option */
-	opt_id = TRACE_DAT_OPTION_HEADER;
-	opt_size = sizeof(unsigned long long);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_HEADER);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	header_off = to_file_u64(pevent, trace_dat_header_info_offset);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_header_info_offset, sizeof(unsigned long long),
+	    !fwrite(&header_off, sizeof(unsigned long long),
 		    1, trace_dat_fp))
 		return -EIO;
 
 	/* FTRACE option */
-	opt_id = TRACE_DAT_OPTION_FTRACE;
-	opt_size = sizeof(unsigned long long);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_FTRACE);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	ftrace_off = to_file_u64(pevent, trace_dat_ftrace_format_offset);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_ftrace_format_offset, sizeof(unsigned long long),
+	    !fwrite(&ftrace_off, sizeof(unsigned long long),
 		   1, trace_dat_fp))
 		return -EIO;
 
 	/* KALLSYMS option */
-	opt_id = TRACE_DAT_OPTION_KALLSYMS;
-	opt_size = sizeof(unsigned long long);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_KALLSYMS);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	kallsyms_off = to_file_u64(pevent, trace_dat_kallsyms_offset);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_kallsyms_offset, sizeof(unsigned long long),
+	    !fwrite(&kallsyms_off, sizeof(unsigned long long),
 		    1, trace_dat_fp))
 		return -EIO;
 
 	/* CMDLINE option */
-	opt_id = TRACE_DAT_OPTION_CMDLINE;
-	opt_size = sizeof(unsigned long long);
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_CMDLINE);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	cmdline_off = to_file_u64(pevent, trace_dat_cmdline_offset);
 
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_cmdline_offset, sizeof(unsigned long long),
+	    !fwrite(&cmdline_off, sizeof(unsigned long long),
 		    1, trace_dat_fp))
 		return -EIO;
 
 	/* DONE option id - next_options_offset filled later */
-	opt_id = TRACE_DAT_OPTION_DONE;
-	opt_size = sizeof(unsigned long long);
-	next_offset = 0;  /* placeholder */
+	opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_DONE);
+	opt_size = to_file_u32(pevent, sizeof(unsigned long long));
+	next_offset = to_file_u64(pevent, 0);
 
 	trace_dat_next_options_offset = ftell(trace_dat_fp);
 	if (!fwrite(&opt_id, sizeof(unsigned short), 1, trace_dat_fp) ||
@@ -560,7 +603,7 @@ int trace_dat__write_options_section1(void)
 	/* fill section size */
 	end_pos = ftell(trace_dat_fp);
 
-	section_size = end_pos - payload_start;
+	section_size = to_file_u64(pevent, end_pos - payload_start);
 	if (fseek(trace_dat_fp, section_size_pos, SEEK_SET) < 0 ||
 	    !fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
 	    fseek(trace_dat_fp, end_pos, SEEK_SET) < 0)
@@ -574,20 +617,21 @@ int trace_dat__write_options_section1(void)
  * (flyrecord section offset, clock type, page size, CPU count,
  * per-CPU offsets/sizes) and DONE option.
  */
-int trace_dat__write_options_section2(void)
+int trace_dat__write_options_section2(struct tep_handle *pevent)
 {
-	unsigned short section_id  = TRACE_DAT_SECTION_OPTIONS;
-	unsigned short flags = 0;
-	unsigned int string_id = STRID_OPTIONS_2;
+	unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_OPTIONS);
+	unsigned short flags = to_file_u16(pevent, 0);
+	unsigned int string_id = to_file_u32(pevent, STRID_OPTIONS_2);
 	unsigned long long section_size = 0;
 	long section_size_pos;
 	long payload_start;
 	int cpu;
-	unsigned short opt_id = TRACE_DAT_OPTION_BUFFER;
-	unsigned int opt_size = 0;
+	unsigned short opt_id = to_file_u16(pevent, TRACE_DAT_OPTION_BUFFER);
+	unsigned int opt_size = 0;  /* filled after payload written */
 	long opt_size_pos;
 	unsigned long long data_offset = 0;
-	unsigned int page_size = (unsigned int)trace_dat_page_size;
+	unsigned int page_size = to_file_u32(pevent, (unsigned int)trace_dat_page_size);
+	unsigned int nr_cpus   = to_file_u32(pevent, trace_dat_nr_cpus);
 	const char *clock = "local";
 	unsigned long long next;
 	long end_pos;
@@ -600,7 +644,7 @@ int trace_dat__write_options_section2(void)
 		return -EINVAL;
 
 	/* fill done1 next offset - points to this section */
-	next = ftell(trace_dat_fp);
+	next = to_file_u64(pevent, ftell(trace_dat_fp));
 
 	if (fseek(trace_dat_fp, trace_dat_next_options_offset + 2 + 4, SEEK_SET) < 0 ||
 	    !fwrite(&next, sizeof(unsigned long long), 1, trace_dat_fp) ||
@@ -631,15 +675,16 @@ int trace_dat__write_options_section2(void)
 	    !fwrite("\0", 1, 1, trace_dat_fp) ||
 	    !fwrite(clock, 1, strlen(clock) + 1, trace_dat_fp) ||
 	    !fwrite(&page_size, sizeof(unsigned int), 1, trace_dat_fp) ||
-	    !fwrite(&trace_dat_nr_cpus, sizeof(unsigned int), 1, trace_dat_fp))
+	    !fwrite(&nr_cpus, sizeof(unsigned int), 1, trace_dat_fp))
 		return -EIO;
 
 	/* per cpu: cpu_id + offset placeholder + size */
 	for (cpu = 0; cpu < trace_dat_nr_cpus; cpu++) {
+		unsigned int cpu_out          = to_file_u32(pevent, cpu);
 		cpu_offset = 0;  /* filled in write_flyrecord */
-		cpu_size   = 0;  /* filled in write_flyrecord */
+		cpu_size = 0;  /* filled in write_flyrecord */
 
-		if (!fwrite(&cpu, sizeof(unsigned int), 1, trace_dat_fp))
+		if (!fwrite(&cpu_out, sizeof(unsigned int), 1, trace_dat_fp))
 			return -EIO;
 		buffer_opt_cpu_offsets_pos[cpu] = ftell(trace_dat_fp);
 		if (!fwrite(&cpu_offset, sizeof(unsigned long long), 1, trace_dat_fp) ||
@@ -650,17 +695,17 @@ int trace_dat__write_options_section2(void)
 	/* fill opt_size */
 	end_pos = ftell(trace_dat_fp);
 
-	opt_size = end_pos - opt_payload_start;
-	fseek(trace_dat_fp, opt_size_pos, SEEK_SET);
-	if (!fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp))
+	opt_size = to_file_u32(pevent, end_pos - opt_payload_start);
+	if (fseek(trace_dat_fp, opt_size_pos, SEEK_SET) < 0 ||
+	    !fwrite(&opt_size, sizeof(unsigned int), 1, trace_dat_fp) ||
+	    fseek(trace_dat_fp, end_pos, SEEK_SET) < 0)
 		return -EIO;
-	fseek(trace_dat_fp, end_pos, SEEK_SET);
 
 	/* DONE id=0 */
-	done_id = TRACE_DAT_OPTION_DONE;
-	done_size = sizeof(unsigned long long);
+	done_id = to_file_u16(pevent, TRACE_DAT_OPTION_DONE);
+	done_size = to_file_u32(pevent, sizeof(unsigned long long));
 	/* No additional options sections follow this one */
-	next = 0;
+	next = to_file_u64(pevent, 0);
 
 	if (!fwrite(&done_id, sizeof(unsigned short), 1, trace_dat_fp) ||
 	    !fwrite(&done_size, sizeof(unsigned int), 1, trace_dat_fp) ||
@@ -670,24 +715,25 @@ int trace_dat__write_options_section2(void)
 	/* fill section size */
 	end_pos = ftell(trace_dat_fp);
 
-	section_size = end_pos - payload_start;
-	fseek(trace_dat_fp, section_size_pos, SEEK_SET);
-	if (!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp))
+	section_size = to_file_u64(pevent, end_pos - payload_start);
+	if (fseek(trace_dat_fp, section_size_pos, SEEK_SET) < 0 ||
+	    !fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+	    fseek(trace_dat_fp, end_pos, SEEK_SET) < 0)
 		return -EIO;
-	fseek(trace_dat_fp, end_pos, SEEK_SET);
 
 	return 0;
 
 }
 
-int trace_dat__write_flyrecord_section(void)
+int trace_dat__write_flyrecord_section(struct tep_handle *pevent)
 {
-	unsigned short section_id = TRACE_DAT_SECTION_FLYRECORD;
-	unsigned short flags = 0;
-	unsigned int string_id = STRID_BUFFER_FLYRECORD;
+	unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_FLYRECORD);
+	unsigned short flags = to_file_u16(pevent, 0);
+	unsigned int string_id = to_file_u32(pevent, STRID_BUFFER_FLYRECORD);
 	unsigned long long section_size = 0;
 	long section_size_pos;
 	long flyrecord_start;
+	unsigned long long flyrecord_out;
 	long after_header;
 	long padding_needed;
 	unsigned long long *cpu_offsets;
@@ -750,7 +796,7 @@ int trace_dat__write_flyrecord_section(void)
 	for (cpu = 0; cpu < trace_dat_nr_cpus; cpu++) {
 		start = ftell(trace_dat_fp);
 
-		ret = trace_dat__write_cpu_dat(trace_dat_fp, cpu, &cpu_offsets[cpu]);
+		ret = trace_dat__write_cpu_dat(trace_dat_fp, pevent, cpu, &cpu_offsets[cpu]);
 
 		if (ret < 0) {
 			pr_err("Failed to write CPU %d data\n", cpu);
@@ -762,7 +808,7 @@ int trace_dat__write_flyrecord_section(void)
 	/* fill section size */
 	end_pos = ftell(trace_dat_fp);
 
-	section_size = end_pos - after_header;
+	section_size = to_file_u64(pevent, end_pos - after_header);
 	if (fseek(trace_dat_fp, section_size_pos, SEEK_SET) < 0 ||
 	    !fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp)) {
 		ret = -EIO;
@@ -775,6 +821,8 @@ int trace_dat__write_flyrecord_section(void)
 
 	/* fill cpu offsets and sizes in BUFFER option */
 	for (cpu = 0; cpu < trace_dat_nr_cpus; cpu++) {
+		cpu_offsets[cpu] = to_file_u64(pevent, cpu_offsets[cpu]);
+		cpu_sizes[cpu]   = to_file_u64(pevent, cpu_sizes[cpu]);
 		if (fseek(trace_dat_fp, buffer_opt_cpu_offsets_pos[cpu], SEEK_SET) < 0 ||
 		    !fwrite(&cpu_offsets[cpu], sizeof(unsigned long long), 1, trace_dat_fp) ||
 		    !fwrite(&cpu_sizes[cpu], sizeof(unsigned long long), 1, trace_dat_fp)) {
@@ -784,8 +832,9 @@ int trace_dat__write_flyrecord_section(void)
 	}
 
 	/* fill data offset in buffer option */
+	flyrecord_out = to_file_u64(pevent, flyrecord_start);
 	if (fseek(trace_dat_fp, opt_payload_start, SEEK_SET) < 0 ||
-	    !fwrite(&flyrecord_start, sizeof(unsigned long long), 1, trace_dat_fp)) {
+	    !fwrite(&flyrecord_out, sizeof(unsigned long long), 1, trace_dat_fp)) {
 		ret = -EIO;
 		goto cleanup;
 	}
@@ -795,7 +844,6 @@ int trace_dat__write_flyrecord_section(void)
 		goto cleanup;
 	}
 
-
 cleanup:
 	free(cpu_offsets);
 	free(cpu_sizes);
diff --git a/tools/perf/util/trace-dat.h b/tools/perf/util/trace-dat.h
index 9aec37b708d4..5985083b275a 100644
--- a/tools/perf/util/trace-dat.h
+++ b/tools/perf/util/trace-dat.h
@@ -8,9 +8,13 @@
 #define __PERF_TRACE_DAT_H
 
 #include <stdio.h>
+#include <stdbool.h>
+#include <event-parse.h>
+#include <byteswap.h>
+#include "util.h"
 
 /* trace.dat file format version */
-#define TRACE_DAT_VERSION '7'
+#define TRACE_DAT_VERSION "7"
 
 /*
  * Section IDs for trace.dat format
@@ -51,6 +55,32 @@
 #define STRID_OPTIONS_2        77
 #define STRID_BUFFER_FLYRECORD 85
 
+/*
+ * Set by trace.dat section writers (kallsyms, ftrace, events etc.) on
+ * fwrite() failure; checked by trace_convert__perf2dat() to clean up.
+ */
+extern bool trace_dat_write_failed;
+
+/*
+ * tep handle from the recording machine; set by trace_convert__perf2dat()
+ * before options/flyrecord sections are written.
+ */
+
+static inline uint16_t to_file_u16(struct tep_handle *pevent, uint16_t val)
+{
+	return tep_read_number(pevent, &val, 2);
+}
+
+static inline uint32_t to_file_u32(struct tep_handle *pevent, uint32_t val)
+{
+	return tep_read_number(pevent, &val, 4);
+}
+
+static inline uint64_t to_file_u64(struct tep_handle *pevent, uint64_t val)
+{
+	return tep_read_number(pevent, &val, 8);
+}
+
 struct perf_session;
 
 extern FILE *trace_dat_fp;
@@ -75,9 +105,9 @@ int trace_dat__collect_cpu_event(int cpu, unsigned long long ts,
 void trace_dat__free_cpu_buffers(void);
 
 /* write trace.dat file sections */
-int trace_dat__write_options_section1(void);
-int trace_dat__write_options_section2(void);
-int trace_dat__write_flyrecord_section(void);
-int trace_dat__write_strings_section(void);
+int trace_dat__write_options_section1(struct tep_handle *pevent);
+int trace_dat__write_options_section2(struct tep_handle *pevent);
+int trace_dat__write_flyrecord_section(struct tep_handle *pevent);
+int trace_dat__write_strings_section(struct tep_handle *pevent);
 
 #endif /* __PERF_TRACE_DAT_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index db1622fc99c2..dd81c675e43c 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -20,6 +20,7 @@
 #include "trace-event.h"
 #include "debug.h"
 #include "util.h"
+#include "trace-dat.h"
 
 static int input_fd;
 
@@ -155,10 +156,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.
@@ -170,11 +170,59 @@ 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 && !trace_dat_write_failed) {
+			unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_KALLSYMS);
+			unsigned short flags = to_file_u16(pevent, 0);
+			unsigned int string_id = to_file_u32(pevent, STRID_KALLSYMS);
+			unsigned long long section_size = to_file_u64(pevent, sizeof(unsigned int));
+			unsigned int kallsyms_data = to_file_u32(pevent, 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(&kallsyms_data, sizeof(unsigned int), 1, trace_dat_fp)) {
+				pr_warning("Failed to write trace.dat kallsyms section\n");
+				trace_dat_write_failed = true;
+			}
+		}
+		return 0;
+	}
+	buf = malloc(size);
+	if (buf == NULL)
+		return -1;
+	if (do_read(buf, size) < 0) {
+		free(buf);
+		return -1;
+	}
 	trace_data_size += size;
+	/* Write kallsyms section with data */
+	if (trace_dat_fp && !trace_dat_write_failed) {
+		unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_KALLSYMS);
+		unsigned int string_id = to_file_u32(pevent, STRID_KALLSYMS);
+		unsigned long long section_size = to_file_u64(pevent, sizeof(unsigned int) + size);
+		unsigned short flags = to_file_u16(pevent, 0);
+		unsigned int size_out = to_file_u32(pevent, size);
+
+		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_out, sizeof(unsigned int), 1, trace_dat_fp) ||
+		    !fwrite(buf, 1, size, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat kallsyms section\n");
+			trace_dat_write_failed = true;
+		}
+	}
+	free(buf);
 	return 0;
 }
 
+
 static int read_ftrace_printk(struct tep_handle *pevent)
 {
 	unsigned int size;
@@ -210,6 +258,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];
 	ssize_t ret = 0;
@@ -224,6 +279,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;
@@ -242,19 +298,63 @@ 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 && !trace_dat_write_failed) {
+		unsigned long long header_page_size_out;
+		unsigned long long header_event_size_out;
+
+		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 = to_file_u16(pevent, TRACE_DAT_SECTION_HEADER);
+		flags = to_file_u16(pevent, 0);
+		string_id = to_file_u32(pevent, STRID_HEADERS);
+		section_size = to_file_u64(pevent, 12 + 8 + header_page_size +
+				13 + 8 + header_event_size);
+		header_page_size_out = to_file_u64(pevent, header_page_size);
+		header_event_size_out = to_file_u64(pevent, 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_out, 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_out, sizeof(unsigned long long), 1, trace_dat_fp) ||
+		    !fwrite(header_event, 1, header_event_size, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat header section\n");
+			trace_dat_write_failed = true;
+		}
+		free(header_event);
+	} else {
+		skip(size);
+	}
 
+	free(header_page);
 	return ret;
 }
 
@@ -274,6 +374,15 @@ 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 && !trace_dat_write_failed) {
+		unsigned long long size_out = to_file_u64(pevent, size);
+
+		if (!fwrite(&size_out, sizeof(unsigned long long), 1, trace_dat_fp) ||
+		    !fwrite(buf, 1, size, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat ftrace event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
 
 	ret = parse_ftrace_file(pevent, buf, size);
 	if (ret < 0)
@@ -298,6 +407,15 @@ 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 && !trace_dat_write_failed) {
+		unsigned long long size_out = to_file_u64(pevent, size);
+
+		if (!fwrite(&size_out, sizeof(unsigned long long), 1, trace_dat_fp) ||
+		    !fwrite(buf, 1, size, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
 
 	ret = parse_event_file(pevent, buf, size, sys);
 	if (ret < 0)
@@ -313,8 +431,39 @@ 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 && !trace_dat_write_failed) {
+		unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_FTRACE);
+		unsigned short flags = to_file_u16(pevent, 0);
+		unsigned int string_id = to_file_u32(pevent, STRID_FTRACE_FORMATS);
+		unsigned int count_out = to_file_u32(pevent, count);
+
+		section_size = to_file_u64(pevent, 0);
+		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)) {
+			pr_warning("Failed to write trace.dat ftrace event formats section\n");
+			trace_dat_write_failed = true;
+		}
+		section_size_pos = ftell(trace_dat_fp);
+		if (!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat ftrace event formats section\n");
+			trace_dat_write_failed = true;
+		}
+		count_pos = ftell(trace_dat_fp);
+		if (!fwrite(&count_out, sizeof(unsigned int), 1, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat ftrace event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
 
 	for (i = 0; i < count; i++) {
 		size = read8(pevent);
@@ -322,6 +471,18 @@ 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 && !trace_dat_write_failed) {
+		end_pos = ftell(trace_dat_fp);
+		section_size = to_file_u64(pevent, end_pos - count_pos);
+		if (fseek(trace_dat_fp, section_size_pos, SEEK_SET) < 0 ||
+			!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+			fseek(trace_dat_fp, end_pos, SEEK_SET) < 0) {
+			pr_warning("Failed to write trace.dat ftrace event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
+
 	return 0;
 }
 
@@ -333,8 +494,38 @@ static int read_event_files(struct tep_handle *pevent)
 	int count;
 	int i,x;
 	ssize_t 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 && !trace_dat_write_failed) {
+		unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_EVENTS);
+		unsigned short flags = to_file_u16(pevent, 0);
+		unsigned int string_id = to_file_u32(pevent, STRID_EVENT_FORMATS);
+		unsigned int systems_out = to_file_u32(pevent, systems);
+
+		section_size = to_file_u64(pevent, 0);
+		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)) {
+			pr_warning("Failed to write trace.dat event formats section\n");
+			trace_dat_write_failed = true;
+		}
+		section_size_pos = ftell(trace_dat_fp);
+		if (!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat event formats section\n");
+			trace_dat_write_failed = true;
+		}
+		sys_count_pos = ftell(trace_dat_fp);
+		if (!fwrite(&systems_out, sizeof(unsigned int), 1, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
 
 	for (i = 0; i < systems; i++) {
 		sys = read_string();
@@ -342,6 +533,15 @@ static int read_event_files(struct tep_handle *pevent)
 			return -1;
 
 		count = read4(pevent);
+		if (trace_dat_fp && !trace_dat_write_failed) {
+			unsigned int count_out = to_file_u32(pevent, count);
+
+			if (!fwrite(sys, 1, strlen(sys) + 1, trace_dat_fp) ||
+			    !fwrite(&count_out, sizeof(unsigned int), 1, trace_dat_fp)) {
+				pr_warning("Failed to write trace.dat event formats section\n");
+				trace_dat_write_failed = true;
+			}
+		}
 
 		for (x=0; x < count; x++) {
 			size = read8(pevent);
@@ -353,6 +553,18 @@ static int read_event_files(struct tep_handle *pevent)
 		}
 		free(sys);
 	}
+	/* Fill in section size after writing all event files */
+	if (trace_dat_fp && !trace_dat_write_failed) {
+		end_pos = ftell(trace_dat_fp);
+		section_size = to_file_u64(pevent, end_pos - sys_count_pos);
+		if (fseek(trace_dat_fp, section_size_pos, SEEK_SET) < 0 ||
+			!fwrite(&section_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+			fseek(trace_dat_fp, end_pos, SEEK_SET) < 0) {
+			pr_warning("Failed to write trace.dat event formats section\n");
+			trace_dat_write_failed = true;
+		}
+	}
+
 	return 0;
 }
 
@@ -364,8 +576,28 @@ 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 && !trace_dat_write_failed) {
+			unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_CMDLINE);
+			unsigned short flags = to_file_u16(pevent, 0);
+			unsigned int string_id = to_file_u32(pevent, STRID_CMDLINES);
+			unsigned long long section_size =
+				to_file_u64(pevent, sizeof(unsigned long long));
+			unsigned long long section_data = to_file_u64(pevent, 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)) {
+				pr_warning("Failed to write trace.dat cmdlines section\n");
+				trace_dat_write_failed = true;
+			}
+		}
 		return 0;
+	}
 
 	if (size == ULLONG_MAX) {
 		pr_debug("invalid saved cmdline size");
@@ -383,6 +615,27 @@ 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 && !trace_dat_write_failed) {
+		unsigned short section_id = to_file_u16(pevent, TRACE_DAT_SECTION_CMDLINE);
+		unsigned short flags = to_file_u16(pevent, 0);
+		unsigned int string_id = to_file_u32(pevent, STRID_CMDLINES);
+		unsigned long long section_size =
+			to_file_u64(pevent, sizeof(unsigned long long) + size);
+		unsigned long long size_out = to_file_u64(pevent, 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_out, sizeof(unsigned long long), 1, trace_dat_fp) ||
+			!fwrite(buf, 1, size, trace_dat_fp)) {
+			pr_warning("Failed to write trace.dat cmdlines section\n");
+			trace_dat_write_failed = true;
+		}
+	}
+
 	buf[ret] = '\0';
 
 	parse_saved_cmdline(pevent, buf, size);
@@ -407,6 +660,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;
@@ -418,12 +672,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)
@@ -460,6 +719,34 @@ 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 && !trace_dat_write_failed) {
+		unsigned char endian = file_bigendian;
+		unsigned char long_size = file_long_size;
+		unsigned int page_size = to_file_u32(pevent, file_page_size);
+		unsigned long long placeholder = to_file_u64(pevent, 0);
+
+		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)) {
+			pr_warning("Failed to write trace.dat initalfile header\n");
+			trace_dat_write_failed = true;
+		}
+
+		if (!trace_dat_write_failed) {
+			trace_dat_options_offset = ftell(trace_dat_fp);
+			if (!fwrite(&placeholder, sizeof(unsigned long long), 1, trace_dat_fp)) {
+				pr_warning("Failed to write trace.dat initial file header\n");
+				trace_dat_write_failed = true;
+			}
+		}
+	}
+
 	err = read_header_files(pevent);
 	if (err)
 		goto out;
@@ -480,6 +767,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 && !trace_dat_write_failed) {
+		err = trace_dat__write_strings_section(pevent);
+		if (err)
+			goto out;
+	}
 
 	size = trace_data_size;
 	repipe = false;
-- 
2.47.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.