1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * $FreeBSD$
23 */
24 /*
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/stack.h>
34 #include <sys/pcpu.h>
35
36 #include <machine/frame.h>
37 #include <machine/md_var.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_param.h>
41 #include <vm/pmap.h>
42
43 #include <machine/atomic.h>
44 #include <machine/db_machdep.h>
45 #include <machine/md_var.h>
46 #include <machine/stack.h>
47 #include <ddb/db_sym.h>
48 #include <ddb/ddb.h>
49 #include <sys/kdb.h>
50
51 #include "regset.h"
52
53 #define MAX_USTACK_DEPTH 2048
54
55 uint8_t dtrace_fuword8_nocheck(void *);
56 uint16_t dtrace_fuword16_nocheck(void *);
57 uint32_t dtrace_fuword32_nocheck(void *);
58 uint64_t dtrace_fuword64_nocheck(void *);
59
60 void
61 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
62 uint32_t *intrpc)
63 {
64 struct unwind_state state;
65 int scp_offset;
66 int depth;
67
68 depth = 0;
69
70 if (intrpc != 0) {
71 pcstack[depth++] = (pc_t) intrpc;
72 }
73
74 aframes++;
75
76 state.fp = (uintptr_t)__builtin_frame_address(0);
77 state.pc = (uintptr_t)dtrace_getpcstack;
78
79 while (depth < pcstack_limit) {
80 if (!unwind_frame(curthread, &state))
81 break;
82 if (!INKERNEL(state.pc))
83 break;
84
85 /*
86 * NB: Unlike some other architectures, we don't need to
87 * explicitly insert cpu_dtrace_caller as it appears in the
88 * normal kernel stack trace rather than a special trap frame.
89 */
90 if (aframes > 0) {
91 aframes--;
92 } else {
93 pcstack[depth++] = state.pc;
94 }
95
96 }
97
98 for (; depth < pcstack_limit; depth++) {
99 pcstack[depth] = 0;
100 }
101 }
102
103 static int
104 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
105 uintptr_t fp)
106 {
107 volatile uint16_t *flags =
108 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
109 int ret = 0;
110 uintptr_t oldfp = fp;
111
112 ASSERT(pcstack == NULL || pcstack_limit > 0);
113
114 while (pc != 0) {
115 /*
116 * We limit the number of times we can go around this
117 * loop to account for a circular stack.
118 */
119 if (ret++ >= MAX_USTACK_DEPTH) {
120 *flags |= CPU_DTRACE_BADSTACK;
121 cpu_core[curcpu].cpuc_dtrace_illval = fp;
122 break;
123 }
124
125 if (pcstack != NULL) {
126 *pcstack++ = (uint64_t)pc;
127 pcstack_limit--;
128 if (pcstack_limit <= 0)
129 break;
130 }
131
132 if (fp == 0)
133 break;
134
135 pc = dtrace_fuword64((void *)(fp +
136 offsetof(struct arm64_frame, f_retaddr)));
137 fp = dtrace_fuword64((void *)fp);
138
139 if (fp == oldfp) {
140 *flags |= CPU_DTRACE_BADSTACK;
141 cpu_core[curcpu].cpuc_dtrace_illval = fp;
142 break;
143 }
144
145 /*
146 * ARM64TODO:
147 * This workaround might not be necessary. It needs to be
148 * revised and removed from all architectures if found
149 * unwanted. Leaving the original x86 comment for reference.
150 *
151 * This is totally bogus: if we faulted, we're going to clear
152 * the fault and break. This is to deal with the apparently
153 * broken Java stacks on x86.
154 */
155 if (*flags & CPU_DTRACE_FAULT) {
156 *flags &= ~CPU_DTRACE_FAULT;
157 break;
158 }
159
160 oldfp = fp;
161 }
162
163 return (ret);
164 }
165
166 void
167 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
168 {
169 proc_t *p = curproc;
170 struct trapframe *tf;
171 uintptr_t pc, fp;
172 volatile uint16_t *flags =
173 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
174 int n;
175
176 if (*flags & CPU_DTRACE_FAULT)
177 return;
178
179 if (pcstack_limit <= 0)
180 return;
181
182 /*
183 * If there's no user context we still need to zero the stack.
184 */
185 if (p == NULL || (tf = curthread->td_frame) == NULL)
186 goto zero;
187
188 *pcstack++ = (uint64_t)p->p_pid;
189 pcstack_limit--;
190
191 if (pcstack_limit <= 0)
192 return;
193
194 pc = tf->tf_elr;
195 fp = tf->tf_x[29];
196
197 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
198 /*
199 * In an entry probe. The frame pointer has not yet been
200 * pushed (that happens in the function prologue). The
201 * best approach is to add the current pc as a missing top
202 * of stack and back the pc up to the caller, which is stored
203 * at the current stack pointer address since the call
204 * instruction puts it there right before the branch.
205 */
206
207 *pcstack++ = (uint64_t)pc;
208 pcstack_limit--;
209 if (pcstack_limit <= 0)
210 return;
211
212 pc = tf->tf_lr;
213 }
214
215 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
216 ASSERT(n >= 0);
217 ASSERT(n <= pcstack_limit);
218
219 pcstack += n;
220 pcstack_limit -= n;
221
222 zero:
223 while (pcstack_limit-- > 0)
224 *pcstack++ = 0;
225 }
226
227 int
228 dtrace_getustackdepth(void)
229 {
230
231 printf("IMPLEMENT ME: %s\n", __func__);
232
233 return (0);
234 }
235
236 void
237 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
238 {
239
240 printf("IMPLEMENT ME: %s\n", __func__);
241 }
242
243 /*ARGSUSED*/
244 uint64_t
245 dtrace_getarg(int arg, int aframes)
246 {
247
248 printf("IMPLEMENT ME: %s\n", __func__);
249
250 return (0);
251 }
252
253 int
254 dtrace_getstackdepth(int aframes)
255 {
256 struct unwind_state state;
257 int scp_offset;
258 int depth;
259 bool done;
260
261 depth = 1;
262 done = false;
263
264 state.fp = (uintptr_t)__builtin_frame_address(0);
265 state.pc = (uintptr_t)dtrace_getstackdepth;
266
267 do {
268 done = !unwind_frame(curthread, &state);
269 if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
270 break;
271 depth++;
272 } while (!done);
273
274 if (depth < aframes)
275 return (0);
276 else
277 return (depth - aframes);
278 }
279
280 ulong_t
281 dtrace_getreg(struct trapframe *rp, uint_t reg)
282 {
283
284 printf("IMPLEMENT ME: %s\n", __func__);
285
286 return (0);
287 }
288
289 static int
290 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
291 {
292
293 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
294 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
295 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
296 return (0);
297 }
298
299 return (1);
300 }
301
302 void
303 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
304 volatile uint16_t *flags)
305 {
306
307 if (dtrace_copycheck(uaddr, kaddr, size))
308 dtrace_copy(uaddr, kaddr, size);
309 }
310
311 void
312 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
313 volatile uint16_t *flags)
314 {
315
316 if (dtrace_copycheck(uaddr, kaddr, size))
317 dtrace_copy(kaddr, uaddr, size);
318 }
319
320 void
321 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
322 volatile uint16_t *flags)
323 {
324
325 if (dtrace_copycheck(uaddr, kaddr, size))
326 dtrace_copystr(uaddr, kaddr, size, flags);
327 }
328
329 void
330 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
331 volatile uint16_t *flags)
332 {
333
334 if (dtrace_copycheck(uaddr, kaddr, size))
335 dtrace_copystr(kaddr, uaddr, size, flags);
336 }
337
338 uint8_t
339 dtrace_fuword8(void *uaddr)
340 {
341
342 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
343 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
344 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
345 return (0);
346 }
347
348 return (dtrace_fuword8_nocheck(uaddr));
349 }
350
351 uint16_t
352 dtrace_fuword16(void *uaddr)
353 {
354
355 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
356 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
357 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
358 return (0);
359 }
360
361 return (dtrace_fuword16_nocheck(uaddr));
362 }
363
364 uint32_t
365 dtrace_fuword32(void *uaddr)
366 {
367
368 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
369 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
370 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
371 return (0);
372 }
373
374 return (dtrace_fuword32_nocheck(uaddr));
375 }
376
377 uint64_t
378 dtrace_fuword64(void *uaddr)
379 {
380
381 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
382 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
383 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
384 return (0);
385 }
386
387 return (dtrace_fuword64_nocheck(uaddr));
388 }
Cache object: 1ad4f13a7400c74023b7f36b5024f710
|