| .. | .. |
|---|
| 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 | } |
|---|