.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
---|
3 | 4 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs |
---|
4 | 5 | * Copyright (C) 2009 Matt Fleming |
---|
5 | 6 | * Copyright (C) 2002 - 2012 Paul Mundt |
---|
6 | | - * |
---|
7 | | - * This file is subject to the terms and conditions of the GNU General Public |
---|
8 | | - * License. See the file "COPYING" in the main directory of this archive |
---|
9 | | - * for more details. |
---|
10 | 7 | */ |
---|
11 | 8 | #include <linux/kallsyms.h> |
---|
12 | 9 | #include <linux/ftrace.h> |
---|
.. | .. |
---|
19 | 16 | #include <asm/unwinder.h> |
---|
20 | 17 | #include <asm/stacktrace.h> |
---|
21 | 18 | |
---|
22 | | -void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
---|
| 19 | +void dump_mem(const char *str, const char *loglvl, unsigned long bottom, |
---|
| 20 | + unsigned long top) |
---|
23 | 21 | { |
---|
24 | 22 | unsigned long p; |
---|
25 | 23 | int i; |
---|
26 | 24 | |
---|
27 | | - printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); |
---|
| 25 | + printk("%s%s(0x%08lx to 0x%08lx)\n", loglvl, str, bottom, top); |
---|
28 | 26 | |
---|
29 | 27 | for (p = bottom & ~31; p < top; ) { |
---|
30 | | - printk("%04lx: ", p & 0xffff); |
---|
| 28 | + printk("%s%04lx: ", loglvl, p & 0xffff); |
---|
31 | 29 | |
---|
32 | 30 | for (i = 0; i < 8; i++, p += 4) { |
---|
33 | 31 | unsigned int val; |
---|
34 | 32 | |
---|
35 | 33 | if (p < bottom || p >= top) |
---|
36 | | - printk(" "); |
---|
| 34 | + pr_cont(" "); |
---|
37 | 35 | else { |
---|
38 | 36 | if (__get_user(val, (unsigned int __user *)p)) { |
---|
39 | | - printk("\n"); |
---|
| 37 | + pr_cont("\n"); |
---|
40 | 38 | return; |
---|
41 | 39 | } |
---|
42 | | - printk("%08x ", val); |
---|
| 40 | + pr_cont("%08x ", val); |
---|
43 | 41 | } |
---|
44 | 42 | } |
---|
45 | | - printk("\n"); |
---|
| 43 | + pr_cont("\n"); |
---|
46 | 44 | } |
---|
47 | 45 | } |
---|
48 | 46 | |
---|
49 | 47 | void printk_address(unsigned long address, int reliable) |
---|
50 | 48 | { |
---|
51 | | - printk(" [<%p>] %s%pS\n", (void *) address, |
---|
52 | | - reliable ? "" : "? ", (void *) address); |
---|
| 49 | + pr_cont(" [<%px>] %s%pS\n", (void *) address, |
---|
| 50 | + reliable ? "" : "? ", (void *) address); |
---|
53 | 51 | } |
---|
54 | 52 | |
---|
55 | 53 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
.. | .. |
---|
59 | 57 | struct thread_info *tinfo, int *graph) |
---|
60 | 58 | { |
---|
61 | 59 | struct task_struct *task = tinfo->task; |
---|
| 60 | + struct ftrace_ret_stack *ret_stack; |
---|
62 | 61 | unsigned long ret_addr; |
---|
63 | | - int index = task->curr_ret_stack; |
---|
64 | 62 | |
---|
65 | 63 | if (addr != (unsigned long)return_to_handler) |
---|
66 | 64 | return; |
---|
67 | 65 | |
---|
68 | | - if (!task->ret_stack || index < *graph) |
---|
| 66 | + if (!task->ret_stack) |
---|
69 | 67 | return; |
---|
70 | 68 | |
---|
71 | | - index -= *graph; |
---|
72 | | - ret_addr = task->ret_stack[index].ret; |
---|
| 69 | + ret_stack = ftrace_graph_get_ret_stack(task, *graph); |
---|
| 70 | + if (!ret_stack) |
---|
| 71 | + return; |
---|
| 72 | + |
---|
| 73 | + ret_addr = ret_stack->ret; |
---|
73 | 74 | |
---|
74 | 75 | ops->address(data, ret_addr, 1); |
---|
75 | 76 | |
---|
.. | .. |
---|
106 | 107 | } |
---|
107 | 108 | } |
---|
108 | 109 | |
---|
109 | | -static int print_trace_stack(void *data, char *name) |
---|
110 | | -{ |
---|
111 | | - printk("%s <%s> ", (char *)data, name); |
---|
112 | | - return 0; |
---|
113 | | -} |
---|
114 | | - |
---|
115 | 110 | /* |
---|
116 | 111 | * Print one address/symbol entries per line. |
---|
117 | 112 | */ |
---|
.. | .. |
---|
122 | 117 | } |
---|
123 | 118 | |
---|
124 | 119 | static const struct stacktrace_ops print_trace_ops = { |
---|
125 | | - .stack = print_trace_stack, |
---|
126 | 120 | .address = print_trace_address, |
---|
127 | 121 | }; |
---|
128 | 122 | |
---|
129 | 123 | void show_trace(struct task_struct *tsk, unsigned long *sp, |
---|
130 | | - struct pt_regs *regs) |
---|
| 124 | + struct pt_regs *regs, const char *loglvl) |
---|
131 | 125 | { |
---|
132 | 126 | if (regs && user_mode(regs)) |
---|
133 | 127 | return; |
---|
134 | 128 | |
---|
135 | | - printk("\nCall trace:\n"); |
---|
| 129 | + printk("%s\nCall trace:\n", loglvl); |
---|
136 | 130 | |
---|
137 | | - unwind_stack(tsk, regs, sp, &print_trace_ops, ""); |
---|
| 131 | + unwind_stack(tsk, regs, sp, &print_trace_ops, (void *)loglvl); |
---|
138 | 132 | |
---|
139 | | - printk("\n"); |
---|
| 133 | + pr_cont("\n"); |
---|
140 | 134 | |
---|
141 | 135 | if (!tsk) |
---|
142 | 136 | tsk = current; |
---|
.. | .. |
---|
144 | 138 | debug_show_held_locks(tsk); |
---|
145 | 139 | } |
---|
146 | 140 | |
---|
147 | | -void show_stack(struct task_struct *tsk, unsigned long *sp) |
---|
| 141 | +void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl) |
---|
148 | 142 | { |
---|
149 | 143 | unsigned long stack; |
---|
150 | 144 | |
---|
.. | .. |
---|
156 | 150 | sp = (unsigned long *)tsk->thread.sp; |
---|
157 | 151 | |
---|
158 | 152 | stack = (unsigned long)sp; |
---|
159 | | - dump_mem("Stack: ", stack, THREAD_SIZE + |
---|
| 153 | + dump_mem("Stack: ", loglvl, stack, THREAD_SIZE + |
---|
160 | 154 | (unsigned long)task_stack_page(tsk)); |
---|
161 | | - show_trace(tsk, sp, NULL); |
---|
| 155 | + show_trace(tsk, sp, NULL, loglvl); |
---|
162 | 156 | } |
---|