projects/linux·blob master · refs

161 lines · 3.5 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3* Generic interfaces for unwinding user space
4*/
5#include <linux/kernel.h>
6#include <linux/sched.h>
7#include <linux/sched/task_stack.h>
8#include <linux/unwind_user.h>
9#include <linux/uaccess.h>
10
11#define for_each_user_frame(state) \
12 for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
13
14static inline int
15get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
16{
17 unsigned long __user *addr = (void __user *)base + off;
18#ifdef CONFIG_COMPAT
19 if (ws == sizeof(int)) {
20 unsigned int data;
21 int ret = get_user(data, (unsigned int __user *)addr);
22 *word = data;
23 return ret;
24 }
25#endif
26 return get_user(*word, addr);
27}
28
29static int unwind_user_next_common(struct unwind_user_state *state,
30 const struct unwind_user_frame *frame)
31{
32 unsigned long cfa, fp, ra;
33
34 /* Get the Canonical Frame Address (CFA) */
35 if (frame->use_fp) {
36 if (state->fp < state->sp)
37 return -EINVAL;
38 cfa = state->fp;
39 } else {
40 cfa = state->sp;
41 }
42 cfa += frame->cfa_off;
43
44 /* Make sure that stack is not going in wrong direction */
45 if (cfa <= state->sp)
46 return -EINVAL;
47
48 /* Make sure that the address is word aligned */
49 if (cfa & (state->ws - 1))
50 return -EINVAL;
51
52 /* Get the Return Address (RA) */
53 if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
54 return -EINVAL;
55
56 /* Get the Frame Pointer (FP) */
57 if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
58 return -EINVAL;
59
60 state->ip = ra;
61 state->sp = cfa;
62 if (frame->fp_off)
63 state->fp = fp;
64 state->topmost = false;
65 return 0;
66}
67
68static int unwind_user_next_fp(struct unwind_user_state *state)
69{
70 struct pt_regs *regs = task_pt_regs(current);
71
72 if (state->topmost && unwind_user_at_function_start(regs)) {
73 const struct unwind_user_frame fp_entry_frame = {
74 ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws)
75 };
76 return unwind_user_next_common(state, &fp_entry_frame);
77 }
78
79 const struct unwind_user_frame fp_frame = {
80 ARCH_INIT_USER_FP_FRAME(state->ws)
81 };
82 return unwind_user_next_common(state, &fp_frame);
83}
84
85static int unwind_user_next(struct unwind_user_state *state)
86{
87 unsigned long iter_mask = state->available_types;
88 unsigned int bit;
89
90 if (state->done)
91 return -EINVAL;
92
93 for_each_set_bit(bit, &iter_mask, NR_UNWIND_USER_TYPE_BITS) {
94 enum unwind_user_type type = BIT(bit);
95
96 state->current_type = type;
97 switch (type) {
98 case UNWIND_USER_TYPE_FP:
99 if (!unwind_user_next_fp(state))
100 return 0;
101 continue;
102 default:
103 WARN_ONCE(1, "Undefined unwind bit %d", bit);
104 break;
105 }
106 break;
107 }
108
109 /* No successful unwind method. */
110 state->current_type = UNWIND_USER_TYPE_NONE;
111 state->done = true;
112 return -EINVAL;
113}
114
115static int unwind_user_start(struct unwind_user_state *state)
116{
117 struct pt_regs *regs = task_pt_regs(current);
118
119 memset(state, 0, sizeof(*state));
120
121 if ((current->flags & PF_KTHREAD) || !user_mode(regs)) {
122 state->done = true;
123 return -EINVAL;
124 }
125
126 if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP))
127 state->available_types |= UNWIND_USER_TYPE_FP;
128
129 state->ip = instruction_pointer(regs);
130 state->sp = user_stack_pointer(regs);
131 state->fp = frame_pointer(regs);
132 state->ws = unwind_user_word_size(regs);
133 if (!state->ws) {
134 state->done = true;
135 return -EINVAL;
136 }
137 state->topmost = true;
138
139 return 0;
140}
141
142int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries)
143{
144 struct unwind_user_state state;
145
146 trace->nr = 0;
147
148 if (!max_entries)
149 return -EINVAL;
150
151 if (current->flags & PF_KTHREAD)
152 return 0;
153
154 for_each_user_frame(&state) {
155 trace->entries[trace->nr++] = state.ip;
156 if (trace->nr >= max_entries)
157 break;
158 }
159
160 return 0;
161}