dtrace_isa.c revision 269557
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: stable/10/sys/cddl/dev/dtrace/i386/dtrace_isa.c 269557 2014-08-05 01:53:15Z markj $
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#include <machine/pcb.h>
39#include <machine/stack.h>
40
41#include <vm/vm.h>
42#include <vm/vm_param.h>
43#include <vm/pmap.h>
44
45#include "regset.h"
46
47extern uintptr_t kernbase;
48uintptr_t kernelbase = (uintptr_t) &kernbase;
49
50#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \
51	 ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
52
53uint8_t dtrace_fuword8_nocheck(void *);
54uint16_t dtrace_fuword16_nocheck(void *);
55uint32_t dtrace_fuword32_nocheck(void *);
56uint64_t dtrace_fuword64_nocheck(void *);
57
58void
59dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
60    uint32_t *intrpc)
61{
62	int depth = 0;
63	register_t ebp;
64	struct i386_frame *frame;
65	vm_offset_t callpc;
66	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
67
68	if (intrpc != 0)
69		pcstack[depth++] = (pc_t) intrpc;
70
71	aframes++;
72
73	__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
74
75	frame = (struct i386_frame *)ebp;
76	while (depth < pcstack_limit) {
77		if (!INKERNEL(frame))
78			break;
79
80		callpc = frame->f_retaddr;
81
82		if (!INKERNEL(callpc))
83			break;
84
85		if (aframes > 0) {
86			aframes--;
87			if ((aframes == 0) && (caller != 0)) {
88				pcstack[depth++] = caller;
89			}
90		}
91		else {
92			pcstack[depth++] = callpc;
93		}
94
95		if (frame->f_frame <= frame ||
96		    (vm_offset_t)frame->f_frame >=
97		    (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
98			break;
99		frame = frame->f_frame;
100	}
101
102	for (; depth < pcstack_limit; depth++) {
103		pcstack[depth] = 0;
104	}
105}
106
107static int
108dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
109    uintptr_t sp)
110{
111#ifdef notyet
112	proc_t *p = curproc;
113	uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
114	size_t s1, s2;
115#endif
116	volatile uint16_t *flags =
117	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
118	int ret = 0;
119
120	ASSERT(pcstack == NULL || pcstack_limit > 0);
121
122#ifdef notyet /* XXX signal stack. */
123	if (p->p_model == DATAMODEL_NATIVE) {
124		s1 = sizeof (struct frame) + 2 * sizeof (long);
125		s2 = s1 + sizeof (siginfo_t);
126	} else {
127		s1 = sizeof (struct frame32) + 3 * sizeof (int);
128		s2 = s1 + sizeof (siginfo32_t);
129	}
130#endif
131
132	while (pc != 0) {
133		ret++;
134		if (pcstack != NULL) {
135			*pcstack++ = (uint64_t)pc;
136			pcstack_limit--;
137			if (pcstack_limit <= 0)
138				break;
139		}
140
141		if (sp == 0)
142			break;
143
144#ifdef notyet /* XXX signal stack. */
145		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
146			if (p->p_model == DATAMODEL_NATIVE) {
147				ucontext_t *ucp = (ucontext_t *)oldcontext;
148				greg_t *gregs = ucp->uc_mcontext.gregs;
149
150				sp = dtrace_fulword(&gregs[REG_FP]);
151				pc = dtrace_fulword(&gregs[REG_PC]);
152
153				oldcontext = dtrace_fulword(&ucp->uc_link);
154			} else {
155				ucontext32_t *ucp = (ucontext32_t *)oldcontext;
156				greg32_t *gregs = ucp->uc_mcontext.gregs;
157
158				sp = dtrace_fuword32(&gregs[EBP]);
159				pc = dtrace_fuword32(&gregs[EIP]);
160
161				oldcontext = dtrace_fuword32(&ucp->uc_link);
162			}
163		} else {
164			if (p->p_model == DATAMODEL_NATIVE) {
165				struct frame *fr = (struct frame *)sp;
166
167				pc = dtrace_fulword(&fr->fr_savpc);
168				sp = dtrace_fulword(&fr->fr_savfp);
169			} else {
170				struct frame32 *fr = (struct frame32 *)sp;
171
172				pc = dtrace_fuword32(&fr->fr_savpc);
173				sp = dtrace_fuword32(&fr->fr_savfp);
174			}
175		}
176#else
177		pc = dtrace_fuword32((void *)(sp +
178			offsetof(struct i386_frame, f_retaddr)));
179		sp = dtrace_fuword32((void *)sp);
180#endif /* ! notyet */
181
182		/*
183		 * This is totally bogus:  if we faulted, we're going to clear
184		 * the fault and break.  This is to deal with the apparently
185		 * broken Java stacks on x86.
186		 */
187		if (*flags & CPU_DTRACE_FAULT) {
188			*flags &= ~CPU_DTRACE_FAULT;
189			break;
190		}
191	}
192
193	return (ret);
194}
195
196void
197dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
198{
199	proc_t *p = curproc;
200	struct trapframe *tf;
201	uintptr_t pc, sp, fp;
202	volatile uint16_t *flags =
203	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
204	int n;
205
206	if (*flags & CPU_DTRACE_FAULT)
207		return;
208
209	if (pcstack_limit <= 0)
210		return;
211
212	/*
213	 * If there's no user context we still need to zero the stack.
214	 */
215	if (p == NULL || (tf = curthread->td_frame) == NULL)
216		goto zero;
217
218	*pcstack++ = (uint64_t)p->p_pid;
219	pcstack_limit--;
220
221	if (pcstack_limit <= 0)
222		return;
223
224	pc = tf->tf_eip;
225	fp = tf->tf_ebp;
226	sp = tf->tf_esp;
227
228	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
229		/*
230		 * In an entry probe.  The frame pointer has not yet been
231		 * pushed (that happens in the function prologue).  The
232		 * best approach is to add the current pc as a missing top
233		 * of stack and back the pc up to the caller, which is stored
234		 * at the current stack pointer address since the call
235		 * instruction puts it there right before the branch.
236		 */
237
238		*pcstack++ = (uint64_t)pc;
239		pcstack_limit--;
240		if (pcstack_limit <= 0)
241			return;
242
243		pc = dtrace_fuword32((void *) sp);
244	}
245
246	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
247	ASSERT(n >= 0);
248	ASSERT(n <= pcstack_limit);
249
250	pcstack += n;
251	pcstack_limit -= n;
252
253zero:
254	while (pcstack_limit-- > 0)
255		*pcstack++ = 0;
256}
257
258int
259dtrace_getustackdepth(void)
260{
261	proc_t *p = curproc;
262	struct trapframe *tf;
263	uintptr_t pc, fp, sp;
264	int n = 0;
265
266	if (p == NULL || (tf = curthread->td_frame) == NULL)
267		return (0);
268
269	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
270		return (-1);
271
272	pc = tf->tf_eip;
273	fp = tf->tf_ebp;
274	sp = tf->tf_esp;
275
276	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
277		/*
278		 * In an entry probe.  The frame pointer has not yet been
279		 * pushed (that happens in the function prologue).  The
280		 * best approach is to add the current pc as a missing top
281		 * of stack and back the pc up to the caller, which is stored
282		 * at the current stack pointer address since the call
283		 * instruction puts it there right before the branch.
284		 */
285
286		pc = dtrace_fuword32((void *) sp);
287		n++;
288	}
289
290	n += dtrace_getustack_common(NULL, 0, pc, fp);
291
292	return (n);
293}
294
295void
296dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
297{
298	proc_t *p = curproc;
299	struct trapframe *tf;
300	uintptr_t pc, sp, fp;
301	volatile uint16_t *flags =
302	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
303#ifdef notyet /* XXX signal stack */
304	uintptr_t oldcontext;
305	size_t s1, s2;
306#endif
307
308	if (*flags & CPU_DTRACE_FAULT)
309		return;
310
311	if (pcstack_limit <= 0)
312		return;
313
314	/*
315	 * If there's no user context we still need to zero the stack.
316	 */
317	if (p == NULL || (tf = curthread->td_frame) == NULL)
318		goto zero;
319
320	*pcstack++ = (uint64_t)p->p_pid;
321	pcstack_limit--;
322
323	if (pcstack_limit <= 0)
324		return;
325
326	pc = tf->tf_eip;
327	fp = tf->tf_ebp;
328	sp = tf->tf_esp;
329
330#ifdef notyet /* XXX signal stack */
331	oldcontext = lwp->lwp_oldcontext;
332
333	if (p->p_model == DATAMODEL_NATIVE) {
334		s1 = sizeof (struct frame) + 2 * sizeof (long);
335		s2 = s1 + sizeof (siginfo_t);
336	} else {
337		s1 = sizeof (struct frame32) + 3 * sizeof (int);
338		s2 = s1 + sizeof (siginfo32_t);
339	}
340#endif
341
342	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
343		*pcstack++ = (uint64_t)pc;
344		*fpstack++ = 0;
345		pcstack_limit--;
346		if (pcstack_limit <= 0)
347			return;
348
349		pc = dtrace_fuword32((void *)sp);
350	}
351
352	while (pc != 0) {
353		*pcstack++ = (uint64_t)pc;
354		*fpstack++ = fp;
355		pcstack_limit--;
356		if (pcstack_limit <= 0)
357			break;
358
359		if (fp == 0)
360			break;
361
362#ifdef notyet /* XXX signal stack */
363		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
364			if (p->p_model == DATAMODEL_NATIVE) {
365				ucontext_t *ucp = (ucontext_t *)oldcontext;
366				greg_t *gregs = ucp->uc_mcontext.gregs;
367
368				sp = dtrace_fulword(&gregs[REG_FP]);
369				pc = dtrace_fulword(&gregs[REG_PC]);
370
371				oldcontext = dtrace_fulword(&ucp->uc_link);
372			} else {
373				ucontext_t *ucp = (ucontext_t *)oldcontext;
374				greg_t *gregs = ucp->uc_mcontext.gregs;
375
376				sp = dtrace_fuword32(&gregs[EBP]);
377				pc = dtrace_fuword32(&gregs[EIP]);
378
379				oldcontext = dtrace_fuword32(&ucp->uc_link);
380			}
381		} else
382#endif /* XXX */
383		{
384			pc = dtrace_fuword32((void *)(fp +
385				offsetof(struct i386_frame, f_retaddr)));
386			fp = dtrace_fuword32((void *)fp);
387		}
388
389		/*
390		 * This is totally bogus:  if we faulted, we're going to clear
391		 * the fault and break.  This is to deal with the apparently
392		 * broken Java stacks on x86.
393		 */
394		if (*flags & CPU_DTRACE_FAULT) {
395			*flags &= ~CPU_DTRACE_FAULT;
396			break;
397		}
398	}
399
400zero:
401	while (pcstack_limit-- > 0)
402		*pcstack++ = 0;
403}
404
405uint64_t
406dtrace_getarg(int arg, int aframes)
407{
408	uintptr_t val;
409	struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
410	uintptr_t *stack;
411	int i;
412
413	for (i = 1; i <= aframes; i++) {
414		fp = fp->f_frame;
415
416		if (P2ROUNDUP(fp->f_retaddr, 4) ==
417		    (long)dtrace_invop_callsite) {
418			/*
419			 * If we pass through the invalid op handler, we will
420			 * use the pointer that it passed to the stack as the
421			 * second argument to dtrace_invop() as the pointer to
422			 * the stack.  When using this stack, we must step
423			 * beyond the EIP/RIP that was pushed when the trap was
424			 * taken -- hence the "+ 1" below.
425			 */
426			stack = ((uintptr_t **)&fp[1])[0] + 1;
427			goto load;
428		}
429
430	}
431
432	/*
433	 * We know that we did not come through a trap to get into
434	 * dtrace_probe() -- the provider simply called dtrace_probe()
435	 * directly.  As this is the case, we need to shift the argument
436	 * that we're looking for:  the probe ID is the first argument to
437	 * dtrace_probe(), so the argument n will actually be found where
438	 * one would expect to find argument (n + 1).
439	 */
440	arg++;
441
442	stack = (uintptr_t *)fp + 2;
443
444load:
445	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
446	val = stack[arg];
447	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
448
449	return (val);
450}
451
452int
453dtrace_getstackdepth(int aframes)
454{
455	int depth = 0;
456	struct i386_frame *frame;
457	vm_offset_t ebp;
458
459	aframes++;
460	ebp = dtrace_getfp();
461	frame = (struct i386_frame *)ebp;
462	depth++;
463	for(;;) {
464		if (!INKERNEL((long) frame))
465			break;
466		if (!INKERNEL((long) frame->f_frame))
467			break;
468		depth++;
469		if (frame->f_frame <= frame ||
470		    (vm_offset_t)frame->f_frame >=
471		    (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
472			break;
473		frame = frame->f_frame;
474	}
475	if (depth < aframes)
476		return 0;
477	else
478		return depth - aframes;
479}
480
481ulong_t
482dtrace_getreg(struct trapframe *rp, uint_t reg)
483{
484	struct pcb *pcb;
485	int regmap[] = {  /* Order is dependent on reg.d */
486		REG_GS,		/* 0  GS */
487		REG_FS,		/* 1  FS */
488		REG_ES,		/* 2  ES */
489		REG_DS,		/* 3  DS */
490		REG_RDI,	/* 4  EDI */
491		REG_RSI,	/* 5  ESI */
492		REG_RBP,	/* 6  EBP, REG_FP */
493		REG_RSP,	/* 7  ESP */
494		REG_RBX,	/* 8  EBX */
495		REG_RDX,	/* 9  EDX, REG_R1 */
496		REG_RCX,	/* 10 ECX */
497		REG_RAX,	/* 11 EAX, REG_R0 */
498		REG_TRAPNO,	/* 12 TRAPNO */
499		REG_ERR,	/* 13 ERR */
500		REG_RIP,	/* 14 EIP, REG_PC */
501		REG_CS,		/* 15 CS */
502		REG_RFL,	/* 16 EFL, REG_PS */
503		REG_RSP,	/* 17 UESP, REG_SP */
504		REG_SS		/* 18 SS */
505	};
506
507	if (reg > SS) {
508		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
509		return (0);
510	}
511
512	if (reg >= sizeof (regmap) / sizeof (int)) {
513		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
514		return (0);
515	}
516
517	reg = regmap[reg];
518
519	switch(reg) {
520	case REG_GS:
521		if ((pcb = curthread->td_pcb) == NULL) {
522			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
523			return (0);
524		}
525		return (pcb->pcb_gs);
526	case REG_FS:
527		return (rp->tf_fs);
528	case REG_ES:
529		return (rp->tf_es);
530	case REG_DS:
531		return (rp->tf_ds);
532	case REG_RDI:
533		return (rp->tf_edi);
534	case REG_RSI:
535		return (rp->tf_esi);
536	case REG_RBP:
537		return (rp->tf_ebp);
538	case REG_RSP:
539		return (rp->tf_isp);
540	case REG_RBX:
541		return (rp->tf_ebx);
542	case REG_RCX:
543		return (rp->tf_ecx);
544	case REG_RAX:
545		return (rp->tf_eax);
546	case REG_TRAPNO:
547		return (rp->tf_trapno);
548	case REG_ERR:
549		return (rp->tf_err);
550	case REG_RIP:
551		return (rp->tf_eip);
552	case REG_CS:
553		return (rp->tf_cs);
554	case REG_RFL:
555		return (rp->tf_eflags);
556#if 0
557	case REG_RSP:
558		return (rp->tf_esp);
559#endif
560	case REG_SS:
561		return (rp->tf_ss);
562	default:
563		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
564		return (0);
565	}
566}
567
568static int
569dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
570{
571	ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
572
573	if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
574		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
575		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
576		return (0);
577	}
578
579	return (1);
580}
581
582void
583dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
584    volatile uint16_t *flags)
585{
586	if (dtrace_copycheck(uaddr, kaddr, size))
587		dtrace_copy(uaddr, kaddr, size);
588}
589
590void
591dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
592    volatile uint16_t *flags)
593{
594	if (dtrace_copycheck(uaddr, kaddr, size))
595		dtrace_copy(kaddr, uaddr, size);
596}
597
598void
599dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
600    volatile uint16_t *flags)
601{
602	if (dtrace_copycheck(uaddr, kaddr, size))
603		dtrace_copystr(uaddr, kaddr, size, flags);
604}
605
606void
607dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
608    volatile uint16_t *flags)
609{
610	if (dtrace_copycheck(uaddr, kaddr, size))
611		dtrace_copystr(kaddr, uaddr, size, flags);
612}
613
614uint8_t
615dtrace_fuword8(void *uaddr)
616{
617	if ((uintptr_t)uaddr >= kernelbase) {
618		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
619		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
620		return (0);
621	}
622	return (dtrace_fuword8_nocheck(uaddr));
623}
624
625uint16_t
626dtrace_fuword16(void *uaddr)
627{
628	if ((uintptr_t)uaddr >= kernelbase) {
629		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
630		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
631		return (0);
632	}
633	return (dtrace_fuword16_nocheck(uaddr));
634}
635
636uint32_t
637dtrace_fuword32(void *uaddr)
638{
639	if ((uintptr_t)uaddr >= kernelbase) {
640		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
641		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
642		return (0);
643	}
644	return (dtrace_fuword32_nocheck(uaddr));
645}
646
647uint64_t
648dtrace_fuword64(void *uaddr)
649{
650	if ((uintptr_t)uaddr >= kernelbase) {
651		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
652		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
653		return (0);
654	}
655	return (dtrace_fuword64_nocheck(uaddr));
656}
657