aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/dumpstack.c34
-rw-r--r--arch/x86/kernel/dumpstack.h2
-rw-r--r--arch/x86/kernel/dumpstack_32.c5
-rw-r--r--arch/x86/kernel/dumpstack_64.c7
4 files changed, 42 insertions, 6 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 5962176dfabb..6b1f6f6f8661 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -30,6 +30,37 @@ void printk_address(unsigned long address, int reliable)
30 reliable ? "" : "? ", (void *) address); 30 reliable ? "" : "? ", (void *) address);
31} 31}
32 32
33#ifdef CONFIG_FUNCTION_GRAPH_TRACER
34static void
35print_ftrace_graph_addr(unsigned long addr, void *data,
36 const struct stacktrace_ops *ops,
37 struct thread_info *tinfo, int *graph)
38{
39 struct task_struct *task = tinfo->task;
40 unsigned long ret_addr;
41 int index = task->curr_ret_stack;
42
43 if (addr != (unsigned long)return_to_handler)
44 return;
45
46 if (!task->ret_stack || index < *graph)
47 return;
48
49 index -= *graph;
50 ret_addr = task->ret_stack[index].ret;
51
52 ops->address(data, ret_addr, 1);
53
54 (*graph)++;
55}
56#else
57static inline void
58print_ftrace_graph_addr(unsigned long addr, void *data,
59 const struct stacktrace_ops *ops,
60 struct thread_info *tinfo, int *graph)
61{ }
62#endif
63
33/* 64/*
34 * x86-64 can have up to three kernel stacks: 65 * x86-64 can have up to three kernel stacks:
35 * process stack 66 * process stack
@@ -54,7 +85,7 @@ unsigned long
54print_context_stack(struct thread_info *tinfo, 85print_context_stack(struct thread_info *tinfo,
55 unsigned long *stack, unsigned long bp, 86 unsigned long *stack, unsigned long bp,
56 const struct stacktrace_ops *ops, void *data, 87 const struct stacktrace_ops *ops, void *data,
57 unsigned long *end) 88 unsigned long *end, int *graph)
58{ 89{
59 struct stack_frame *frame = (struct stack_frame *)bp; 90 struct stack_frame *frame = (struct stack_frame *)bp;
60 91
@@ -70,6 +101,7 @@ print_context_stack(struct thread_info *tinfo,
70 } else { 101 } else {
71 ops->address(data, addr, bp == 0); 102 ops->address(data, addr, bp == 0);
72 } 103 }
104 print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
73 } 105 }
74 stack++; 106 stack++;
75 } 107 }
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h
index 3119a801c32b..da87590b8698 100644
--- a/arch/x86/kernel/dumpstack.h
+++ b/arch/x86/kernel/dumpstack.h
@@ -18,7 +18,7 @@ extern unsigned long
18print_context_stack(struct thread_info *tinfo, 18print_context_stack(struct thread_info *tinfo,
19 unsigned long *stack, unsigned long bp, 19 unsigned long *stack, unsigned long bp,
20 const struct stacktrace_ops *ops, void *data, 20 const struct stacktrace_ops *ops, void *data,
21 unsigned long *end); 21 unsigned long *end, int *graph);
22 22
23extern void 23extern void
24show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, 24show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 7b031b106ec8..d593cd1f58dc 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -23,6 +23,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
23 unsigned long *stack, unsigned long bp, 23 unsigned long *stack, unsigned long bp,
24 const struct stacktrace_ops *ops, void *data) 24 const struct stacktrace_ops *ops, void *data)
25{ 25{
26 int graph = 0;
27
26 if (!task) 28 if (!task)
27 task = current; 29 task = current;
28 30
@@ -50,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
50 52
51 context = (struct thread_info *) 53 context = (struct thread_info *)
52 ((unsigned long)stack & (~(THREAD_SIZE - 1))); 54 ((unsigned long)stack & (~(THREAD_SIZE - 1)));
53 bp = print_context_stack(context, stack, bp, ops, data, NULL); 55 bp = print_context_stack(context, stack, bp, ops,
56 data, NULL, &graph);
54 57
55 stack = (unsigned long *)context->previous_esp; 58 stack = (unsigned long *)context->previous_esp;
56 if (!stack) 59 if (!stack)
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 33ff10287a5d..c302d0707048 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -109,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
109 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; 109 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
110 unsigned used = 0; 110 unsigned used = 0;
111 struct thread_info *tinfo; 111 struct thread_info *tinfo;
112 int graph = 0;
112 113
113 if (!task) 114 if (!task)
114 task = current; 115 task = current;
@@ -149,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
149 break; 150 break;
150 151
151 bp = print_context_stack(tinfo, stack, bp, ops, 152 bp = print_context_stack(tinfo, stack, bp, ops,
152 data, estack_end); 153 data, estack_end, &graph);
153 ops->stack(data, "<EOE>"); 154 ops->stack(data, "<EOE>");
154 /* 155 /*
155 * We link to the next stack via the 156 * We link to the next stack via the
@@ -168,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
168 if (ops->stack(data, "IRQ") < 0) 169 if (ops->stack(data, "IRQ") < 0)
169 break; 170 break;
170 bp = print_context_stack(tinfo, stack, bp, 171 bp = print_context_stack(tinfo, stack, bp,
171 ops, data, irqstack_end); 172 ops, data, irqstack_end, &graph);
172 /* 173 /*
173 * We link to the next stack (which would be 174 * We link to the next stack (which would be
174 * the process stack normally) the last 175 * the process stack normally) the last
@@ -186,7 +187,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
186 /* 187 /*
187 * This handles the process stack: 188 * This handles the process stack:
188 */ 189 */
189 bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); 190 bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph);
190 put_cpu(); 191 put_cpu();
191} 192}
192EXPORT_SYMBOL(dump_trace); 193EXPORT_SYMBOL(dump_trace);