]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
tracing: Show module names and addresses of last boot
authorSteven Rostedt <rostedt@goodmis.org>
Wed, 5 Mar 2025 16:45:46 +0000 (11:45 -0500)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Fri, 28 Mar 2025 12:39:27 +0000 (08:39 -0400)
Add the last boot module's names and addresses to the last_boot_info file.
This only shows the module information from a previous boot. If the buffer
is started and is recording the current boot, this file still will only
show "current".

  ~# cat instances/boot_mapped/last_boot_info
  10c00000 [kernel]
  ffffffffc00ca000 usb_serial_simple
  ffffffffc00ae000 usbserial
  ffffffffc008b000 bfq

  ~# echo function > instances/boot_mapped/current_tracer
  ~# cat instances/boot_mapped/last_boot_info
  # Current

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lore.kernel.org/20250305164609.299186021@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
kernel/trace/trace.c

index a75e03994312f9e6fbf298633d8e53dfe7680e76..d22f8d34b18d38ea8f7f0eae81172c8cf7e704f8 100644 (file)
@@ -5999,6 +5999,8 @@ struct trace_scratch {
        struct trace_mod_entry  entries[];
 };
 
+static DEFINE_MUTEX(scratch_mutex);
+
 static int save_mod(struct module *mod, void *data)
 {
        struct trace_array *tr = data;
@@ -6039,6 +6041,7 @@ static void update_last_data(struct trace_array *tr)
                       flex_array_size(tscratch, entries, tscratch->nr_entries));
                tscratch->nr_entries = 0;
 
+               guard(mutex)(&scratch_mutex);
                module_for_each_mod(save_mod, tr);
        }
 
@@ -6876,15 +6879,47 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
-static ssize_t
-tracing_last_boot_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+#define LAST_BOOT_HEADER ((void *)1)
+
+static void *l_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct trace_array *tr = filp->private_data;
+       struct trace_array *tr = m->private;
        struct trace_scratch *tscratch = tr->scratch;
-       struct seq_buf seq;
-       char buf[64];
+       unsigned int index = *pos;
+
+       (*pos)++;
 
-       seq_buf_init(&seq, buf, 64);
+       if (*pos == 1)
+               return LAST_BOOT_HEADER;
+
+       /* Only show offsets of the last boot data */
+       if (!tscratch || !(tr->flags & TRACE_ARRAY_FL_LAST_BOOT))
+               return NULL;
+
+       /* *pos 0 is for the header, 1 is for the first module */
+       index--;
+
+       if (index >= tscratch->nr_entries)
+               return NULL;
+
+       return &tscratch->entries[index];
+}
+
+static void *l_start(struct seq_file *m, loff_t *pos)
+{
+       mutex_lock(&scratch_mutex);
+
+       return l_next(m, NULL, pos);
+}
+
+static void l_stop(struct seq_file *m, void *p)
+{
+       mutex_unlock(&scratch_mutex);
+}
+
+static void show_last_boot_header(struct seq_file *m, struct trace_array *tr)
+{
+       struct trace_scratch *tscratch = tr->scratch;
 
        /*
         * Do not leak KASLR address. This only shows the KASLR address of
@@ -6894,11 +6929,52 @@ tracing_last_boot_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t
         * should not be the same as the current boot.
         */
        if (tscratch && (tr->flags & TRACE_ARRAY_FL_LAST_BOOT))
-               seq_buf_printf(&seq, "%lx\t[kernel]\n", tscratch->kaslr_addr);
+               seq_printf(m, "%lx\t[kernel]\n", tscratch->kaslr_addr);
        else
-               seq_buf_puts(&seq, "# Current\n");
+               seq_puts(m, "# Current\n");
+}
 
-       return simple_read_from_buffer(ubuf, cnt, ppos, buf, seq_buf_used(&seq));
+static int l_show(struct seq_file *m, void *v)
+{
+       struct trace_array *tr = m->private;
+       struct trace_mod_entry *entry = v;
+
+       if (v == LAST_BOOT_HEADER) {
+               show_last_boot_header(m, tr);
+               return 0;
+       }
+
+       seq_printf(m, "%lx\t%s\n", entry->mod_addr, entry->mod_name);
+       return 0;
+}
+
+static const struct seq_operations last_boot_seq_ops = {
+       .start          = l_start,
+       .next           = l_next,
+       .stop           = l_stop,
+       .show           = l_show,
+};
+
+static int tracing_last_boot_open(struct inode *inode, struct file *file)
+{
+       struct trace_array *tr = inode->i_private;
+       struct seq_file *m;
+       int ret;
+
+       ret = tracing_check_open_get_tr(tr);
+       if (ret)
+               return ret;
+
+       ret = seq_open(file, &last_boot_seq_ops);
+       if (ret) {
+               trace_array_put(tr);
+               return ret;
+       }
+
+       m = file->private_data;
+       m->private = tr;
+
+       return 0;
 }
 
 static int tracing_buffer_meta_open(struct inode *inode, struct file *filp)
@@ -7527,10 +7603,10 @@ static const struct file_operations trace_time_stamp_mode_fops = {
 };
 
 static const struct file_operations last_boot_fops = {
-       .open           = tracing_open_generic_tr,
-       .read           = tracing_last_boot_read,
-       .llseek         = generic_file_llseek,
-       .release        = tracing_release_generic_tr,
+       .open           = tracing_last_boot_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = tracing_seq_release,
 };
 
 #ifdef CONFIG_TRACER_SNAPSHOT