Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/openrisc/kernel/unwinder.c
26444 views
1
/*
2
* OpenRISC unwinder.c
3
*
4
* Reusable arch specific api for unwinding stacks.
5
*
6
* Copyright (C) 2017 Stafford Horne <[email protected]>
7
*
8
* This file is licensed under the terms of the GNU General Public License
9
* version 2. This program is licensed "as is" without any warranty of any
10
* kind, whether express or implied.
11
*/
12
13
#include <linux/sched/task_stack.h>
14
#include <linux/kernel.h>
15
16
#include <asm/unwinder.h>
17
18
#ifdef CONFIG_FRAME_POINTER
19
struct or1k_frameinfo {
20
unsigned long *fp;
21
unsigned long ra;
22
unsigned long top;
23
};
24
25
/*
26
* Verify a frameinfo structure. The return address should be a valid text
27
* address. The frame pointer may be null if its the last frame, otherwise
28
* the frame pointer should point to a location in the stack after the
29
* top of the next frame up.
30
*/
31
static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
32
{
33
return (frameinfo->fp == NULL ||
34
(!kstack_end(frameinfo->fp) &&
35
frameinfo->fp > &frameinfo->top)) &&
36
__kernel_text_address(frameinfo->ra);
37
}
38
39
/*
40
* Create a stack trace doing scanning which is frame pointer aware. We can
41
* get reliable stack traces by matching the previously found frame
42
* pointer with the top of the stack address every time we find a valid
43
* or1k_frameinfo.
44
*
45
* Ideally the stack parameter will be passed as FP, but it can not be
46
* guaranteed. Therefore we scan each address looking for the first sign
47
* of a return address.
48
*
49
* The OpenRISC stack frame looks something like the following. The
50
* location SP is held in r1 and location FP is held in r2 when frame pointers
51
* enabled.
52
*
53
* SP -> (top of stack)
54
* - (callee saved registers)
55
* - (local variables)
56
* FP-8 -> previous FP \
57
* FP-4 -> return address |- or1k_frameinfo
58
* FP -> (previous top of stack) /
59
*/
60
void unwind_stack(void *data, unsigned long *stack,
61
void (*trace)(void *data, unsigned long addr, int reliable))
62
{
63
unsigned long *next_fp = NULL;
64
struct or1k_frameinfo *frameinfo = NULL;
65
int reliable = 0;
66
67
while (!kstack_end(stack)) {
68
frameinfo = container_of(stack,
69
struct or1k_frameinfo,
70
top);
71
72
if (__kernel_text_address(frameinfo->ra)) {
73
if (or1k_frameinfo_valid(frameinfo) &&
74
(next_fp == NULL ||
75
next_fp == &frameinfo->top)) {
76
reliable = 1;
77
next_fp = frameinfo->fp;
78
} else
79
reliable = 0;
80
81
trace(data, frameinfo->ra, reliable);
82
}
83
stack++;
84
}
85
}
86
87
#else /* CONFIG_FRAME_POINTER */
88
89
/*
90
* Create a stack trace by doing a simple scan treating all text addresses
91
* as return addresses.
92
*/
93
void unwind_stack(void *data, unsigned long *stack,
94
void (*trace)(void *data, unsigned long addr, int reliable))
95
{
96
unsigned long addr;
97
98
while (!kstack_end(stack)) {
99
addr = *stack++;
100
if (__kernel_text_address(addr))
101
trace(data, addr, 0);
102
}
103
}
104
#endif /* CONFIG_FRAME_POINTER */
105
106
107