gator: support kernel backtrace in kernel module
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 1 Dec 2020 08:09:29 +0000 (17:09 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 2 Dec 2020 04:43:05 +0000 (13:43 +0900)
From Linux 4.9, walk_stackframe was unexported so it is not
possible to build gator as kernel module. Use save_stack_trace
instead for kernel backtrace as like higher gator version.

Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
drivers/gator/gator_backtrace.c

index 057318354d8edc72a8b906edd04093f61473d836..0bc5ef77d992d10391abb0dfa54ad38835b96f7e 100644 (file)
@@ -7,6 +7,17 @@
  *
  */
 
+/* on 4.9 walk_stackframe was unexported so use save_stack_trace instead */
+#if defined(MODULE) && defined(__aarch64__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
+#define GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME  0
+#else
+#define GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME  1
+#endif
+
+#if (!GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME) && !defined(CONFIG_STACKTRACE)
+#error "CONFIG_STACKTRACE is required for kernel unwinding"
+#endif
+
 /*
  * EABI backtrace stores {fp,lr} on the stack.
  */
@@ -120,7 +131,15 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
 #if defined(__arm__) || defined(__aarch64__)
 
 #include <asm/stacktrace.h>
+#if !GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME
+#include <linux/stacktrace.h>
+#endif
+
+#endif /* defined(__arm__) || defined(__aarch64__) */
+
+#if GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME
 
+#if defined(__arm__) || defined(__aarch64__)
 static int report_trace(struct stackframe *frame, void *d)
 {
        unsigned int *depth = d, cookie = NO_COOKIE;
@@ -147,7 +166,6 @@ static int report_trace(struct stackframe *frame, void *d)
 
        return *depth == 0;
 }
-#endif
 
 /* Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile */
 /* #define GATOR_KERNEL_STACK_UNWINDING */
@@ -193,6 +211,74 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
 #endif
 }
 
+#else /* GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME */
+
+/* -------------------------- KERNEL UNWINDING USING save_stack_trace_regs -------------------------- */
+
+#define GATOR_KMOD_STACK_MAX_SIZE 32
+struct gator_kmod_stack { unsigned long addresses[GATOR_KMOD_STACK_MAX_SIZE]; };
+static DEFINE_PER_CPU(struct gator_kmod_stack, gator_kmod_stack);
+
+static void report_trace(unsigned int cpu, struct stack_trace * trace)
+{
+    unsigned int cookie = NO_COOKIE;
+    unsigned int index;
+
+    for (index = 0; index < trace->nr_entries; ++index) {
+        unsigned long addr = trace->entries[index];
+#if defined(MODULE)
+        struct module * mod = __module_address(addr);
+        if (mod) {
+            cookie = get_cookie(cpu, current, mod->name, false);
+            addr = addr -
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
+              (unsigned long) mod->module_core;
+#else
+              (unsigned long) mod->core_layout.base;
+#endif
+        }
+        else {
+            cookie = NO_COOKIE;
+        }
+#endif
+        marshal_backtrace(addr & ~1, cookie, 1);
+    }
+}
+
+static void kernel_backtrace(int cpu, struct pt_regs *const regs)
+{
+    struct stack_trace trace;
+    trace.skip = 0;
+    trace.nr_entries = 0;
+    trace.entries = per_cpu(gator_kmod_stack, cpu).addresses;
+#ifdef GATOR_KERNEL_STACK_UNWINDING
+    trace.max_entries = gator_backtrace_depth;
+#else
+    trace.max_entries = (kernel_stack_unwinding ? gator_backtrace_depth : 1);
+#endif
+    if (trace.max_entries < 1) {
+        trace.max_entries = 1;
+    }
+    else if (trace.max_entries > GATOR_KMOD_STACK_MAX_SIZE) {
+        trace.max_entries = GATOR_KMOD_STACK_MAX_SIZE;
+    }
+
+    save_stack_trace(&trace);
+
+    report_trace(cpu, &trace);
+}
+
+#endif /* GATOR_KERNEL_UNWINDING_USE_WALK_STACKFRAME */
+
+#else /* defined(__arm__) || defined(__aarch64__) */
+
+static void kernel_backtrace(int cpu, struct pt_regs *const regs)
+{
+    marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1);
+}
+
+#endif /* defined(__arm__) || defined(__aarch64__) */
+
 static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
 {
        bool in_kernel;