summaryrefslogtreecommitdiffstats
path: root/runtime/stack.c
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2009-02-20 14:56:38 +0100
committerMark Wielaard <mjw@redhat.com>2009-02-20 14:56:38 +0100
commit02615365a92ca2570c1f96abc8a97674aa2ccae1 (patch)
treeebedfd91a0f6d299b39e84295e091e12c0767dc8 /runtime/stack.c
parentc3bad3042df505a3470f1e20b09822a9df1d4761 (diff)
parentadc67597f327cd43d58b1d0cb740dab14a75a058 (diff)
downloadsystemtap-steved-02615365a92ca2570c1f96abc8a97674aa2ccae1.tar.gz
systemtap-steved-02615365a92ca2570c1f96abc8a97674aa2ccae1.tar.xz
systemtap-steved-02615365a92ca2570c1f96abc8a97674aa2ccae1.zip
Merge branch 'master' into pr6866
Conflicts: ChangeLog: Removed runtime/ChangeLog: Removed runtime/sym.c: Merged runtime/task_finder.c: Merged tapset/ChangeLog: Removed testsuite/ChangeLog: Removed
Diffstat (limited to 'runtime/stack.c')
-rw-r--r--runtime/stack.c96
1 files changed, 93 insertions, 3 deletions
diff --git a/runtime/stack.c b/runtime/stack.c
index 23ac2edc..aa0e6d65 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -27,6 +27,14 @@
#define MAXBACKTRACE 20
+#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+// XXX: PR9866: hacky temporarily restriction to recent kernels
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+#endif
+
+static void _stp_stack_print_fallback(unsigned long, int, int);
+
#if defined (__x86_64__)
#include "stack-x86_64.c"
#elif defined (__ia64__)
@@ -43,11 +51,58 @@
#error "Unsupported architecture"
#endif
+#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+
+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.
*/
-void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
{
if (verbose) {
/* print the current address */
@@ -75,7 +130,7 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan
* @param regs A pointer to the struct pt_regs.
* @returns void
*/
-void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
{
/* To get a string, we use a simple trick. First flush the print buffer, */
/* then call _stp_stack_print, then copy the result into the output string */
@@ -93,7 +148,7 @@ void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose,
* @note Currently limited to a depth of two. Works from jprobes and kprobes.
*/
#if 0
-void _stp_ustack_print(char *str)
+static void _stp_ustack_print(char *str)
{
struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
_stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
@@ -103,4 +158,39 @@ void _stp_ustack_print(char *str)
#endif /* 0 */
/** @} */
+
+void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
+{
+#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+ 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_ */