]>
Commit | Line | Data |
---|---|---|
548f1176 HD |
1 | /* |
2 | * Stack trace management functions | |
3 | * | |
4 | * Copyright (C) 2009 Helge Deller <deller@gmx.de> | |
5 | * based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com> | |
6 | * and parisc unwind functions by Randolph Chung <tausq@debian.org> | |
7 | * | |
8 | * TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT) | |
9 | */ | |
10 | #include <linux/module.h> | |
11 | #include <linux/stacktrace.h> | |
12 | ||
13 | #include <asm/unwind.h> | |
14 | ||
15 | static void dump_trace(struct task_struct *task, struct stack_trace *trace) | |
16 | { | |
17 | struct unwind_frame_info info; | |
18 | ||
19 | /* initialize unwind info */ | |
20 | if (task == current) { | |
21 | unsigned long sp; | |
22 | struct pt_regs r; | |
23 | HERE: | |
24 | asm volatile ("copy %%r30, %0" : "=r"(sp)); | |
25 | memset(&r, 0, sizeof(struct pt_regs)); | |
26 | r.iaoq[0] = (unsigned long)&&HERE; | |
27 | r.gr[2] = (unsigned long)__builtin_return_address(0); | |
28 | r.gr[30] = sp; | |
29 | unwind_frame_init(&info, task, &r); | |
30 | } else { | |
31 | unwind_frame_init_from_blocked_task(&info, task); | |
32 | } | |
33 | ||
34 | /* unwind stack and save entries in stack_trace struct */ | |
35 | trace->nr_entries = 0; | |
36 | while (trace->nr_entries < trace->max_entries) { | |
37 | if (unwind_once(&info) < 0 || info.ip == 0) | |
38 | break; | |
39 | ||
40 | if (__kernel_text_address(info.ip)) | |
41 | trace->entries[trace->nr_entries++] = info.ip; | |
42 | } | |
43 | } | |
44 | ||
45 | ||
46 | /* | |
47 | * Save stack-backtrace addresses into a stack_trace buffer. | |
48 | */ | |
49 | void save_stack_trace(struct stack_trace *trace) | |
50 | { | |
51 | dump_trace(current, trace); | |
52 | if (trace->nr_entries < trace->max_entries) | |
53 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
54 | } | |
55 | EXPORT_SYMBOL_GPL(save_stack_trace); | |
56 | ||
57 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |
58 | { | |
59 | dump_trace(tsk, trace); | |
60 | if (trace->nr_entries < trace->max_entries) | |
61 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
62 | } | |
63 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |