[PATCH 1/2] trace-cmd record: Handle last_boot_info file
Steven Rostedt <[email protected]> Tue, 3 Feb 2026 20:18:05 -0500
| Newsgroups | org.kernel.vger.linux-trace-devel |
|---|---|
| Message-ID | <[email protected]> |
From: "Steven Rostedt (Google)" <[email protected]> A persistent ring buffer has the ability to record a trace and have it exposed after a crash or reboot. The issue with that buffer is that the function pointers in it have the addresses of the last boot (the one that the function events were recorded in). Due to KASLR, these address do not match the address in kallsyms and can not be used directly to map the address to the names of the functions. To solve this, the kernel exposes the addresses in a last_boot_info file if the content of the buffer is from the last boot. If the content is of the current boot, the file simply contains "# Current". If the file exists in the instance and contains something other than "# Current" then record it into a new section called TRACECMD_OPTION_LAST_BOOT_INFO. Signed-off-by: Steven Rostedt (Google) <[email protected]> --- .../trace-cmd/trace-cmd.dat.v7.5.txt | 7 +++ .../include/private/trace-cmd-private.h | 1 + lib/trace-cmd/trace-ftrace.c | 4 +- lib/trace-cmd/trace-input.c | 12 +++++ tracecmd/include/trace-local.h | 2 + tracecmd/trace-record.c | 49 +++++++++++++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt b/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt index 73857d1a04f8..154ffe271df3 100644 --- a/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt +++ b/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt @@ -276,6 +276,13 @@ OPTIONS SECTION compression algorthim defined by the trace.dat header. The compression data includes the size of the uncompressed output. + LAST_BOOT_INFO: id 24, size vary + The LAST_BOOT_INFO option data contains the content of the last_boot_info if + the file existed for an instance. It starts with the instance name, followed + by a colon ":" and then the content of the last_boot_info file. Currently + the instance name is not used, but exists in case in the future there are + more than one instance with this file. + HEADER INFO SECTION ------------------- diff --git a/lib/trace-cmd/include/private/trace-cmd-private.h b/lib/trace-cmd/include/private/trace-cmd-private.h index 4743bbc62048..cf19c0d6f7e1 100644 --- a/lib/trace-cmd/include/private/trace-cmd-private.h +++ b/lib/trace-cmd/include/private/trace-cmd-private.h @@ -160,6 +160,7 @@ enum { TRACECMD_OPTION_CMDLINES, TRACECMD_OPTION_BUFFER_TEXT, TRACECMD_OPTION_BTF_FILE, + TRACECMD_OPTION_LAST_BOOT_INFO, TRACECMD_OPTION_MAX, }; diff --git a/lib/trace-cmd/trace-ftrace.c b/lib/trace-cmd/trace-ftrace.c index f52b203ccbd4..c874113bc66e 100644 --- a/lib/trace-cmd/trace-ftrace.c +++ b/lib/trace-cmd/trace-ftrace.c @@ -272,7 +272,7 @@ print_graph_entry_leaf(struct trace_seq *s, } /* In case this is a retaddr event */ - if (!tep_get_field_val(s, event, "retaddr", record, &val, 1)) + if (!tep_get_field_val(s, event, "retaddr", record, &val, 0)) retfunc = tep_find_function(pevent, val); duration = rettime - calltime; @@ -347,7 +347,7 @@ static int print_graph_nested(struct trace_seq *s, return trace_seq_putc(s, '!'); /* In case this is a retaddr event */ - if (!tep_get_field_val(s, event, "retaddr", record, &val, 1)) + if (!tep_get_field_val(s, event, "retaddr", record, &val, 0)) retfunc = tep_find_function(pevent, val); /* Function */ diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 7e03c0da5485..ef5095b83b09 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -4227,6 +4227,18 @@ static int handle_options(struct tracecmd_input *handle) if (!(handle->flags & TRACECMD_FL_RAW_TS)) handle->flags |= TRACECMD_FL_IN_USECS; break; + case TRACECMD_OPTION_LAST_BOOT_INFO: + { + char *file; + + /* Skip the name of the instance (for now) */ + file = strchr(buf, ':'); + if (!file) + break; + file++; + tep_parse_last_boot_info(handle->pevent, file); + break; + } case TRACECMD_OPTION_HEADER_INFO: case TRACECMD_OPTION_FTRACE_EVENTS: case TRACECMD_OPTION_EVENT_FORMATS: diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 4ad07b6357b1..32c5c5a3c4e9 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -298,6 +298,8 @@ struct buffer_instance { int argc; char **argv; + char *last_boot_info; + struct addrinfo *result; unsigned int cid; unsigned int port; diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 30727d613492..dfa6cb91c436 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -4778,6 +4778,22 @@ static void record_data(struct common_record_context *ctx) cpus); add_buffer_stat(handle, instance); check_need_btf(&need_btf, instance->tracefs); + if (instance->last_boot_info && instance->name) { + char *buf; + int len; + + if (asprintf(&buf, "%s:%s", instance->name, + instance->last_boot_info) < 0) { + warning("Failed to add last_boot_info"); + continue; + } + len = strlen(instance->name); + len += strlen(instance->last_boot_info) + 2; + + tracecmd_add_option(handle, TRACECMD_OPTION_LAST_BOOT_INFO, + len, buf); + free(buf); + } } } @@ -7425,6 +7441,37 @@ void trace_set(int argc, char **argv) exit(0); } +static void read_last_boot_info(void) +{ + struct buffer_instance *instance; + char *path; + char *buf; + + for_all_instances(instance) { + if (is_guest(instance)) + continue; + + if (!tracefs_file_exists(instance->tracefs, "last_boot_info")) + continue; + + path = tracefs_instance_get_file(instance->tracefs, "last_boot_info"); + if (!path) { + warning("Could not read last_boot_info"); + return; + } + buf = read_file(path); + tracefs_put_tracing_file(path); + if (!buf) { + warning("Could not copy last_boot_info"); + return; + } + if (strncmp(buf, "# Current", 9) == 0) + free(buf); + else + instance->last_boot_info = buf; + } +} + void trace_extract(int argc, char **argv) { struct common_record_context ctx; @@ -7466,6 +7513,8 @@ void trace_extract(int argc, char **argv) if (ctx.events) expand_event_list(); + read_last_boot_info(); + page_size = getpagesize(); update_plugins(type); set_options(); -- 2.51.0