Blob Blame History Raw
From 49fa913a61e7f2941bb59c11d72a1aafa6930162 Mon Sep 17 00:00:00 2001
From: "Frank Ch. Eigler" <fche@redhat.com>
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 <tglx@linutronix.de>
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 <linux/stacktrace.h>
+
+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 <linux/stacktrace.h>
+
 #if defined(STAPCONF_KERNEL_STACKTRACE) || defined(STAPCONF_KERNEL_STACKTRACE_NO_BP)
 #include <asm/stacktrace.h>
 #endif
@@ -47,6 +48,20 @@
 #include <asm/unwind.h>
 #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<MAXBACKTRACE && i<trace.nr_entries && entries[i]!=ULONG_MAX; ++i) {
+	for (i=0; i<MAXBACKTRACE && i<num_entries && entries[i]!=ULONG_MAX; ++i) {
 		/* When we have frame pointers, the unwind addresses can be
 		   (mostly) trusted, otherwise it is all guesswork.  */
 #ifdef CONFIG_FRAME_POINTER
-- 
2.21.0