summaryrefslogtreecommitdiffstats
path: root/runtime/stack.c
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2009-02-02 15:58:53 +0100
committerTim Moore <timoore@redhat.com>2009-02-11 18:20:20 +0100
commitbbc46bf643491173b9086907cf0820b3fd2c1fe3 (patch)
tree9b74716911ed9deb015b1f12c4e2f31ed90a8339 /runtime/stack.c
parent89dd03e34c2f890e9fbb065c74a60036aa480827 (diff)
downloadsystemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.tar.gz
systemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.tar.xz
systemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.zip
Use kernel stack backtrace support when available
Define new functions that use the kernel support to do a backtrace of other tasks than current.
Diffstat (limited to 'runtime/stack.c')
-rw-r--r--runtime/stack.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/runtime/stack.c b/runtime/stack.c
index 7ca0e316..25d0817d 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -27,6 +27,11 @@
#define MAXBACKTRACE 20
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+
+static void _stp_stack_print_fallback(unsigned long, int, int);
+
#if defined (__x86_64__)
#include "stack-x86_64.c"
#elif defined (__ia64__)
@@ -43,6 +48,53 @@
#error "Unsupported architecture"
#endif
+#ifdef CONFIG_STACKTRACE
+
+struct print_stack_data
+{
+ int verbose;
+ int max_level;
+ int level;
+};
+
+static void print_stack_warning(void *data, char *msg)
+{
+}
+
+static void
+print_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+}
+
+static int print_stack_stack(void *data, char *name)
+{
+ return -1;
+}
+
+static void print_stack_address(void *data, unsigned long addr, int reliable)
+{
+ struct print_stack_data *sdata = data;
+ if (sdata->level++ < sdata->max_level)
+ _stp_func_print(addr,sdata->verbose, 0);
+}
+
+static const struct stacktrace_ops print_stack_ops = {
+ .warning = print_stack_warning,
+ .warning_symbol = print_stack_warning_symbol,
+ .stack = print_stack_stack,
+ .address = print_stack_address,
+};
+
+static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels)
+{
+ struct print_stack_data print_data;
+ print_data.verbose = verbose;
+ print_data.max_level = levels;
+ print_data.level = 0;
+ dump_trace(current, NULL, (long *)stack, 0, &print_stack_ops,
+ &print_data);
+}
+#endif
/** Prints the stack backtrace
* @param regs A pointer to the struct pt_regs.
*/
@@ -103,4 +155,39 @@ static void _stp_ustack_print(char *str)
#endif /* 0 */
/** @} */
+
+void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
+{
+#ifdef CONFIG_STACKTRACE
+ int i;
+ unsigned long backtrace[MAXBACKTRACE];
+ struct stack_trace trace;
+ int maxLevels = min(levels, MAXBACKTRACE);
+ memset(&trace, 0, sizeof(trace));
+ trace.entries = &backtrace[0];
+ trace.max_entries = maxLevels;
+ trace.skip = 0;
+ save_stack_trace_tsk(tsk, &trace);
+ for (i = 0; i < maxLevels; ++i) {
+ if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
+ break;
+ _stp_printf("%lx ", backtrace[i]);
+ }
+#endif
+}
+
+/** Writes a task stack backtrace to a string
+ *
+ * @param str string
+ * @param tsk A pointer to the task_struct
+ * @returns void
+ */
+void _stp_stack_snprint_tsk(char *str, int size, struct task_struct *tsk, int verbose, int levels)
+{
+ _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
+ _stp_print_flush();
+ _stp_stack_print_tsk(tsk, verbose, levels);
+ strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
+ pb->len = 0;
+}
#endif /* _STACK_C_ */