]>
Commit | Line | Data |
---|---|---|
5a24160a WC |
1 | /* Dwarfless register access for arm */ |
2 | ||
029130b7 DS |
3 | %{ |
4 | // These functions are largely lifted from arch/arm/kernel/ptrace.c. | |
5 | ||
6 | static inline unsigned long _stp_kernel_stack_pointer(struct pt_regs *regs) | |
7 | { | |
8 | return regs->ARM_sp; | |
9 | } | |
10 | ||
11 | /* | |
12 | * _stp_regs_within_kernel_stack() - check the address in the stack | |
13 | * @regs: pt_regs which contains kernel stack pointer. | |
14 | * @addr: address which is checked. | |
15 | * | |
16 | * _stp_regs_within_kernel_stack() checks @addr is within the kernel | |
17 | * stack page(s). If @addr is within the kernel stack, it returns | |
18 | * true. If not, returns false. | |
19 | */ | |
20 | bool _stp_regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | |
21 | { | |
22 | return ((addr & ~(THREAD_SIZE - 1)) == | |
23 | (_stp_kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); | |
24 | } | |
25 | ||
26 | /* | |
27 | * _stp_regs_get_kernel_stack_nth_addr() - get address of the Nth entry of the stack | |
28 | * @regs: pt_regs which contains kernel stack pointer. | |
29 | * @n: stack entry number. | |
30 | * | |
31 | * _stp_regs_get_kernel_stack_nth_addr() returns the address of the @n | |
32 | * th entry of the kernel stack which is specified by @regs. If the @n | |
33 | * th entry is NOT in the kernel stack, this returns 0. | |
34 | */ | |
35 | long * | |
36 | _stp_regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n) | |
37 | { | |
38 | long *addr = (unsigned long *)_stp_kernel_stack_pointer(regs); | |
39 | addr += n; | |
40 | if (_stp_regs_within_kernel_stack(regs, (unsigned long)addr)) | |
41 | return addr; | |
42 | else | |
43 | return 0; | |
44 | } | |
45 | %} | |
46 | ||
6ae3ec1c | 47 | global _reg_offsets[30] |
5a24160a | 48 | |
6ae3ec1c | 49 | probe init { |
5a24160a WC |
50 | |
51 | /* Same order as pt_regs */ | |
52 | _reg_offsets["r0"] = 0 _reg_offsets["a1"] = 0 | |
53 | _reg_offsets["r1"] = 4 _reg_offsets["a2"] = 4 | |
54 | _reg_offsets["r2"] = 8 _reg_offsets["a3"] = 8 | |
55 | _reg_offsets["r3"] = 12 _reg_offsets["a4"] = 12 | |
56 | _reg_offsets["r4"] = 16 _reg_offsets["v1"] = 16 | |
57 | _reg_offsets["r5"] = 20 _reg_offsets["v2"] = 20 | |
58 | _reg_offsets["r6"] = 24 _reg_offsets["v3"] = 24 | |
59 | _reg_offsets["r7"] = 28 _reg_offsets["v4"] = 28 | |
60 | _reg_offsets["r8"] = 32 _reg_offsets["v5"] = 32 | |
61 | _reg_offsets["r9"] = 36 _reg_offsets["v6"] = 36 | |
62 | _reg_offsets["r10"] = 40 _reg_offsets["v7"] = 40 | |
63 | _reg_offsets["fp"] = 44 _reg_offsets["v8"] = 44 | |
64 | _reg_offsets["ip"] = 48 | |
65 | _reg_offsets["sp"] = 52 | |
66 | _reg_offsets["lr"] = 56 | |
67 | _reg_offsets["pc"] = 60 | |
68 | _reg_offsets["cpsr"] = 64 | |
69 | _reg_offsets["orig_r0"] = 68 | |
5a24160a WC |
70 | } |
71 | ||
72 | function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ | |
73 | long value; | |
d9aed31e | 74 | struct pt_regs *regs; |
e04b5d74 | 75 | if (CONTEXT->user_mode_p) { |
d9aed31e | 76 | regs = CONTEXT->uregs; |
6c40239d MW |
77 | } else { |
78 | regs = CONTEXT->kregs; | |
d9aed31e MW |
79 | } |
80 | if (!regs) { | |
5a24160a WC |
81 | CONTEXT->last_error = "No registers available in this context"; |
82 | return; | |
83 | } | |
b7b482fb | 84 | if (STAP_ARG_offset < 0 || STAP_ARG_offset > sizeof(struct pt_regs) - sizeof(long)) { |
5a24160a | 85 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), |
b7b482fb | 86 | "Bad register offset: %lld", STAP_ARG_offset); |
5a24160a WC |
87 | CONTEXT->last_error = CONTEXT->error_buffer; |
88 | return; | |
89 | } | |
b7b482fb SM |
90 | memcpy(&value, ((char *)regs) + STAP_ARG_offset, sizeof(value)); |
91 | STAP_RETVALUE = value; | |
5a24160a WC |
92 | %} |
93 | ||
92c25572 MW |
94 | function _stp_probing_kernel:long () { |
95 | return !user_mode(); | |
96 | } | |
5a24160a | 97 | |
93f70a9a FL |
98 | function arch_bytes:long() %{ /* pure */ |
99 | STAP_RETVALUE = sizeof(long); | |
100 | %} | |
101 | ||
102 | function uarch_bytes:long() { | |
103 | if (!user_mode()) { | |
104 | error("requires user mode") | |
105 | return 0 | |
106 | } else | |
107 | return 4 | |
108 | } | |
109 | ||
5a24160a WC |
110 | /* Return the named register value as a signed value. */ |
111 | function register:long (name:string) { | |
112 | if (!registers_valid()) { | |
113 | error("cannot access CPU registers in this context") | |
114 | return 0 | |
115 | } | |
5a24160a WC |
116 | offset = _reg_offsets[name] |
117 | if (offset == 0 && !(name in _reg_offsets)) { | |
118 | error("Unknown register: " . name) | |
119 | return 0 | |
120 | } | |
121 | return _stp_get_register_by_offset(offset) | |
122 | } | |
123 | ||
124 | /* | |
125 | * Return the named register value as an unsigned value. Specifically, | |
126 | * don't sign-extend the register value when promoting it to 64 bits. | |
127 | */ | |
128 | function u_register:long (name:string) { | |
129 | return register(name) & 0xffffffff; | |
130 | } | |
131 | ||
029130b7 DS |
132 | function _stp_get_stack_nth:long (n:long) |
133 | %{ /* pure */ | |
134 | unsigned int n = (unsigned int)STAP_ARG_n; | |
135 | struct pt_regs *regs; | |
136 | long *addr; | |
137 | ||
138 | STAP_RETVALUE = 0; | |
139 | if (CONTEXT->user_mode_p) { | |
140 | // This function only handles kernel arguments off the stack. | |
141 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
142 | "cannot access function args in this context"); | |
143 | CONTEXT->last_error = CONTEXT->error_buffer; | |
144 | return; | |
145 | } | |
146 | regs = CONTEXT->kregs; | |
147 | if (!regs) { | |
148 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
149 | "cannot access function args in this context"); | |
150 | CONTEXT->last_error = CONTEXT->error_buffer; | |
151 | return; | |
152 | } | |
153 | ||
154 | /* Get the address of the nth item on the stack. */ | |
155 | addr = _stp_regs_get_kernel_stack_nth_addr(regs, n); | |
156 | if (addr == NULL) { | |
157 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
158 | "cannot access stack arg(%d)", n); | |
159 | CONTEXT->last_error = CONTEXT->error_buffer; | |
160 | return; | |
161 | } | |
162 | STAP_RETVALUE = kread(addr); | |
163 | return; | |
164 | ||
165 | if (0) { | |
166 | deref_fault: /* branched to from kread() */ | |
167 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
168 | "kernel fault at %#lx accessing stack arg(%d)", | |
169 | (unsigned long)addr, n); | |
170 | CONTEXT->last_error = CONTEXT->error_buffer; | |
171 | } | |
172 | %} | |
173 | ||
174 | ||
5a24160a WC |
175 | /* Return the value of function arg #argnum (1=first arg) as a signed value. |
176 | * | |
177 | * We don't yet support extracting arg #5 and beyond, which are passed | |
178 | * on stack | |
179 | */ | |
180 | function _stp_arg:long (argnum:long) { | |
181 | val = 0 | |
1482dd61 | 182 | if (argnum < 1 || argnum > 7) { |
5a24160a WC |
183 | error(sprintf("Cannot access arg(%d)", argnum)) |
184 | return 0 | |
185 | } | |
186 | ||
187 | if (argnum == 1) | |
f52d32a9 | 188 | val = register("r0") |
5a24160a | 189 | else if (argnum == 2) |
f52d32a9 | 190 | val = register("r1") |
5a24160a | 191 | else if (argnum == 3) |
f52d32a9 | 192 | val = register("r2") |
5a24160a | 193 | else if (argnum == 4) |
f52d32a9 | 194 | val = register("r3") |
029130b7 DS |
195 | else |
196 | val = _stp_get_stack_nth(argnum - 5) | |
5a24160a WC |
197 | |
198 | return val; | |
199 | } | |
200 | ||
201 | /* Return the value of function arg #argnum as a signed int. */ | |
202 | function int_arg:long (argnum:long) { | |
203 | return _stp_arg(argnum) | |
204 | } | |
205 | ||
206 | /* Return the value of function arg #argnum as an unsigned int. */ | |
207 | function uint_arg:long (argnum:long) { | |
208 | return _stp_arg(argnum) & 0xffffffff; | |
209 | } | |
210 | ||
211 | function long_arg:long (argnum:long) { | |
212 | return int_arg(argnum) | |
213 | } | |
214 | ||
215 | function ulong_arg:long (argnum:long) { | |
216 | return uint_arg(argnum) | |
217 | } | |
218 | ||
219 | function longlong_arg:long (argnum:long) { | |
220 | /* | |
029130b7 DS |
221 | * gcc has a few odd rules: |
222 | * 1) If argnum == 2, the 64-bit arg will start with arg 3. | |
223 | * 2) If argnum == nr_regarg (4), gcc puts the whole 64-bit | |
224 | * arg on the stack. | |
225 | * | |
226 | * Note that following argument numbers will need to be | |
227 | * adjusted. | |
5a24160a | 228 | */ |
029130b7 DS |
229 | if (argnum == 2 || argnum == 4) |
230 | argnum++ | |
5a24160a WC |
231 | lowbits = uint_arg(argnum) |
232 | highbits = uint_arg(argnum+1) | |
233 | return ((highbits << 32) | lowbits) | |
234 | } | |
235 | ||
236 | function ulonglong_arg:long (argnum:long) { | |
237 | return longlong_arg(argnum) | |
238 | } | |
239 | ||
240 | function pointer_arg:long (argnum:long) { | |
241 | return ulong_arg(argnum) | |
242 | } | |
243 | ||
244 | function s32_arg:long (argnum:long) { | |
245 | return int_arg(argnum) | |
246 | } | |
247 | ||
248 | function u32_arg:long (argnum:long) { | |
249 | return uint_arg(argnum) | |
250 | } | |
251 | ||
252 | function s64_arg:long (argnum:long) { | |
253 | return longlong_arg(argnum) | |
254 | } | |
255 | ||
256 | function u64_arg:long (argnum:long) { | |
257 | return ulonglong_arg(argnum) | |
258 | } | |
259 | ||
260 | function asmlinkage() %{ /* pure */ %} | |
261 | ||
262 | function fastcall() %{ /* pure */ %} | |
263 | ||
309d67d8 | 264 | function regparm(n:long) %{ |
5a24160a WC |
265 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), |
266 | "regparm is invalid on arm."); | |
267 | CONTEXT->last_error = CONTEXT->error_buffer; | |
268 | %} |