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 * Portions Copyright 2016 Ruslan Bukin <br@bsdpad.com>
23 *
24 * $FreeBSD$
25 */
26 /*
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30 #include <sys/cdefs.h>
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/stack.h>
36 #include <sys/pcpu.h>
37
38 #include <machine/frame.h>
39 #include <machine/md_var.h>
40
41 #include <vm/vm.h>
42 #include <vm/vm_param.h>
43 #include <vm/pmap.h>
44
45 #include <machine/atomic.h>
46 #include <machine/db_machdep.h>
47 #include <machine/md_var.h>
48 #include <machine/stack.h>
49 #include <ddb/db_sym.h>
50 #include <ddb/ddb.h>
51 #include <sys/kdb.h>
52
53 #include "regset.h"
54
55 #define MAX_USTACK_DEPTH 2048
56
57 uint8_t dtrace_fuword8_nocheck(void *);
58 uint16_t dtrace_fuword16_nocheck(void *);
59 uint32_t dtrace_fuword32_nocheck(void *);
60 uint64_t dtrace_fuword64_nocheck(void *);
61
62 void
63 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
64 uint32_t *intrpc)
65 {
66 struct unwind_state state;
67 uintptr_t caller;
68 register_t sp;
69 int scp_offset;
70 int depth;
71
72 depth = 0;
73 caller = solaris_cpu[curcpu].cpu_dtrace_caller;
74
75 if (intrpc != 0) {
76 pcstack[depth++] = (pc_t)intrpc;
77 }
78
79 /*
80 * Construct the unwind state, starting from this function. This frame,
81 * and 'aframes' others will be skipped.
82 */
83 __asm __volatile("mv %0, sp" : "=&r" (sp));
84
85 state.fp = (uintptr_t)__builtin_frame_address(0);
86 state.sp = (uintptr_t)sp;
87 state.pc = (uintptr_t)dtrace_getpcstack;
88
89 while (depth < pcstack_limit) {
90 if (!unwind_frame(curthread, &state))
91 break;
92
93 if (!INKERNEL(state.pc) || !kstack_contains(curthread,
94 (vm_offset_t)state.fp, sizeof(uintptr_t)))
95 break;
96
97 if (aframes > 0) {
98 aframes--;
99
100 /*
101 * fbt_invop() records the return address at the time
102 * the FBT probe fires. We need to insert this into the
103 * backtrace manually, since the stack frame state at
104 * the time of the probe does not capture it.
105 */
106 if (aframes == 0 && caller != 0)
107 pcstack[depth++] = caller;
108 } else {
109 pcstack[depth++] = state.pc;
110 }
111 }
112
113 for (; depth < pcstack_limit; depth++) {
114 pcstack[depth] = 0;
115 }
116 }
117
118 static int
119 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
120 uintptr_t fp)
121 {
122 volatile uint16_t *flags;
123 uintptr_t oldfp;
124 int ret;
125
126 oldfp = fp;
127 ret = 0;
128 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
129
130 ASSERT(pcstack == NULL || pcstack_limit > 0);
131
132 while (pc != 0) {
133 /*
134 * We limit the number of times we can go around this
135 * loop to account for a circular stack.
136 */
137 if (ret++ >= MAX_USTACK_DEPTH) {
138 *flags |= CPU_DTRACE_BADSTACK;
139 cpu_core[curcpu].cpuc_dtrace_illval = fp;
140 break;
141 }
142
143 if (pcstack != NULL) {
144 *pcstack++ = (uint64_t)pc;
145 pcstack_limit--;
146 if (pcstack_limit <= 0)
147 break;
148 }
149
150 if (fp == 0)
151 break;
152
153 pc = dtrace_fuword64((void *)(fp +
154 offsetof(struct riscv_frame, f_retaddr)));
155 fp = dtrace_fuword64((void *)fp);
156
157 if (fp == oldfp) {
158 *flags |= CPU_DTRACE_BADSTACK;
159 cpu_core[curcpu].cpuc_dtrace_illval = fp;
160 break;
161 }
162 oldfp = fp;
163 }
164
165 return (ret);
166 }
167
168 void
169 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
170 {
171 volatile uint16_t *flags;
172 struct trapframe *tf;
173 uintptr_t pc, sp, fp;
174 proc_t *p;
175 int n;
176
177 p = curproc;
178 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
179
180 if (*flags & CPU_DTRACE_FAULT)
181 return;
182
183 if (pcstack_limit <= 0)
184 return;
185
186 /*
187 * If there's no user context we still need to zero the stack.
188 */
189 if (p == NULL || (tf = curthread->td_frame) == NULL)
190 goto zero;
191
192 *pcstack++ = (uint64_t)p->p_pid;
193 pcstack_limit--;
194
195 if (pcstack_limit <= 0)
196 return;
197
198 pc = tf->tf_sepc;
199 sp = tf->tf_sp;
200 fp = tf->tf_s[0];
201
202 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
203 /*
204 * In an entry probe. The frame pointer has not yet been
205 * pushed (that happens in the function prologue). The
206 * best approach is to add the current pc as a missing top
207 * of stack and back the pc up to the caller, which is stored
208 * at the current stack pointer address since the call
209 * instruction puts it there right before the branch.
210 */
211
212 *pcstack++ = (uint64_t)pc;
213 pcstack_limit--;
214 if (pcstack_limit <= 0)
215 return;
216
217 pc = tf->tf_ra;
218 }
219
220 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
221 ASSERT(n >= 0);
222 ASSERT(n <= pcstack_limit);
223
224 pcstack += n;
225 pcstack_limit -= n;
226
227 zero:
228 while (pcstack_limit-- > 0)
229 *pcstack++ = 0;
230 }
231
232 int
233 dtrace_getustackdepth(void)
234 {
235
236 printf("IMPLEMENT ME: %s\n", __func__);
237
238 return (0);
239 }
240
241 void
242 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
243 {
244
245 printf("IMPLEMENT ME: %s\n", __func__);
246 }
247
248 /*ARGSUSED*/
249 uint64_t
250 dtrace_getarg(int arg, int aframes)
251 {
252
253 printf("IMPLEMENT ME: %s\n", __func__);
254
255 return (0);
256 }
257
258 int
259 dtrace_getstackdepth(int aframes)
260 {
261 struct unwind_state state;
262 int scp_offset;
263 register_t sp;
264 int depth;
265 bool done;
266
267 depth = 1;
268 done = false;
269
270 __asm __volatile("mv %0, sp" : "=&r" (sp));
271
272 state.fp = (uintptr_t)__builtin_frame_address(0);
273 state.sp = sp;
274 state.pc = (uintptr_t)dtrace_getstackdepth;
275
276 do {
277 done = !unwind_frame(curthread, &state);
278 if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
279 break;
280 depth++;
281 } while (!done);
282
283 if (depth < aframes)
284 return (0);
285 else
286 return (depth - aframes);
287 }
288
289 ulong_t
290 dtrace_getreg(struct trapframe *rp, uint_t reg)
291 {
292
293 printf("IMPLEMENT ME: %s\n", __func__);
294
295 return (0);
296 }
297
298 static int
299 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
300 {
301
302 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
303 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
304 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
305 return (0);
306 }
307
308 return (1);
309 }
310
311 void
312 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
313 volatile uint16_t *flags)
314 {
315
316 if (dtrace_copycheck(uaddr, kaddr, size))
317 dtrace_copy(uaddr, kaddr, size);
318 }
319
320 void
321 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
322 volatile uint16_t *flags)
323 {
324
325 if (dtrace_copycheck(uaddr, kaddr, size))
326 dtrace_copy(kaddr, uaddr, size);
327 }
328
329 void
330 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
331 volatile uint16_t *flags)
332 {
333
334 if (dtrace_copycheck(uaddr, kaddr, size))
335 dtrace_copystr(uaddr, kaddr, size, flags);
336 }
337
338 void
339 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
340 volatile uint16_t *flags)
341 {
342
343 if (dtrace_copycheck(uaddr, kaddr, size))
344 dtrace_copystr(kaddr, uaddr, size, flags);
345 }
346
347 uint8_t
348 dtrace_fuword8(void *uaddr)
349 {
350
351 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
352 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
353 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
354 return (0);
355 }
356
357 return (dtrace_fuword8_nocheck(uaddr));
358 }
359
360 uint16_t
361 dtrace_fuword16(void *uaddr)
362 {
363
364 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
365 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
366 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
367 return (0);
368 }
369
370 return (dtrace_fuword16_nocheck(uaddr));
371 }
372
373 uint32_t
374 dtrace_fuword32(void *uaddr)
375 {
376
377 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
378 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
379 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
380 return (0);
381 }
382
383 return (dtrace_fuword32_nocheck(uaddr));
384 }
385
386 uint64_t
387 dtrace_fuword64(void *uaddr)
388 {
389
390 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
391 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
392 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
393 return (0);
394 }
395
396 return (dtrace_fuword64_nocheck(uaddr));
397 }
Cache object: 7117dcd849b7b371f432b7e9eef37045
|