1*eada09acSchs /* $NetBSD: dtrace_isa.c,v 1.6 2018/05/28 21:05:03 chs Exp $ */
201c9547eSdarran
3bb8023b5Sdarran /*
4bb8023b5Sdarran * CDDL HEADER START
5bb8023b5Sdarran *
6bb8023b5Sdarran * The contents of this file are subject to the terms of the
7bb8023b5Sdarran * Common Development and Distribution License, Version 1.0 only
8bb8023b5Sdarran * (the "License"). You may not use this file except in compliance
9bb8023b5Sdarran * with the License.
10bb8023b5Sdarran *
11bb8023b5Sdarran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12bb8023b5Sdarran * or http://www.opensolaris.org/os/licensing.
13bb8023b5Sdarran * See the License for the specific language governing permissions
14bb8023b5Sdarran * and limitations under the License.
15bb8023b5Sdarran *
16bb8023b5Sdarran * When distributing Covered Code, include this CDDL HEADER in each
17bb8023b5Sdarran * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18bb8023b5Sdarran * If applicable, add the following below this CDDL HEADER, with the
19bb8023b5Sdarran * fields enclosed by brackets "[]" replaced with your own identifying
20bb8023b5Sdarran * information: Portions Copyright [yyyy] [name of copyright owner]
21bb8023b5Sdarran *
22bb8023b5Sdarran * CDDL HEADER END
23bb8023b5Sdarran *
24*eada09acSchs * $FreeBSD: head/sys/cddl/dev/dtrace/i386/dtrace_isa.c 298171 2016-04-17 23:08:47Z markj $
25bb8023b5Sdarran */
26bb8023b5Sdarran /*
27bb8023b5Sdarran * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28bb8023b5Sdarran * Use is subject to license terms.
29bb8023b5Sdarran */
30bb8023b5Sdarran #include <sys/cdefs.h>
31bb8023b5Sdarran
32bb8023b5Sdarran #include <sys/param.h>
33bb8023b5Sdarran #include <sys/systm.h>
34bb8023b5Sdarran #include <sys/kernel.h>
35bb8023b5Sdarran
3601c9547eSdarran #include <machine/vmparam.h>
3701c9547eSdarran #include <machine/pmap.h>
38bb8023b5Sdarran
39*eada09acSchs #include "regset.h"
40*eada09acSchs
4101c9547eSdarran uintptr_t kernelbase = (uintptr_t)KERNBASE;
42bb8023b5Sdarran
4380dd0070Schs #define INKERNEL(va) \
4480dd0070Schs (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS && \
45bb8023b5Sdarran ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
46bb8023b5Sdarran
4701c9547eSdarran struct i386_frame {
4801c9547eSdarran struct i386_frame *f_frame;
4901c9547eSdarran int f_retaddr;
5001c9547eSdarran };
5101c9547eSdarran
5201c9547eSdarran typedef unsigned long vm_offset_t;
5301c9547eSdarran
54bb8023b5Sdarran uint8_t dtrace_fuword8_nocheck(void *);
55bb8023b5Sdarran uint16_t dtrace_fuword16_nocheck(void *);
56bb8023b5Sdarran uint32_t dtrace_fuword32_nocheck(void *);
57bb8023b5Sdarran uint64_t dtrace_fuword64_nocheck(void *);
58bb8023b5Sdarran
59*eada09acSchs int dtrace_ustackdepth_max = 2048;
60*eada09acSchs
61bb8023b5Sdarran void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)62bb8023b5Sdarran dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
63bb8023b5Sdarran uint32_t *intrpc)
64bb8023b5Sdarran {
65bb8023b5Sdarran int depth = 0;
66bb8023b5Sdarran register_t ebp;
67bb8023b5Sdarran struct i386_frame *frame;
68bb8023b5Sdarran vm_offset_t callpc;
6901c9547eSdarran pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller;
70bb8023b5Sdarran
71bb8023b5Sdarran if (intrpc != 0)
72bb8023b5Sdarran pcstack[depth++] = (pc_t) intrpc;
73bb8023b5Sdarran
74bb8023b5Sdarran aframes++;
75bb8023b5Sdarran
76bb8023b5Sdarran __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
77bb8023b5Sdarran
78bb8023b5Sdarran frame = (struct i386_frame *)ebp;
79bb8023b5Sdarran while (depth < pcstack_limit) {
80bb8023b5Sdarran if (!INKERNEL(frame))
81bb8023b5Sdarran break;
82bb8023b5Sdarran
83bb8023b5Sdarran callpc = frame->f_retaddr;
84bb8023b5Sdarran
85bb8023b5Sdarran if (!INKERNEL(callpc))
86bb8023b5Sdarran break;
87bb8023b5Sdarran
88bb8023b5Sdarran if (aframes > 0) {
89bb8023b5Sdarran aframes--;
90bb8023b5Sdarran if ((aframes == 0) && (caller != 0)) {
91bb8023b5Sdarran pcstack[depth++] = caller;
92bb8023b5Sdarran }
93bb8023b5Sdarran }
94bb8023b5Sdarran else {
95bb8023b5Sdarran pcstack[depth++] = callpc;
96bb8023b5Sdarran }
97bb8023b5Sdarran
98bb8023b5Sdarran if (frame->f_frame <= frame ||
99bb8023b5Sdarran (vm_offset_t)frame->f_frame >=
10001c9547eSdarran (vm_offset_t)ebp + KSTACK_SIZE)
101bb8023b5Sdarran break;
102bb8023b5Sdarran frame = frame->f_frame;
103bb8023b5Sdarran }
104bb8023b5Sdarran
105bb8023b5Sdarran for (; depth < pcstack_limit; depth++) {
106bb8023b5Sdarran pcstack[depth] = 0;
107bb8023b5Sdarran }
108bb8023b5Sdarran }
109bb8023b5Sdarran
110bb8023b5Sdarran static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)111bb8023b5Sdarran dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
112bb8023b5Sdarran uintptr_t sp)
113bb8023b5Sdarran {
11480dd0070Schs #ifdef notyet
115bb8023b5Sdarran proc_t *p = curproc;
11680dd0070Schs uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
11780dd0070Schs size_t s1, s2;
11880dd0070Schs #endif
119*eada09acSchs uintptr_t oldsp;
120bb8023b5Sdarran volatile uint16_t *flags =
12101c9547eSdarran (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
122bb8023b5Sdarran int ret = 0;
123bb8023b5Sdarran
124bb8023b5Sdarran ASSERT(pcstack == NULL || pcstack_limit > 0);
125*eada09acSchs ASSERT(dtrace_ustackdepth_max > 0);
126bb8023b5Sdarran
12780dd0070Schs #ifdef notyet /* XXX signal stack. */
128bb8023b5Sdarran if (p->p_model == DATAMODEL_NATIVE) {
129bb8023b5Sdarran s1 = sizeof (struct frame) + 2 * sizeof (long);
130bb8023b5Sdarran s2 = s1 + sizeof (siginfo_t);
131bb8023b5Sdarran } else {
132bb8023b5Sdarran s1 = sizeof (struct frame32) + 3 * sizeof (int);
133bb8023b5Sdarran s2 = s1 + sizeof (siginfo32_t);
134bb8023b5Sdarran }
13580dd0070Schs #endif
136bb8023b5Sdarran
13780dd0070Schs while (pc != 0) {
138*eada09acSchs /*
139*eada09acSchs * We limit the number of times we can go around this
140*eada09acSchs * loop to account for a circular stack.
141*eada09acSchs */
142*eada09acSchs if (ret++ >= dtrace_ustackdepth_max) {
143*eada09acSchs *flags |= CPU_DTRACE_BADSTACK;
144*eada09acSchs cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
145*eada09acSchs break;
146*eada09acSchs }
147*eada09acSchs
148bb8023b5Sdarran if (pcstack != NULL) {
149bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
150bb8023b5Sdarran pcstack_limit--;
151bb8023b5Sdarran if (pcstack_limit <= 0)
152bb8023b5Sdarran break;
153bb8023b5Sdarran }
154bb8023b5Sdarran
15580dd0070Schs if (sp == 0)
15680dd0070Schs break;
15780dd0070Schs
158*eada09acSchs oldsp = sp;
159*eada09acSchs
16080dd0070Schs #ifdef notyet /* XXX signal stack. */
161bb8023b5Sdarran if (oldcontext == sp + s1 || oldcontext == sp + s2) {
162bb8023b5Sdarran if (p->p_model == DATAMODEL_NATIVE) {
163bb8023b5Sdarran ucontext_t *ucp = (ucontext_t *)oldcontext;
164bb8023b5Sdarran greg_t *gregs = ucp->uc_mcontext.gregs;
165bb8023b5Sdarran
166bb8023b5Sdarran sp = dtrace_fulword(&gregs[REG_FP]);
167bb8023b5Sdarran pc = dtrace_fulword(&gregs[REG_PC]);
168bb8023b5Sdarran
169bb8023b5Sdarran oldcontext = dtrace_fulword(&ucp->uc_link);
170bb8023b5Sdarran } else {
171bb8023b5Sdarran ucontext32_t *ucp = (ucontext32_t *)oldcontext;
172bb8023b5Sdarran greg32_t *gregs = ucp->uc_mcontext.gregs;
173bb8023b5Sdarran
174bb8023b5Sdarran sp = dtrace_fuword32(&gregs[EBP]);
175bb8023b5Sdarran pc = dtrace_fuword32(&gregs[EIP]);
176bb8023b5Sdarran
177bb8023b5Sdarran oldcontext = dtrace_fuword32(&ucp->uc_link);
178bb8023b5Sdarran }
179bb8023b5Sdarran } else {
180bb8023b5Sdarran if (p->p_model == DATAMODEL_NATIVE) {
181bb8023b5Sdarran struct frame *fr = (struct frame *)sp;
182bb8023b5Sdarran
183bb8023b5Sdarran pc = dtrace_fulword(&fr->fr_savpc);
184bb8023b5Sdarran sp = dtrace_fulword(&fr->fr_savfp);
185bb8023b5Sdarran } else {
186bb8023b5Sdarran struct frame32 *fr = (struct frame32 *)sp;
187bb8023b5Sdarran
188bb8023b5Sdarran pc = dtrace_fuword32(&fr->fr_savpc);
189bb8023b5Sdarran sp = dtrace_fuword32(&fr->fr_savfp);
190bb8023b5Sdarran }
191bb8023b5Sdarran }
19280dd0070Schs #else
19380dd0070Schs pc = dtrace_fuword32((void *)(sp +
19480dd0070Schs offsetof(struct i386_frame, f_retaddr)));
19580dd0070Schs sp = dtrace_fuword32((void *)sp);
19680dd0070Schs #endif /* ! notyet */
197bb8023b5Sdarran
198*eada09acSchs if (sp == oldsp) {
199*eada09acSchs *flags |= CPU_DTRACE_BADSTACK;
200*eada09acSchs cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
201*eada09acSchs break;
202*eada09acSchs }
203*eada09acSchs
204bb8023b5Sdarran /*
205bb8023b5Sdarran * This is totally bogus: if we faulted, we're going to clear
206bb8023b5Sdarran * the fault and break. This is to deal with the apparently
207bb8023b5Sdarran * broken Java stacks on x86.
208bb8023b5Sdarran */
209bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT) {
210bb8023b5Sdarran *flags &= ~CPU_DTRACE_FAULT;
211bb8023b5Sdarran break;
212bb8023b5Sdarran }
213bb8023b5Sdarran }
214bb8023b5Sdarran
215bb8023b5Sdarran return (ret);
216bb8023b5Sdarran }
217bb8023b5Sdarran
218bb8023b5Sdarran void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)219bb8023b5Sdarran dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
220bb8023b5Sdarran {
221bb8023b5Sdarran proc_t *p = curproc;
22280dd0070Schs struct trapframe *tf;
22380dd0070Schs uintptr_t pc, sp, fp;
224bb8023b5Sdarran volatile uint16_t *flags =
22501c9547eSdarran (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
226bb8023b5Sdarran int n;
227bb8023b5Sdarran
228bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT)
229bb8023b5Sdarran return;
230bb8023b5Sdarran
231bb8023b5Sdarran if (pcstack_limit <= 0)
232bb8023b5Sdarran return;
233bb8023b5Sdarran
234bb8023b5Sdarran /*
235bb8023b5Sdarran * If there's no user context we still need to zero the stack.
236bb8023b5Sdarran */
23780dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
238bb8023b5Sdarran goto zero;
239bb8023b5Sdarran
240bb8023b5Sdarran *pcstack++ = (uint64_t)p->p_pid;
241bb8023b5Sdarran pcstack_limit--;
242bb8023b5Sdarran
243bb8023b5Sdarran if (pcstack_limit <= 0)
244bb8023b5Sdarran return;
245bb8023b5Sdarran
24680dd0070Schs pc = tf->tf_eip;
24780dd0070Schs fp = tf->tf_ebp;
24880dd0070Schs sp = tf->tf_esp;
249bb8023b5Sdarran
250bb8023b5Sdarran if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
25180dd0070Schs /*
25280dd0070Schs * In an entry probe. The frame pointer has not yet been
25380dd0070Schs * pushed (that happens in the function prologue). The
25480dd0070Schs * best approach is to add the current pc as a missing top
25580dd0070Schs * of stack and back the pc up to the caller, which is stored
25680dd0070Schs * at the current stack pointer address since the call
25780dd0070Schs * instruction puts it there right before the branch.
25880dd0070Schs */
25980dd0070Schs
260bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
261bb8023b5Sdarran pcstack_limit--;
262bb8023b5Sdarran if (pcstack_limit <= 0)
263bb8023b5Sdarran return;
264bb8023b5Sdarran
26580dd0070Schs pc = dtrace_fuword32((void *) sp);
266bb8023b5Sdarran }
267bb8023b5Sdarran
268*eada09acSchs n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
269bb8023b5Sdarran ASSERT(n >= 0);
270bb8023b5Sdarran ASSERT(n <= pcstack_limit);
271bb8023b5Sdarran
272bb8023b5Sdarran pcstack += n;
273bb8023b5Sdarran pcstack_limit -= n;
274bb8023b5Sdarran
275bb8023b5Sdarran zero:
276bb8023b5Sdarran while (pcstack_limit-- > 0)
27780dd0070Schs *pcstack++ = 0;
278bb8023b5Sdarran }
279bb8023b5Sdarran
280bb8023b5Sdarran int
dtrace_getustackdepth(void)281bb8023b5Sdarran dtrace_getustackdepth(void)
282bb8023b5Sdarran {
28380dd0070Schs proc_t *p = curproc;
28480dd0070Schs struct trapframe *tf;
28580dd0070Schs uintptr_t pc, fp, sp;
28680dd0070Schs int n = 0;
28780dd0070Schs
28880dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
28980dd0070Schs return (0);
29080dd0070Schs
29180dd0070Schs if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
29280dd0070Schs return (-1);
29380dd0070Schs
29480dd0070Schs pc = tf->tf_eip;
29580dd0070Schs fp = tf->tf_ebp;
29680dd0070Schs sp = tf->tf_esp;
29780dd0070Schs
29880dd0070Schs if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
29980dd0070Schs /*
30080dd0070Schs * In an entry probe. The frame pointer has not yet been
30180dd0070Schs * pushed (that happens in the function prologue). The
30280dd0070Schs * best approach is to add the current pc as a missing top
30380dd0070Schs * of stack and back the pc up to the caller, which is stored
30480dd0070Schs * at the current stack pointer address since the call
30580dd0070Schs * instruction puts it there right before the branch.
30680dd0070Schs */
30780dd0070Schs
30880dd0070Schs pc = dtrace_fuword32((void *) sp);
30980dd0070Schs n++;
31080dd0070Schs }
31180dd0070Schs
31280dd0070Schs n += dtrace_getustack_common(NULL, 0, pc, fp);
31380dd0070Schs
31480dd0070Schs return (n);
315bb8023b5Sdarran }
316bb8023b5Sdarran
317bb8023b5Sdarran void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)318bb8023b5Sdarran dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
319bb8023b5Sdarran {
320bb8023b5Sdarran proc_t *p = curproc;
32180dd0070Schs struct trapframe *tf;
32280dd0070Schs uintptr_t pc, sp, fp;
323bb8023b5Sdarran volatile uint16_t *flags =
32401c9547eSdarran (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
32580dd0070Schs #ifdef notyet /* XXX signal stack */
32680dd0070Schs uintptr_t oldcontext;
327bb8023b5Sdarran size_t s1, s2;
32880dd0070Schs #endif
329bb8023b5Sdarran
330bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT)
331bb8023b5Sdarran return;
332bb8023b5Sdarran
333bb8023b5Sdarran if (pcstack_limit <= 0)
334bb8023b5Sdarran return;
335bb8023b5Sdarran
336bb8023b5Sdarran /*
337bb8023b5Sdarran * If there's no user context we still need to zero the stack.
338bb8023b5Sdarran */
33980dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
340bb8023b5Sdarran goto zero;
341bb8023b5Sdarran
342bb8023b5Sdarran *pcstack++ = (uint64_t)p->p_pid;
343bb8023b5Sdarran pcstack_limit--;
344bb8023b5Sdarran
345bb8023b5Sdarran if (pcstack_limit <= 0)
346bb8023b5Sdarran return;
347bb8023b5Sdarran
34880dd0070Schs pc = tf->tf_eip;
34980dd0070Schs fp = tf->tf_ebp;
35080dd0070Schs sp = tf->tf_esp;
35180dd0070Schs
35280dd0070Schs #ifdef notyet /* XXX signal stack */
353bb8023b5Sdarran oldcontext = lwp->lwp_oldcontext;
354bb8023b5Sdarran
355bb8023b5Sdarran if (p->p_model == DATAMODEL_NATIVE) {
356bb8023b5Sdarran s1 = sizeof (struct frame) + 2 * sizeof (long);
357bb8023b5Sdarran s2 = s1 + sizeof (siginfo_t);
358bb8023b5Sdarran } else {
359bb8023b5Sdarran s1 = sizeof (struct frame32) + 3 * sizeof (int);
360bb8023b5Sdarran s2 = s1 + sizeof (siginfo32_t);
361bb8023b5Sdarran }
36280dd0070Schs #endif
363bb8023b5Sdarran
364bb8023b5Sdarran if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
365bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
366bb8023b5Sdarran *fpstack++ = 0;
367bb8023b5Sdarran pcstack_limit--;
368bb8023b5Sdarran if (pcstack_limit <= 0)
369bb8023b5Sdarran return;
370bb8023b5Sdarran
37180dd0070Schs pc = dtrace_fuword32((void *)sp);
372bb8023b5Sdarran }
373bb8023b5Sdarran
37480dd0070Schs while (pc != 0) {
375bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
37680dd0070Schs *fpstack++ = fp;
377bb8023b5Sdarran pcstack_limit--;
378bb8023b5Sdarran if (pcstack_limit <= 0)
379bb8023b5Sdarran break;
380bb8023b5Sdarran
38180dd0070Schs if (fp == 0)
38280dd0070Schs break;
38380dd0070Schs
38480dd0070Schs #ifdef notyet /* XXX signal stack */
385bb8023b5Sdarran if (oldcontext == sp + s1 || oldcontext == sp + s2) {
386bb8023b5Sdarran if (p->p_model == DATAMODEL_NATIVE) {
387bb8023b5Sdarran ucontext_t *ucp = (ucontext_t *)oldcontext;
388bb8023b5Sdarran greg_t *gregs = ucp->uc_mcontext.gregs;
389bb8023b5Sdarran
390bb8023b5Sdarran sp = dtrace_fulword(&gregs[REG_FP]);
391bb8023b5Sdarran pc = dtrace_fulword(&gregs[REG_PC]);
392bb8023b5Sdarran
393bb8023b5Sdarran oldcontext = dtrace_fulword(&ucp->uc_link);
394bb8023b5Sdarran } else {
395bb8023b5Sdarran ucontext_t *ucp = (ucontext_t *)oldcontext;
396bb8023b5Sdarran greg_t *gregs = ucp->uc_mcontext.gregs;
397bb8023b5Sdarran
398bb8023b5Sdarran sp = dtrace_fuword32(&gregs[EBP]);
399bb8023b5Sdarran pc = dtrace_fuword32(&gregs[EIP]);
400bb8023b5Sdarran
401bb8023b5Sdarran oldcontext = dtrace_fuword32(&ucp->uc_link);
402bb8023b5Sdarran }
40380dd0070Schs } else
40480dd0070Schs #endif /* XXX */
40580dd0070Schs {
40680dd0070Schs pc = dtrace_fuword32((void *)(fp +
40780dd0070Schs offsetof(struct i386_frame, f_retaddr)));
40880dd0070Schs fp = dtrace_fuword32((void *)fp);
409bb8023b5Sdarran }
410bb8023b5Sdarran
411bb8023b5Sdarran /*
412bb8023b5Sdarran * This is totally bogus: if we faulted, we're going to clear
413bb8023b5Sdarran * the fault and break. This is to deal with the apparently
414bb8023b5Sdarran * broken Java stacks on x86.
415bb8023b5Sdarran */
416bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT) {
417bb8023b5Sdarran *flags &= ~CPU_DTRACE_FAULT;
418bb8023b5Sdarran break;
419bb8023b5Sdarran }
420bb8023b5Sdarran }
421bb8023b5Sdarran
422bb8023b5Sdarran zero:
423bb8023b5Sdarran while (pcstack_limit-- > 0)
42480dd0070Schs *pcstack++ = 0;
425bb8023b5Sdarran }
426bb8023b5Sdarran
427bb8023b5Sdarran uint64_t
dtrace_getarg(int arg,int aframes)428bb8023b5Sdarran dtrace_getarg(int arg, int aframes)
429bb8023b5Sdarran {
4300fa27af2Schs struct trapframe *frame;
431bb8023b5Sdarran struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
4320fa27af2Schs uintptr_t *stack, val;
43301c9547eSdarran int i;
43480dd0070Schs
435bb8023b5Sdarran for (i = 1; i <= aframes; i++) {
436bb8023b5Sdarran fp = fp->f_frame;
437bb8023b5Sdarran
4380fa27af2Schs if (P2ROUNDUP(fp->f_retaddr, 16) ==
4390fa27af2Schs (long)dtrace_invop_callsite) {
440bb8023b5Sdarran /*
441bb8023b5Sdarran * If we pass through the invalid op handler, we will
4420fa27af2Schs * use the trap frame pointer that it pushed on the
4430fa27af2Schs * stack as the second argument to dtrace_invop() as
4440fa27af2Schs * the pointer to the stack.
445bb8023b5Sdarran */
4460fa27af2Schs frame = (struct trapframe *)(((uintptr_t **)&fp[1])[1]);
4470fa27af2Schs
4480fa27af2Schs /*
4490fa27af2Schs * Skip the three hardware-saved registers and the
4500fa27af2Schs * return address.
4510fa27af2Schs */
4520fa27af2Schs stack = (uintptr_t *)&frame->tf_esp + 1;
453bb8023b5Sdarran goto load;
454bb8023b5Sdarran }
455*eada09acSchs
456bb8023b5Sdarran }
457bb8023b5Sdarran
458bb8023b5Sdarran /*
459bb8023b5Sdarran * We know that we did not come through a trap to get into
460bb8023b5Sdarran * dtrace_probe() -- the provider simply called dtrace_probe()
461bb8023b5Sdarran * directly. As this is the case, we need to shift the argument
462bb8023b5Sdarran * that we're looking for: the probe ID is the first argument to
463bb8023b5Sdarran * dtrace_probe(), so the argument n will actually be found where
464bb8023b5Sdarran * one would expect to find argument (n + 1).
465bb8023b5Sdarran */
466bb8023b5Sdarran arg++;
467bb8023b5Sdarran
46880dd0070Schs stack = (uintptr_t *)fp + 2;
469bb8023b5Sdarran
470bb8023b5Sdarran load:
471bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
472bb8023b5Sdarran val = stack[arg];
473bb8023b5Sdarran DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
474bb8023b5Sdarran
475bb8023b5Sdarran return (val);
476bb8023b5Sdarran }
477bb8023b5Sdarran
478bb8023b5Sdarran int
dtrace_getstackdepth(int aframes)479bb8023b5Sdarran dtrace_getstackdepth(int aframes)
480bb8023b5Sdarran {
481bb8023b5Sdarran int depth = 0;
482bb8023b5Sdarran struct i386_frame *frame;
483bb8023b5Sdarran vm_offset_t ebp;
484bb8023b5Sdarran
485bb8023b5Sdarran aframes++;
486bb8023b5Sdarran ebp = dtrace_getfp();
487bb8023b5Sdarran frame = (struct i386_frame *)ebp;
488bb8023b5Sdarran depth++;
489bb8023b5Sdarran for(;;) {
490bb8023b5Sdarran if (!INKERNEL((long) frame))
491bb8023b5Sdarran break;
492bb8023b5Sdarran if (!INKERNEL((long) frame->f_frame))
493bb8023b5Sdarran break;
494bb8023b5Sdarran depth++;
495bb8023b5Sdarran if (frame->f_frame <= frame ||
496bb8023b5Sdarran (vm_offset_t)frame->f_frame >=
49701c9547eSdarran (vm_offset_t)ebp + KSTACK_SIZE)
498bb8023b5Sdarran break;
499bb8023b5Sdarran frame = frame->f_frame;
500bb8023b5Sdarran }
501bb8023b5Sdarran if (depth < aframes)
502bb8023b5Sdarran return 0;
503bb8023b5Sdarran else
504bb8023b5Sdarran return depth - aframes;
505bb8023b5Sdarran }
506bb8023b5Sdarran
507bb8023b5Sdarran ulong_t
dtrace_getreg(struct trapframe * rp,uint_t reg)508*eada09acSchs dtrace_getreg(struct trapframe *rp, uint_t reg)
509bb8023b5Sdarran {
510*eada09acSchs struct pcb *pcb;
511*eada09acSchs int regmap[] = { /* Order is dependent on reg.d */
512*eada09acSchs REG_GS, /* 0 GS */
513*eada09acSchs REG_FS, /* 1 FS */
514*eada09acSchs REG_ES, /* 2 ES */
515*eada09acSchs REG_DS, /* 3 DS */
516*eada09acSchs REG_RDI, /* 4 EDI */
517*eada09acSchs REG_RSI, /* 5 ESI */
518*eada09acSchs REG_RBP, /* 6 EBP, REG_FP */
519*eada09acSchs REG_RSP, /* 7 ESP */
520*eada09acSchs REG_RBX, /* 8 EBX */
521*eada09acSchs REG_RDX, /* 9 EDX, REG_R1 */
522*eada09acSchs REG_RCX, /* 10 ECX */
523*eada09acSchs REG_RAX, /* 11 EAX, REG_R0 */
524*eada09acSchs REG_TRAPNO, /* 12 TRAPNO */
525*eada09acSchs REG_ERR, /* 13 ERR */
526*eada09acSchs REG_RIP, /* 14 EIP, REG_PC */
527*eada09acSchs REG_CS, /* 15 CS */
528*eada09acSchs REG_RFL, /* 16 EFL, REG_PS */
529*eada09acSchs REG_RSP, /* 17 UESP, REG_SP */
530*eada09acSchs REG_SS /* 18 SS */
531bb8023b5Sdarran };
532bb8023b5Sdarran
533*eada09acSchs if (reg > SS) {
534*eada09acSchs DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
535*eada09acSchs return (0);
536*eada09acSchs }
537*eada09acSchs
538bb8023b5Sdarran if (reg >= sizeof (regmap) / sizeof (int)) {
539bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
540bb8023b5Sdarran return (0);
541bb8023b5Sdarran }
542bb8023b5Sdarran
543bb8023b5Sdarran reg = regmap[reg];
544bb8023b5Sdarran
545bb8023b5Sdarran switch(reg) {
546bb8023b5Sdarran case REG_GS:
547*eada09acSchs #ifdef __FreeBSD__
548*eada09acSchs if ((pcb = curthread->td_pcb) == NULL) {
549*eada09acSchs DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
550*eada09acSchs return (0);
551*eada09acSchs }
552*eada09acSchs return (pcb->pcb_gs);
553*eada09acSchs #endif
554*eada09acSchs #ifdef __NetBSD__
555*eada09acSchs return (rp->tf_gs);
556*eada09acSchs #endif
557*eada09acSchs case REG_FS:
558*eada09acSchs return (rp->tf_fs);
559*eada09acSchs case REG_ES:
560*eada09acSchs return (rp->tf_es);
561*eada09acSchs case REG_DS:
562*eada09acSchs return (rp->tf_ds);
563*eada09acSchs case REG_RDI:
564*eada09acSchs return (rp->tf_edi);
565*eada09acSchs case REG_RSI:
566*eada09acSchs return (rp->tf_esi);
567*eada09acSchs case REG_RBP:
568*eada09acSchs return (rp->tf_ebp);
569bb8023b5Sdarran case REG_RSP:
570*eada09acSchs #ifdef __FreeBSD__
571*eada09acSchs return (rp->tf_isp);
572*eada09acSchs #endif
573*eada09acSchs #ifdef __NetBSD__
574*eada09acSchs return (rp->tf_esp);
575*eada09acSchs #endif
576*eada09acSchs case REG_RBX:
577*eada09acSchs return (rp->tf_ebx);
578*eada09acSchs case REG_RCX:
579*eada09acSchs return (rp->tf_ecx);
580*eada09acSchs case REG_RAX:
581*eada09acSchs return (rp->tf_eax);
582*eada09acSchs case REG_TRAPNO:
583*eada09acSchs return (rp->tf_trapno);
584*eada09acSchs case REG_ERR:
585*eada09acSchs return (rp->tf_err);
586*eada09acSchs case REG_RIP:
587*eada09acSchs return (rp->tf_eip);
588*eada09acSchs case REG_CS:
589*eada09acSchs return (rp->tf_cs);
590*eada09acSchs case REG_RFL:
591*eada09acSchs return (rp->tf_eflags);
592*eada09acSchs #if 0
593*eada09acSchs case REG_RSP:
594*eada09acSchs return (rp->tf_esp);
595*eada09acSchs #endif
596*eada09acSchs case REG_SS:
597*eada09acSchs return (rp->tf_ss);
598bb8023b5Sdarran default:
599bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
600bb8023b5Sdarran return (0);
601bb8023b5Sdarran }
602bb8023b5Sdarran }
603bb8023b5Sdarran
604bb8023b5Sdarran static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)605bb8023b5Sdarran dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
606bb8023b5Sdarran {
607bb8023b5Sdarran ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
608bb8023b5Sdarran
609bb8023b5Sdarran if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
610bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
61101c9547eSdarran cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr;
612bb8023b5Sdarran return (0);
613bb8023b5Sdarran }
614bb8023b5Sdarran
615bb8023b5Sdarran return (1);
616bb8023b5Sdarran }
617bb8023b5Sdarran
618bb8023b5Sdarran void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)619bb8023b5Sdarran dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
620bb8023b5Sdarran volatile uint16_t *flags)
621bb8023b5Sdarran {
622bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
623bb8023b5Sdarran dtrace_copy(uaddr, kaddr, size);
624bb8023b5Sdarran }
625bb8023b5Sdarran
626bb8023b5Sdarran void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)627bb8023b5Sdarran dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
628bb8023b5Sdarran volatile uint16_t *flags)
629bb8023b5Sdarran {
630bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
631bb8023b5Sdarran dtrace_copy(kaddr, uaddr, size);
632bb8023b5Sdarran }
633bb8023b5Sdarran
634bb8023b5Sdarran void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)635bb8023b5Sdarran dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
636bb8023b5Sdarran volatile uint16_t *flags)
637bb8023b5Sdarran {
638bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
639bb8023b5Sdarran dtrace_copystr(uaddr, kaddr, size, flags);
640bb8023b5Sdarran }
641bb8023b5Sdarran
642bb8023b5Sdarran void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)643bb8023b5Sdarran dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
644bb8023b5Sdarran volatile uint16_t *flags)
645bb8023b5Sdarran {
646bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
647bb8023b5Sdarran dtrace_copystr(kaddr, uaddr, size, flags);
648bb8023b5Sdarran }
649bb8023b5Sdarran
650bb8023b5Sdarran uint8_t
dtrace_fuword8(void * uaddr)651bb8023b5Sdarran dtrace_fuword8(void *uaddr)
652bb8023b5Sdarran {
653bb8023b5Sdarran if ((uintptr_t)uaddr >= kernelbase) {
654bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
65501c9547eSdarran cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
656bb8023b5Sdarran return (0);
657bb8023b5Sdarran }
658bb8023b5Sdarran return (dtrace_fuword8_nocheck(uaddr));
659bb8023b5Sdarran }
660bb8023b5Sdarran
661bb8023b5Sdarran uint16_t
dtrace_fuword16(void * uaddr)662bb8023b5Sdarran dtrace_fuword16(void *uaddr)
663bb8023b5Sdarran {
664bb8023b5Sdarran if ((uintptr_t)uaddr >= kernelbase) {
665bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
66601c9547eSdarran cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
667bb8023b5Sdarran return (0);
668bb8023b5Sdarran }
669bb8023b5Sdarran return (dtrace_fuword16_nocheck(uaddr));
670bb8023b5Sdarran }
671bb8023b5Sdarran
672bb8023b5Sdarran uint32_t
dtrace_fuword32(void * uaddr)673bb8023b5Sdarran dtrace_fuword32(void *uaddr)
674bb8023b5Sdarran {
675bb8023b5Sdarran if ((uintptr_t)uaddr >= kernelbase) {
676bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
67701c9547eSdarran cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
678bb8023b5Sdarran return (0);
679bb8023b5Sdarran }
680bb8023b5Sdarran return (dtrace_fuword32_nocheck(uaddr));
681bb8023b5Sdarran }
682bb8023b5Sdarran
683bb8023b5Sdarran uint64_t
dtrace_fuword64(void * uaddr)684bb8023b5Sdarran dtrace_fuword64(void *uaddr)
685bb8023b5Sdarran {
686bb8023b5Sdarran if ((uintptr_t)uaddr >= kernelbase) {
687bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
68801c9547eSdarran cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
689bb8023b5Sdarran return (0);
690bb8023b5Sdarran }
691bb8023b5Sdarran return (dtrace_fuword64_nocheck(uaddr));
692bb8023b5Sdarran }
693