@@ -51,5 +51,6 @@ struct cpu_data_source {
int out_write_cpu_data(struct tracecmd_output *handle, int cpus,
struct cpu_data_source *data, const char *buff_name);
off64_t msg_lseek(struct tracecmd_msg_handle *msg_handle, off_t offset, int whence);
+unsigned long long get_last_option_offset(struct tracecmd_input *handle);
#endif /* _TRACE_CMD_LOCAL_H */
@@ -176,6 +176,7 @@ struct tracecmd_input {
struct file_section *sections;
bool options_init;
unsigned long long options_start;
+ unsigned long long options_last_offset;
size_t total_file_size;
/* For custom profilers. */
@@ -2858,6 +2859,30 @@ tracecmd_search_task_map(struct tracecmd_input *handle,
return lib;
}
+__hidden unsigned long long get_last_option_offset(struct tracecmd_input *handle)
+{
+ return handle->options_last_offset;
+}
+
+static int handle_option_done(struct tracecmd_input *handle, char *buf, int size)
+{
+ unsigned long long offset;
+
+ if (size < 8)
+ return -1;
+ offset = lseek64(handle->fd, 0, SEEK_CUR);
+ if (offset >= size)
+ handle->options_last_offset = offset - size;
+ offset = tep_read_number(handle->pevent, buf, 8);
+ if (!offset)
+ return 0;
+
+ if (lseek64(handle->fd, offset, SEEK_SET) == (off_t)-1)
+ return -1;
+
+ return handle_options(handle);
+}
+
static inline int save_read_number(struct tep_handle *tep, char *data, int *data_size,
int *read_pos, int bytes, unsigned long long *num)
{
@@ -2960,19 +2985,27 @@ static int handle_options(struct tracecmd_input *handle)
long long offset;
unsigned short option;
unsigned int size;
+ unsigned short id, flags;
char *cpustats = NULL;
struct hook_list *hook;
char *buf;
int cpus;
int ret;
- handle->options_start = lseek64(handle->fd, 0, SEEK_CUR);
+ if (!HAS_SECTIONS(handle)) {
+ handle->options_start = lseek64(handle->fd, 0, SEEK_CUR);
+ } else {
+ if (read_section_header(handle, &id, &flags, NULL, NULL))
+ return -1;
+ if (id != TRACECMD_OPTION_DONE)
+ return -1;
+ }
for (;;) {
if (read2(handle, &option))
return -1;
- if (option == TRACECMD_OPTION_DONE)
+ if (!HAS_SECTIONS(handle) && option == TRACECMD_OPTION_DONE)
break;
/* next 4 bytes is the size of the option */
@@ -3112,7 +3145,10 @@ static int handle_options(struct tracecmd_input *handle)
section_add_or_update(handle, option, -1,
tep_read_number(handle->pevent, buf, 8), 0);
break;
-
+ case TRACECMD_OPTION_DONE:
+ ret = handle_option_done(handle, buf, size);
+ free(buf);
+ return ret;
default:
tracecmd_warning("unknown option %d", option);
break;
@@ -2154,7 +2154,7 @@ struct tracecmd_output *tracecmd_get_output_handle_fd(int fd)
tep_ref(handle->pevent);
handle->page_size = tracecmd_page_size(ihandle);
handle->file_version = tracecmd_get_in_file_version(ihandle);
- handle->options_start = tracecmd_get_options_offset(ihandle);
+ handle->options_start = get_last_option_offset(ihandle);
list_head_init(&handle->options);
list_head_init(&handle->buffers);
In trace file version 7 the DONE option is extended to store the offset in the file to the next options section. This way a list of options sections can be stored in the file. Added logic to recursively read all option sections from the file. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- lib/trace-cmd/include/trace-cmd-local.h | 1 + lib/trace-cmd/trace-input.c | 42 +++++++++++++++++++++++-- lib/trace-cmd/trace-output.c | 2 +- 3 files changed, 41 insertions(+), 4 deletions(-)