From 49fa913a61e7f2941bb59c11d72a1aafa6930162 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 20 Aug 2019 21:20:40 -0400 Subject: [PATCH] PR24904: support linux 5.2's stacktrace.c changes The following kernel commit disabled the older struct stack_trace APIs on architectures that support the newer stackwalk APIs. Provide an adaptation layer to stack_trace_save_regs(). commit 214d8ca6ee854f696f75e75511fe66b409e656db Author: Thomas Gleixner Date: Thu Apr 25 11:45:21 2019 +0200 stacktrace: Provide common infrastructure --- buildrun.cxx | 2 + .../linux/autoconf-stack-trace-save-regs.c | 8 ++++ runtime/stack.c | 37 +++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 runtime/linux/autoconf-stack-trace-save-regs.c diff --git a/buildrun.cxx b/buildrun.cxx index 5e8d3b961..6ed744707 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -485,6 +485,8 @@ compile_pass (systemtap_session& s) output_autoconf(s, o, "autoconf-bio-bi_opf.c", "STAPCONF_BIO_BI_OPF", NULL); output_autoconf(s, o, "autoconf-linux-sched_headers.c", "STAPCONF_LINUX_SCHED_HEADERS", NULL); + output_autoconf(s, o, "autoconf-stack-trace-save-regs.c", + "STAPCONF_STACK_TRACE_SAVE_REGS", NULL); // used by runtime/linux/netfilter.c output_exportconf(s, o, "nf_register_hook", "STAPCONF_NF_REGISTER_HOOK"); diff --git a/runtime/linux/autoconf-stack-trace-save-regs.c b/runtime/linux/autoconf-stack-trace-save-regs.c new file mode 100644 index 000000000..8bf33391f --- /dev/null +++ b/runtime/linux/autoconf-stack-trace-save-regs.c @@ -0,0 +1,8 @@ +#include + +unsigned int foo () +{ + unsigned long e[10]; + struct pt_regs* r = 0; + return stack_trace_save_regs (r, & e[0], 10, 0); +} diff --git a/runtime/stack.c b/runtime/stack.c index 0f649e8da..bf59b2909 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -39,6 +39,7 @@ #include "linux/uprobes-inc.h" #include + #if defined(STAPCONF_KERNEL_STACKTRACE) || defined(STAPCONF_KERNEL_STACKTRACE_NO_BP) #include #endif @@ -47,6 +48,20 @@ #include #endif +#if defined(STAPCONF_STACK_TRACE_SAVE_REGS) /* linux 5.2+ apprx. */ +static __typeof__(stack_trace_save_regs) (*stack_trace_save_regs_fn); /* not exported */ + +static int +_stp_init_stack(void) +{ + stack_trace_save_regs_fn = (void*) kallsyms_lookup_name("stack_trace_save_regs"); + dbug_unwind(1, "stack_trace_saves_regs_fn=%lx for _stp_stack_print_fallback().\n", + (unsigned long) save_trace_save_regs_fn); + return 0; +} + +#else /* ! STAPCONF_STACK_TRACE_SAVE_REGS */ + static void (*(save_stack_trace_regs_fn))(struct pt_regs *regs, struct stack_trace *trace); @@ -60,6 +75,10 @@ _stp_init_stack(void) return 0; } +#endif /* STAPCONF_STACK_TRACE_SAVE_REGS */ + + + static void _stp_stack_print_fallback(unsigned long, struct pt_regs*, int, int, int); #ifdef STP_USE_DWARF_UNWINDER @@ -168,9 +187,19 @@ static void _stp_stack_print_fallback(unsigned long sp, struct pt_regs *regs, int sym_flags, int levels, int skip) { unsigned long entries[MAXBACKTRACE]; - struct stack_trace trace; - int i; + unsigned i; + unsigned num_entries; + +#if defined(STAPCONF_STACK_TRACE_SAVE_REGS) /* linux 5.2+ apprx. */ + if (!stack_trace_save_regs_fn) { + dbug_unwind(1, "no fallback kernel stacktrace (giving up)\n"); + _stp_print_addr(0, sym_flags | _STP_SYM_INEXACT, NULL); + return; + } + num_entries = (*stack_trace_save_regs_fn)(regs, &entries[0], MAXBACKTRACE, skip); +#else + struct stack_trace trace; /* If don't have save_stack_trace_regs unwinder, just give up. */ if (!save_stack_trace_regs_fn) { dbug_unwind(1, "no fallback kernel stacktrace (giving up)\n"); @@ -189,9 +218,11 @@ static void _stp_stack_print_fallback(unsigned long sp, struct pt_regs *regs, dbug_unwind(1, "trace.nr_entries: %d\n", trace.nr_entries); dbug_unwind(1, "trace.max_entries: %d\n", trace.max_entries); dbug_unwind(1, "trace.skip %d\n", trace.skip); + num_entries = trace.nr_entries; +#endif /* save_stack_trace_reg() adds a ULONG_MAX after last valid entry. Ignore it. */ - for (i=0; i