From: Masami Hiramatsu (Google) <[email protected]>

Since the relative offset stacktrace requires a special module loading
events to decode binary, it should be an optional for normal use case.
User can enable this feature via `options/relative-stacktrace`.

Signed-off-by: Masami Hiramatsu (Google) <[email protected]>
---
 kernel/trace/trace.c         |   13 ++++++++-----
 kernel/trace/trace.h         |    2 ++
 kernel/trace/trace_entries.h |   22 ++++++++++++++++++++++
 kernel/trace/trace_output.c  |   37 ++++++++++++++++++++++++++++++++-----
 4 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8e86a43b368c..b4da5e29957f 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2926,6 +2926,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        struct ftrace_stack *fstack;
        struct stack_entry *entry;
        int stackidx;
+       int type;
 
        /*
         * Add one, for this function and the call to save_stack_trace()
@@ -2937,6 +2938,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
 #endif
 
        preempt_disable_notrace();
+       type = (tr->trace_flags & TRACE_ITER_REL_STACK_BIT) ? TRACE_REL_STACK : 
TRACE_STACK;
 
        stackidx = __this_cpu_inc_return(ftrace_stack_reserve) - 1;
 
@@ -2973,17 +2975,18 @@ static void __ftrace_trace_stack(struct trace_array *tr,
                for (int i = 0; i < nr_entries; i++) {
                        if (calls[i] >= tramp_start && calls[i] < tramp_end)
                                calls[i] = FTRACE_TRAMPOLINE_MARKER;
-                       else
+                       else if (type == TRACE_REL_STACK)
                                calls[i] -= (unsigned long)_stext;
                }
        }
 #else
-       /* Adjsut entries as the offset from _stext, instead of raw address. */
-       for (int i = 0; i < nr_entries; i++)
-               fstack->calls[i] -= (unsigned long)_stext;
+       if (type == TRACE_REL_STACK)
+               /* Adjsut entries as the offset from _stext, instead of raw 
address. */
+               for (int i = 0; i < nr_entries; i++)
+                       fstack->calls[i] -= (unsigned long)_stext;
 #endif
 
-       event = __trace_buffer_lock_reserve(buffer, TRACE_STACK,
+       event = __trace_buffer_lock_reserve(buffer, type,
                                    struct_size(entry, caller, nr_entries),
                                    trace_ctx);
        if (!event)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 9c21ba45b7af..602aea0ec69a 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -55,6 +55,7 @@ enum trace_type {
        TRACE_TIMERLAT,
        TRACE_RAW_DATA,
        TRACE_FUNC_REPEATS,
+       TRACE_REL_STACK,
 
        __TRACE_LAST_TYPE,
 };
@@ -1350,6 +1351,7 @@ extern int trace_get_user(struct trace_parser *parser, 
const char __user *ubuf,
                C(TRACE_PRINTK,         "trace_printk_dest"),   \
                C(PAUSE_ON_TRACE,       "pause-on-trace"),      \
                C(HASH_PTR,             "hash-ptr"),    /* Print hashed pointer 
*/ \
+               C(REL_STACK,    "relative-stacktrace"), \
                FUNCTION_FLAGS                                  \
                FGRAPH_FLAGS                                    \
                STACK_FLAGS                                     \
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index fbfb396905a6..7769f95b70fe 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -229,6 +229,28 @@ FTRACE_ENTRY(kernel_stack, stack_entry,
                 (void *)__entry->caller[6], (void *)__entry->caller[7])
 );
 
+FTRACE_ENTRY_DUP(kernel_rel_stack, stack_entry,
+
+       TRACE_REL_STACK,
+
+       F_STRUCT(
+               __field(        int,            size    )
+               __stack_array(  unsigned long,  caller, FTRACE_STACK_ENTRIES, 
size)
+       ),
+
+       F_printk("\t=> %ps\n\t=> %ps\n\t=> %ps\n"
+                "\t=> %ps\n\t=> %ps\n\t=> %ps\n"
+                "\t=> %ps\n\t=> %ps\n",
+                (void *)__entry->caller[0] + (unsigned long)_stext,
+                (void *)__entry->caller[1] + (unsigned long)_stext,
+                (void *)__entry->caller[2] + (unsigned long)_stext,
+                (void *)__entry->caller[3] + (unsigned long)_stext,
+                (void *)__entry->caller[4] + (unsigned long)_stext,
+                (void *)__entry->caller[5] + (unsigned long)_stext,
+                (void *)__entry->caller[6] + (unsigned long)_stext,
+                (void *)__entry->caller[7] + (unsigned long)_stext)
+);
+
 FTRACE_ENTRY(user_stack, userstack_entry,
 
        TRACE_USER_STACK,
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 497872df48f6..47e4ab549e81 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -1239,16 +1239,17 @@ static struct trace_event trace_wake_event = {
        .funcs          = &trace_wake_funcs,
 };
 
-/* TRACE_STACK */
-
-static enum print_line_t trace_stack_print(struct trace_iterator *iter,
-                                          int flags, struct trace_event *event)
+static enum print_line_t trace_kernel_stack_print(struct trace_iterator *iter,
+                                          int flags, struct trace_event 
*event, bool relative)
 {
        struct stack_entry *field;
        struct trace_seq *s = &iter->seq;
        unsigned long *p;
        unsigned long *end;
-       long delta = (unsigned long)_stext + iter->tr->text_delta;
+       long delta = iter->tr->text_delta;
+
+       if (relative)
+               delta += (unsigned long)_stext;
 
        trace_assign_type(field, iter->ent);
        end = (unsigned long *)((long)iter->ent + iter->ent_size);
@@ -1272,6 +1273,14 @@ static enum print_line_t trace_stack_print(struct 
trace_iterator *iter,
        return trace_handle_return(s);
 }
 
+/* TRACE_STACK */
+
+static enum print_line_t trace_stack_print(struct trace_iterator *iter,
+                                          int flags, struct trace_event *event)
+{
+       return trace_kernel_stack_print(iter, flags, event, false);
+}
+
 static struct trace_event_functions trace_stack_funcs = {
        .trace          = trace_stack_print,
 };
@@ -1281,6 +1290,23 @@ static struct trace_event trace_stack_event = {
        .funcs          = &trace_stack_funcs,
 };
 
+/* TRACE_REL_STACK */
+
+static enum print_line_t trace_rel_stack_print(struct trace_iterator *iter,
+                                          int flags, struct trace_event *event)
+{
+       return trace_kernel_stack_print(iter, flags, event, true);
+}
+
+static struct trace_event_functions trace_rel_stack_funcs = {
+       .trace          = trace_rel_stack_print,
+};
+
+static struct trace_event trace_rel_stack_event = {
+       .type           = TRACE_REL_STACK,
+       .funcs          = &trace_rel_stack_funcs,
+};
+
 /* TRACE_USER_STACK */
 static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
                                                int flags, struct trace_event 
*event)
@@ -1724,6 +1750,7 @@ static struct trace_event *events[] __initdata = {
        &trace_ctx_event,
        &trace_wake_event,
        &trace_stack_event,
+       &trace_rel_stack_event,
        &trace_user_stack_event,
        &trace_bputs_event,
        &trace_bprint_event,


Reply via email to