1*affd5374Schristos /* $NetBSD: dtrace_isa.c,v 1.10 2018/08/16 14:14:51 christos 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 *
24eada09acSchs * $FreeBSD: head/sys/cddl/dev/dtrace/amd64/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
36bb8023b5Sdarran #include <machine/frame.h>
37bb8023b5Sdarran #include <machine/reg.h>
38bb8023b5Sdarran
39958e171bSchristos #include <machine/vmparam.h>
40bb8023b5Sdarran
41eada09acSchs #include "regset.h"
42eada09acSchs
43bb8023b5Sdarran uint8_t dtrace_fuword8_nocheck(void *);
44bb8023b5Sdarran uint16_t dtrace_fuword16_nocheck(void *);
45bb8023b5Sdarran uint32_t dtrace_fuword32_nocheck(void *);
46bb8023b5Sdarran uint64_t dtrace_fuword64_nocheck(void *);
47bb8023b5Sdarran
48ea15ab1fSmaxv #define INKERNEL(va) ((intptr_t)(va) < 0) /* XXX horror */
49958e171bSchristos
50958e171bSchristos struct amd64_frame {
51958e171bSchristos struct amd64_frame *f_frame;
5231e28111Schs uintptr_t f_retaddr;
53958e171bSchristos };
54958e171bSchristos
55958e171bSchristos typedef unsigned long vm_offset_t;
56958e171bSchristos
57eada09acSchs int dtrace_ustackdepth_max = 2048;
58eada09acSchs
59bb8023b5Sdarran void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)60bb8023b5Sdarran dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
61bb8023b5Sdarran uint32_t *intrpc)
62bb8023b5Sdarran {
63bb8023b5Sdarran int depth = 0;
64bb8023b5Sdarran register_t rbp;
65bb8023b5Sdarran struct amd64_frame *frame;
66bb8023b5Sdarran vm_offset_t callpc;
67958e171bSchristos pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller;
68bb8023b5Sdarran
69bb8023b5Sdarran if (intrpc != 0)
70bb8023b5Sdarran pcstack[depth++] = (pc_t) intrpc;
71bb8023b5Sdarran
72bb8023b5Sdarran aframes++;
73bb8023b5Sdarran
74bb8023b5Sdarran __asm __volatile("movq %%rbp,%0" : "=r" (rbp));
75bb8023b5Sdarran
76bb8023b5Sdarran frame = (struct amd64_frame *)rbp;
77bb8023b5Sdarran while (depth < pcstack_limit) {
78bb8023b5Sdarran if (!INKERNEL((long) frame))
79bb8023b5Sdarran break;
80bb8023b5Sdarran
81bb8023b5Sdarran callpc = frame->f_retaddr;
82bb8023b5Sdarran
83bb8023b5Sdarran if (!INKERNEL(callpc))
84bb8023b5Sdarran break;
85bb8023b5Sdarran
86bb8023b5Sdarran if (aframes > 0) {
87bb8023b5Sdarran aframes--;
88bb8023b5Sdarran if ((aframes == 0) && (caller != 0)) {
89bb8023b5Sdarran pcstack[depth++] = caller;
90bb8023b5Sdarran }
91bb8023b5Sdarran }
92bb8023b5Sdarran else {
93bb8023b5Sdarran pcstack[depth++] = callpc;
94bb8023b5Sdarran }
95bb8023b5Sdarran
96bb8023b5Sdarran if (frame->f_frame <= frame ||
97bb8023b5Sdarran (vm_offset_t)frame->f_frame >=
98958e171bSchristos (vm_offset_t)rbp + KSTACK_SIZE)
99bb8023b5Sdarran break;
100bb8023b5Sdarran frame = frame->f_frame;
101bb8023b5Sdarran }
102bb8023b5Sdarran
103bb8023b5Sdarran for (; depth < pcstack_limit; depth++) {
104bb8023b5Sdarran pcstack[depth] = 0;
105bb8023b5Sdarran }
106bb8023b5Sdarran }
107bb8023b5Sdarran
108bb8023b5Sdarran static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)109bb8023b5Sdarran dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
110bb8023b5Sdarran uintptr_t sp)
111bb8023b5Sdarran {
112eada09acSchs uintptr_t oldsp;
113bb8023b5Sdarran volatile uint16_t *flags =
114958e171bSchristos (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
115bb8023b5Sdarran int ret = 0;
116bb8023b5Sdarran
117bb8023b5Sdarran ASSERT(pcstack == NULL || pcstack_limit > 0);
118eada09acSchs ASSERT(dtrace_ustackdepth_max > 0);
119bb8023b5Sdarran
12080dd0070Schs while (pc != 0) {
121eada09acSchs /*
122eada09acSchs * We limit the number of times we can go around this
123eada09acSchs * loop to account for a circular stack.
124eada09acSchs */
125eada09acSchs if (ret++ >= dtrace_ustackdepth_max) {
126eada09acSchs *flags |= CPU_DTRACE_BADSTACK;
127eada09acSchs cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
128eada09acSchs break;
129eada09acSchs }
130eada09acSchs
131bb8023b5Sdarran if (pcstack != NULL) {
132bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
133bb8023b5Sdarran pcstack_limit--;
134bb8023b5Sdarran if (pcstack_limit <= 0)
135bb8023b5Sdarran break;
136bb8023b5Sdarran }
137bb8023b5Sdarran
13880dd0070Schs if (sp == 0)
13980dd0070Schs break;
140bb8023b5Sdarran
141eada09acSchs oldsp = sp;
142eada09acSchs
14380dd0070Schs pc = dtrace_fuword64((void *)(sp +
14480dd0070Schs offsetof(struct amd64_frame, f_retaddr)));
14580dd0070Schs sp = dtrace_fuword64((void *)sp);
146bb8023b5Sdarran
147eada09acSchs if (sp == oldsp) {
148eada09acSchs *flags |= CPU_DTRACE_BADSTACK;
149eada09acSchs cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
150eada09acSchs break;
151eada09acSchs }
152eada09acSchs
153bb8023b5Sdarran /*
154bb8023b5Sdarran * This is totally bogus: if we faulted, we're going to clear
155bb8023b5Sdarran * the fault and break. This is to deal with the apparently
156bb8023b5Sdarran * broken Java stacks on x86.
157bb8023b5Sdarran */
158bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT) {
159bb8023b5Sdarran *flags &= ~CPU_DTRACE_FAULT;
160bb8023b5Sdarran break;
161bb8023b5Sdarran }
162bb8023b5Sdarran }
163bb8023b5Sdarran
164bb8023b5Sdarran return (ret);
165bb8023b5Sdarran }
166bb8023b5Sdarran
167bb8023b5Sdarran void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)168bb8023b5Sdarran dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
169bb8023b5Sdarran {
170bb8023b5Sdarran proc_t *p = curproc;
17180dd0070Schs struct trapframe *tf;
17280dd0070Schs uintptr_t pc, sp, fp;
173bb8023b5Sdarran volatile uint16_t *flags =
174958e171bSchristos (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
175bb8023b5Sdarran int n;
176bb8023b5Sdarran
177bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT)
178bb8023b5Sdarran return;
179bb8023b5Sdarran
180bb8023b5Sdarran if (pcstack_limit <= 0)
181bb8023b5Sdarran return;
182bb8023b5Sdarran
183bb8023b5Sdarran /*
184bb8023b5Sdarran * If there's no user context we still need to zero the stack.
185bb8023b5Sdarran */
18680dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
187bb8023b5Sdarran goto zero;
188bb8023b5Sdarran
189bb8023b5Sdarran *pcstack++ = (uint64_t)p->p_pid;
190bb8023b5Sdarran pcstack_limit--;
191bb8023b5Sdarran
192bb8023b5Sdarran if (pcstack_limit <= 0)
193bb8023b5Sdarran return;
194bb8023b5Sdarran
19580dd0070Schs pc = tf->tf_rip;
19680dd0070Schs fp = tf->tf_rbp;
19780dd0070Schs sp = tf->tf_rsp;
198bb8023b5Sdarran
199bb8023b5Sdarran if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
20080dd0070Schs /*
20180dd0070Schs * In an entry probe. The frame pointer has not yet been
20280dd0070Schs * pushed (that happens in the function prologue). The
20380dd0070Schs * best approach is to add the current pc as a missing top
20480dd0070Schs * of stack and back the pc up to the caller, which is stored
20580dd0070Schs * at the current stack pointer address since the call
20680dd0070Schs * instruction puts it there right before the branch.
20780dd0070Schs */
20880dd0070Schs
209bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
210bb8023b5Sdarran pcstack_limit--;
211bb8023b5Sdarran if (pcstack_limit <= 0)
212bb8023b5Sdarran return;
213bb8023b5Sdarran
21480dd0070Schs pc = dtrace_fuword64((void *) sp);
215bb8023b5Sdarran }
216bb8023b5Sdarran
21780dd0070Schs n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
218bb8023b5Sdarran ASSERT(n >= 0);
219bb8023b5Sdarran ASSERT(n <= pcstack_limit);
220bb8023b5Sdarran
221bb8023b5Sdarran pcstack += n;
222bb8023b5Sdarran pcstack_limit -= n;
223bb8023b5Sdarran
224bb8023b5Sdarran zero:
225bb8023b5Sdarran while (pcstack_limit-- > 0)
226bb8023b5Sdarran *pcstack++ = 0;
227bb8023b5Sdarran }
228bb8023b5Sdarran
229bb8023b5Sdarran int
dtrace_getustackdepth(void)230bb8023b5Sdarran dtrace_getustackdepth(void)
231bb8023b5Sdarran {
23280dd0070Schs proc_t *p = curproc;
23380dd0070Schs struct trapframe *tf;
23480dd0070Schs uintptr_t pc, fp, sp;
23580dd0070Schs int n = 0;
23680dd0070Schs
23780dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
23880dd0070Schs return (0);
23980dd0070Schs
24080dd0070Schs if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
24180dd0070Schs return (-1);
24280dd0070Schs
24380dd0070Schs pc = tf->tf_rip;
24480dd0070Schs fp = tf->tf_rbp;
24580dd0070Schs sp = tf->tf_rsp;
24680dd0070Schs
24780dd0070Schs if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
24880dd0070Schs /*
24980dd0070Schs * In an entry probe. The frame pointer has not yet been
25080dd0070Schs * pushed (that happens in the function prologue). The
25180dd0070Schs * best approach is to add the current pc as a missing top
25280dd0070Schs * of stack and back the pc up to the caller, which is stored
25380dd0070Schs * at the current stack pointer address since the call
25480dd0070Schs * instruction puts it there right before the branch.
25580dd0070Schs */
25680dd0070Schs
25780dd0070Schs pc = dtrace_fuword64((void *) sp);
25880dd0070Schs n++;
25980dd0070Schs }
26080dd0070Schs
26180dd0070Schs n += dtrace_getustack_common(NULL, 0, pc, fp);
26280dd0070Schs
26380dd0070Schs return (n);
264bb8023b5Sdarran }
265bb8023b5Sdarran
266bb8023b5Sdarran void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)267bb8023b5Sdarran dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
268bb8023b5Sdarran {
269bb8023b5Sdarran proc_t *p = curproc;
27080dd0070Schs struct trapframe *tf;
27180dd0070Schs uintptr_t pc, sp, fp;
272bb8023b5Sdarran volatile uint16_t *flags =
273958e171bSchristos (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
27480dd0070Schs #ifdef notyet /* XXX signal stack */
27580dd0070Schs uintptr_t oldcontext;
276bb8023b5Sdarran size_t s1, s2;
27780dd0070Schs #endif
278bb8023b5Sdarran
279bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT)
280bb8023b5Sdarran return;
281bb8023b5Sdarran
282bb8023b5Sdarran if (pcstack_limit <= 0)
283bb8023b5Sdarran return;
284bb8023b5Sdarran
285bb8023b5Sdarran /*
286bb8023b5Sdarran * If there's no user context we still need to zero the stack.
287bb8023b5Sdarran */
28880dd0070Schs if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
289bb8023b5Sdarran goto zero;
290bb8023b5Sdarran
291bb8023b5Sdarran *pcstack++ = (uint64_t)p->p_pid;
292bb8023b5Sdarran pcstack_limit--;
293bb8023b5Sdarran
294bb8023b5Sdarran if (pcstack_limit <= 0)
295bb8023b5Sdarran return;
296bb8023b5Sdarran
29780dd0070Schs pc = tf->tf_rip;
29880dd0070Schs sp = tf->tf_rsp;
29980dd0070Schs fp = tf->tf_rbp;
300bb8023b5Sdarran
30180dd0070Schs #ifdef notyet /* XXX signal stack */
30280dd0070Schs oldcontext = lwp->lwp_oldcontext;
303bb8023b5Sdarran s1 = sizeof (struct xframe) + 2 * sizeof (long);
304bb8023b5Sdarran s2 = s1 + sizeof (siginfo_t);
30580dd0070Schs #endif
306bb8023b5Sdarran
307bb8023b5Sdarran if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
308bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
309bb8023b5Sdarran *fpstack++ = 0;
310bb8023b5Sdarran pcstack_limit--;
311bb8023b5Sdarran if (pcstack_limit <= 0)
312bb8023b5Sdarran return;
313bb8023b5Sdarran
31480dd0070Schs pc = dtrace_fuword64((void *)sp);
315bb8023b5Sdarran }
316bb8023b5Sdarran
31780dd0070Schs while (pc != 0) {
318bb8023b5Sdarran *pcstack++ = (uint64_t)pc;
31980dd0070Schs *fpstack++ = fp;
320bb8023b5Sdarran pcstack_limit--;
321bb8023b5Sdarran if (pcstack_limit <= 0)
322bb8023b5Sdarran break;
323bb8023b5Sdarran
32480dd0070Schs if (fp == 0)
32580dd0070Schs break;
32680dd0070Schs
32780dd0070Schs #ifdef notyet /* XXX signal stack */
328bb8023b5Sdarran if (oldcontext == sp + s1 || oldcontext == sp + s2) {
329bb8023b5Sdarran ucontext_t *ucp = (ucontext_t *)oldcontext;
330bb8023b5Sdarran greg_t *gregs = ucp->uc_mcontext.gregs;
331bb8023b5Sdarran
332bb8023b5Sdarran sp = dtrace_fulword(&gregs[REG_FP]);
333bb8023b5Sdarran pc = dtrace_fulword(&gregs[REG_PC]);
334bb8023b5Sdarran
335bb8023b5Sdarran oldcontext = dtrace_fulword(&ucp->uc_link);
33680dd0070Schs } else
33780dd0070Schs #endif /* XXX */
33880dd0070Schs {
33980dd0070Schs pc = dtrace_fuword64((void *)(fp +
34080dd0070Schs offsetof(struct amd64_frame, f_retaddr)));
34180dd0070Schs fp = dtrace_fuword64((void *)fp);
342bb8023b5Sdarran }
343bb8023b5Sdarran
344bb8023b5Sdarran /*
345bb8023b5Sdarran * This is totally bogus: if we faulted, we're going to clear
346bb8023b5Sdarran * the fault and break. This is to deal with the apparently
347bb8023b5Sdarran * broken Java stacks on x86.
348bb8023b5Sdarran */
349bb8023b5Sdarran if (*flags & CPU_DTRACE_FAULT) {
350bb8023b5Sdarran *flags &= ~CPU_DTRACE_FAULT;
351bb8023b5Sdarran break;
352bb8023b5Sdarran }
353bb8023b5Sdarran }
354bb8023b5Sdarran
355bb8023b5Sdarran zero:
356bb8023b5Sdarran while (pcstack_limit-- > 0)
35780dd0070Schs *pcstack++ = 0;
358bb8023b5Sdarran }
359bb8023b5Sdarran
360bb8023b5Sdarran /*ARGSUSED*/
361bb8023b5Sdarran uint64_t
dtrace_getarg(int arg,int aframes)362bb8023b5Sdarran dtrace_getarg(int arg, int aframes)
363bb8023b5Sdarran {
364bb8023b5Sdarran uintptr_t val;
365bb8023b5Sdarran struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp();
366bb8023b5Sdarran uintptr_t *stack;
367bb8023b5Sdarran int i;
368bb8023b5Sdarran
369bb8023b5Sdarran /*
370bb8023b5Sdarran * A total of 6 arguments are passed via registers; any argument with
371bb8023b5Sdarran * index of 5 or lower is therefore in a register.
372bb8023b5Sdarran */
373bb8023b5Sdarran int inreg = 5;
374bb8023b5Sdarran
375bb8023b5Sdarran for (i = 1; i <= aframes; i++) {
376bb8023b5Sdarran fp = fp->f_frame;
377bb8023b5Sdarran
3780fa27af2Schs if (P2ROUNDUP(fp->f_retaddr, 16) ==
3790fa27af2Schs (long)dtrace_invop_callsite) {
380bb8023b5Sdarran /*
381bb8023b5Sdarran * In the case of amd64, we will use the pointer to the
382bb8023b5Sdarran * regs structure that was pushed when we took the
383bb8023b5Sdarran * trap. To get this structure, we must increment
384bb8023b5Sdarran * beyond the frame structure, and then again beyond
385bb8023b5Sdarran * the calling RIP stored in dtrace_invop(). If the
386bb8023b5Sdarran * argument that we're seeking is passed on the stack,
387bb8023b5Sdarran * we'll pull the true stack pointer out of the saved
388bb8023b5Sdarran * registers and decrement our argument by the number
389bb8023b5Sdarran * of arguments passed in registers; if the argument
39080dd0070Schs * we're seeking is passed in registers, we can just
391bb8023b5Sdarran * load it directly.
392bb8023b5Sdarran */
3930fa27af2Schs struct trapframe *tf = (struct trapframe *)&fp[1];
394bb8023b5Sdarran
395bb8023b5Sdarran if (arg <= inreg) {
3960fa27af2Schs switch (arg) {
3970fa27af2Schs case 0:
3980fa27af2Schs stack = (uintptr_t *)&tf->tf_rdi;
3990fa27af2Schs break;
4000fa27af2Schs case 1:
4010fa27af2Schs stack = (uintptr_t *)&tf->tf_rsi;
4020fa27af2Schs break;
4030fa27af2Schs case 2:
4040fa27af2Schs stack = (uintptr_t *)&tf->tf_rdx;
4050fa27af2Schs break;
4060fa27af2Schs case 3:
4070fa27af2Schs stack = (uintptr_t *)&tf->tf_rcx;
4080fa27af2Schs break;
4090fa27af2Schs case 4:
4100fa27af2Schs stack = (uintptr_t *)&tf->tf_r8;
4110fa27af2Schs break;
4120fa27af2Schs case 5:
4130fa27af2Schs stack = (uintptr_t *)&tf->tf_r9;
4140fa27af2Schs break;
4150fa27af2Schs default:
4160fa27af2Schs KASSERT(0);
4170fa27af2Schs stack = NULL;
4180fa27af2Schs break;
4190fa27af2Schs }
4200fa27af2Schs arg = 0;
421bb8023b5Sdarran } else {
4220fa27af2Schs stack = (uintptr_t *)(tf->tf_rsp);
423bb8023b5Sdarran arg -= inreg;
424bb8023b5Sdarran }
425bb8023b5Sdarran goto load;
426bb8023b5Sdarran }
427bb8023b5Sdarran
428bb8023b5Sdarran }
429bb8023b5Sdarran
430bb8023b5Sdarran /*
431bb8023b5Sdarran * We know that we did not come through a trap to get into
432bb8023b5Sdarran * dtrace_probe() -- the provider simply called dtrace_probe()
433bb8023b5Sdarran * directly. As this is the case, we need to shift the argument
434bb8023b5Sdarran * that we're looking for: the probe ID is the first argument to
435bb8023b5Sdarran * dtrace_probe(), so the argument n will actually be found where
436bb8023b5Sdarran * one would expect to find argument (n + 1).
437bb8023b5Sdarran */
438bb8023b5Sdarran arg++;
439bb8023b5Sdarran
440bb8023b5Sdarran if (arg <= inreg) {
441bb8023b5Sdarran /*
442bb8023b5Sdarran * This shouldn't happen. If the argument is passed in a
443bb8023b5Sdarran * register then it should have been, well, passed in a
444bb8023b5Sdarran * register...
445bb8023b5Sdarran */
446bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
447bb8023b5Sdarran return (0);
448bb8023b5Sdarran }
449bb8023b5Sdarran
450bb8023b5Sdarran arg -= (inreg + 1);
451bb8023b5Sdarran stack = (uintptr_t *)&fp[1];
452bb8023b5Sdarran
453bb8023b5Sdarran load:
454bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
455bb8023b5Sdarran val = stack[arg];
456bb8023b5Sdarran DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
457bb8023b5Sdarran
458bb8023b5Sdarran return (val);
459bb8023b5Sdarran return (0);
460bb8023b5Sdarran }
461bb8023b5Sdarran
462bb8023b5Sdarran int
dtrace_getstackdepth(int aframes)463bb8023b5Sdarran dtrace_getstackdepth(int aframes)
464bb8023b5Sdarran {
465bb8023b5Sdarran int depth = 0;
466bb8023b5Sdarran struct amd64_frame *frame;
467bb8023b5Sdarran vm_offset_t rbp;
468bb8023b5Sdarran
469bb8023b5Sdarran aframes++;
470bb8023b5Sdarran rbp = dtrace_getfp();
471bb8023b5Sdarran frame = (struct amd64_frame *)rbp;
472bb8023b5Sdarran depth++;
473bb8023b5Sdarran for(;;) {
474bb8023b5Sdarran if (!INKERNEL((long) frame))
475bb8023b5Sdarran break;
476bb8023b5Sdarran if (!INKERNEL((long) frame->f_frame))
477bb8023b5Sdarran break;
478bb8023b5Sdarran depth++;
479bb8023b5Sdarran if (frame->f_frame <= frame ||
480bb8023b5Sdarran (vm_offset_t)frame->f_frame >=
481958e171bSchristos (vm_offset_t)rbp + KSTACK_SIZE)
482bb8023b5Sdarran break;
483bb8023b5Sdarran frame = frame->f_frame;
484bb8023b5Sdarran }
485bb8023b5Sdarran if (depth < aframes)
486bb8023b5Sdarran return 0;
487bb8023b5Sdarran else
488bb8023b5Sdarran return depth - aframes;
489bb8023b5Sdarran }
490bb8023b5Sdarran
491bb8023b5Sdarran ulong_t
dtrace_getreg(struct trapframe * rp,uint_t reg)492eada09acSchs dtrace_getreg(struct trapframe *rp, uint_t reg)
493bb8023b5Sdarran {
494bb8023b5Sdarran int regmap[] = {
495bb8023b5Sdarran REG_GS, /* GS */
496bb8023b5Sdarran REG_FS, /* FS */
497bb8023b5Sdarran REG_ES, /* ES */
498bb8023b5Sdarran REG_DS, /* DS */
499bb8023b5Sdarran REG_RDI, /* EDI */
500bb8023b5Sdarran REG_RSI, /* ESI */
501bb8023b5Sdarran REG_RBP, /* EBP */
502bb8023b5Sdarran REG_RSP, /* ESP */
503bb8023b5Sdarran REG_RBX, /* EBX */
504bb8023b5Sdarran REG_RDX, /* EDX */
505bb8023b5Sdarran REG_RCX, /* ECX */
506bb8023b5Sdarran REG_RAX, /* EAX */
507bb8023b5Sdarran REG_TRAPNO, /* TRAPNO */
508bb8023b5Sdarran REG_ERR, /* ERR */
509bb8023b5Sdarran REG_RIP, /* EIP */
510bb8023b5Sdarran REG_CS, /* CS */
511bb8023b5Sdarran REG_RFL, /* EFL */
512bb8023b5Sdarran REG_RSP, /* UESP */
513bb8023b5Sdarran REG_SS /* SS */
514bb8023b5Sdarran };
515bb8023b5Sdarran
516bb8023b5Sdarran if (reg <= SS) {
517bb8023b5Sdarran if (reg >= sizeof (regmap) / sizeof (int)) {
518bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
519bb8023b5Sdarran return (0);
520bb8023b5Sdarran }
521bb8023b5Sdarran
522bb8023b5Sdarran reg = regmap[reg];
523bb8023b5Sdarran } else {
524bb8023b5Sdarran reg -= SS + 1;
525bb8023b5Sdarran }
526bb8023b5Sdarran
527bb8023b5Sdarran switch (reg) {
528bb8023b5Sdarran case REG_RDI:
529eada09acSchs return (rp->tf_rdi);
530bb8023b5Sdarran case REG_RSI:
531eada09acSchs return (rp->tf_rsi);
532bb8023b5Sdarran case REG_RDX:
533eada09acSchs return (rp->tf_rdx);
534bb8023b5Sdarran case REG_RCX:
535eada09acSchs return (rp->tf_rcx);
536bb8023b5Sdarran case REG_R8:
537eada09acSchs return (rp->tf_r8);
538bb8023b5Sdarran case REG_R9:
539eada09acSchs return (rp->tf_r9);
540bb8023b5Sdarran case REG_RAX:
541eada09acSchs return (rp->tf_rax);
542bb8023b5Sdarran case REG_RBX:
543eada09acSchs return (rp->tf_rbx);
544bb8023b5Sdarran case REG_RBP:
545eada09acSchs return (rp->tf_rbp);
546bb8023b5Sdarran case REG_R10:
547eada09acSchs return (rp->tf_r10);
548bb8023b5Sdarran case REG_R11:
549eada09acSchs return (rp->tf_r11);
550bb8023b5Sdarran case REG_R12:
551eada09acSchs return (rp->tf_r12);
552bb8023b5Sdarran case REG_R13:
553eada09acSchs return (rp->tf_r13);
554bb8023b5Sdarran case REG_R14:
555eada09acSchs return (rp->tf_r14);
556bb8023b5Sdarran case REG_R15:
557eada09acSchs return (rp->tf_r15);
558bb8023b5Sdarran case REG_DS:
559eada09acSchs return (rp->tf_ds);
560bb8023b5Sdarran case REG_ES:
561eada09acSchs return (rp->tf_es);
562bb8023b5Sdarran case REG_FS:
563eada09acSchs return (rp->tf_fs);
564bb8023b5Sdarran case REG_GS:
565eada09acSchs return (rp->tf_gs);
566bb8023b5Sdarran case REG_TRAPNO:
567eada09acSchs return (rp->tf_trapno);
568bb8023b5Sdarran case REG_ERR:
569eada09acSchs return (rp->tf_err);
570bb8023b5Sdarran case REG_RIP:
571eada09acSchs return (rp->tf_rip);
572bb8023b5Sdarran case REG_CS:
573eada09acSchs return (rp->tf_cs);
574bb8023b5Sdarran case REG_SS:
575eada09acSchs return (rp->tf_ss);
576bb8023b5Sdarran case REG_RFL:
577eada09acSchs return (rp->tf_rflags);
578bb8023b5Sdarran case REG_RSP:
579eada09acSchs return (rp->tf_rsp);
580bb8023b5Sdarran default:
581bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
582bb8023b5Sdarran return (0);
583bb8023b5Sdarran }
584bb8023b5Sdarran }
585bb8023b5Sdarran
586bb8023b5Sdarran static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)587bb8023b5Sdarran dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
588bb8023b5Sdarran {
589bb8023b5Sdarran ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
590bb8023b5Sdarran
591bb8023b5Sdarran if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
592bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
593958e171bSchristos cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr;
594bb8023b5Sdarran return (0);
595bb8023b5Sdarran }
596bb8023b5Sdarran
597bb8023b5Sdarran return (1);
598bb8023b5Sdarran }
599bb8023b5Sdarran
600bb8023b5Sdarran void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)601bb8023b5Sdarran dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
602bb8023b5Sdarran volatile uint16_t *flags)
603bb8023b5Sdarran {
604bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
605bb8023b5Sdarran dtrace_copy(uaddr, kaddr, size);
606bb8023b5Sdarran }
607bb8023b5Sdarran
608bb8023b5Sdarran void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)609bb8023b5Sdarran dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
610bb8023b5Sdarran volatile uint16_t *flags)
611bb8023b5Sdarran {
612bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
613bb8023b5Sdarran dtrace_copy(kaddr, uaddr, size);
614bb8023b5Sdarran }
615bb8023b5Sdarran
616bb8023b5Sdarran void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)617bb8023b5Sdarran dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
618bb8023b5Sdarran volatile uint16_t *flags)
619bb8023b5Sdarran {
620bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
621bb8023b5Sdarran dtrace_copystr(uaddr, kaddr, size, flags);
622bb8023b5Sdarran }
623bb8023b5Sdarran
624bb8023b5Sdarran void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)625bb8023b5Sdarran dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
626bb8023b5Sdarran volatile uint16_t *flags)
627bb8023b5Sdarran {
628bb8023b5Sdarran if (dtrace_copycheck(uaddr, kaddr, size))
629bb8023b5Sdarran dtrace_copystr(kaddr, uaddr, size, flags);
630bb8023b5Sdarran }
631bb8023b5Sdarran
632bb8023b5Sdarran uint8_t
dtrace_fuword8(void * uaddr)633bb8023b5Sdarran dtrace_fuword8(void *uaddr)
634bb8023b5Sdarran {
635bb8023b5Sdarran if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
636bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
637958e171bSchristos cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
638bb8023b5Sdarran return (0);
639bb8023b5Sdarran }
640bb8023b5Sdarran return (dtrace_fuword8_nocheck(uaddr));
641bb8023b5Sdarran }
642bb8023b5Sdarran
643bb8023b5Sdarran uint16_t
dtrace_fuword16(void * uaddr)644bb8023b5Sdarran dtrace_fuword16(void *uaddr)
645bb8023b5Sdarran {
646bb8023b5Sdarran if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
647bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
648958e171bSchristos cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
649bb8023b5Sdarran return (0);
650bb8023b5Sdarran }
651bb8023b5Sdarran return (dtrace_fuword16_nocheck(uaddr));
652bb8023b5Sdarran }
653bb8023b5Sdarran
654bb8023b5Sdarran uint32_t
dtrace_fuword32(void * uaddr)655bb8023b5Sdarran dtrace_fuword32(void *uaddr)
656bb8023b5Sdarran {
657bb8023b5Sdarran if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
658bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
659958e171bSchristos cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
660bb8023b5Sdarran return (0);
661bb8023b5Sdarran }
662bb8023b5Sdarran return (dtrace_fuword32_nocheck(uaddr));
663bb8023b5Sdarran }
664bb8023b5Sdarran
665bb8023b5Sdarran uint64_t
dtrace_fuword64(void * uaddr)666bb8023b5Sdarran dtrace_fuword64(void *uaddr)
667bb8023b5Sdarran {
668bb8023b5Sdarran if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
669bb8023b5Sdarran DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
670958e171bSchristos cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
671bb8023b5Sdarran return (0);
672bb8023b5Sdarran }
673bb8023b5Sdarran return (dtrace_fuword64_nocheck(uaddr));
674bb8023b5Sdarran }
675