Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/kernel/dumpstack.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 1991, 1992 Linus Torvalds
4
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
5
* Copyright (C) 2009 Matt Fleming
6
* Copyright (C) 2002 - 2012 Paul Mundt
7
*/
8
#include <linux/kallsyms.h>
9
#include <linux/ftrace.h>
10
#include <linux/debug_locks.h>
11
#include <linux/sched/debug.h>
12
#include <linux/sched/task_stack.h>
13
#include <linux/kdebug.h>
14
#include <linux/export.h>
15
#include <linux/uaccess.h>
16
#include <asm/unwinder.h>
17
#include <asm/stacktrace.h>
18
19
void dump_mem(const char *str, const char *loglvl, unsigned long bottom,
20
unsigned long top)
21
{
22
unsigned long p;
23
int i;
24
25
printk("%s%s(0x%08lx to 0x%08lx)\n", loglvl, str, bottom, top);
26
27
for (p = bottom & ~31; p < top; ) {
28
printk("%s%04lx: ", loglvl, p & 0xffff);
29
30
for (i = 0; i < 8; i++, p += 4) {
31
unsigned int val;
32
33
if (p < bottom || p >= top)
34
pr_cont(" ");
35
else {
36
if (__get_user(val, (unsigned int __user *)p)) {
37
pr_cont("\n");
38
return;
39
}
40
pr_cont("%08x ", val);
41
}
42
}
43
pr_cont("\n");
44
}
45
}
46
47
void printk_address(unsigned long address, int reliable)
48
{
49
pr_cont(" [<%px>] %s%pS\n", (void *) address,
50
reliable ? "" : "? ", (void *) address);
51
}
52
53
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
54
static void
55
print_ftrace_graph_addr(unsigned long addr, void *data,
56
const struct stacktrace_ops *ops,
57
struct thread_info *tinfo, int *graph)
58
{
59
struct task_struct *task = tinfo->task;
60
struct ftrace_ret_stack *ret_stack;
61
unsigned long ret_addr;
62
63
if (addr != (unsigned long)return_to_handler)
64
return;
65
66
if (!task->ret_stack)
67
return;
68
69
ret_stack = ftrace_graph_get_ret_stack(task, *graph);
70
if (!ret_stack)
71
return;
72
73
ret_addr = ret_stack->ret;
74
75
ops->address(data, ret_addr, 1);
76
77
(*graph)++;
78
}
79
#else
80
static inline void
81
print_ftrace_graph_addr(unsigned long addr, void *data,
82
const struct stacktrace_ops *ops,
83
struct thread_info *tinfo, int *graph)
84
{ }
85
#endif
86
87
void
88
stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
89
unsigned long *sp, const struct stacktrace_ops *ops,
90
void *data)
91
{
92
struct thread_info *context;
93
int graph = 0;
94
95
context = (struct thread_info *)
96
((unsigned long)sp & (~(THREAD_SIZE - 1)));
97
98
while (!kstack_end(sp)) {
99
unsigned long addr = *sp++;
100
101
if (__kernel_text_address(addr)) {
102
ops->address(data, addr, 1);
103
104
print_ftrace_graph_addr(addr, data, ops,
105
context, &graph);
106
}
107
}
108
}
109
110
/*
111
* Print one address/symbol entries per line.
112
*/
113
static void print_trace_address(void *data, unsigned long addr, int reliable)
114
{
115
printk("%s", (char *)data);
116
printk_address(addr, reliable);
117
}
118
119
static const struct stacktrace_ops print_trace_ops = {
120
.address = print_trace_address,
121
};
122
123
void show_trace(struct task_struct *tsk, unsigned long *sp,
124
struct pt_regs *regs, const char *loglvl)
125
{
126
if (regs && user_mode(regs))
127
return;
128
129
printk("%s\nCall trace:\n", loglvl);
130
131
unwind_stack(tsk, regs, sp, &print_trace_ops, (void *)loglvl);
132
133
pr_cont("\n");
134
135
if (!tsk)
136
tsk = current;
137
138
debug_show_held_locks(tsk);
139
}
140
141
void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
142
{
143
unsigned long stack;
144
145
if (!tsk)
146
tsk = current;
147
if (tsk == current)
148
sp = (unsigned long *)current_stack_pointer;
149
else
150
sp = (unsigned long *)tsk->thread.sp;
151
152
stack = (unsigned long)sp;
153
dump_mem("Stack: ", loglvl, stack, THREAD_SIZE +
154
(unsigned long)task_stack_page(tsk));
155
show_trace(tsk, sp, NULL, loglvl);
156
}
157
158