dtrace_isa.c revision 286396
1117397Skan/*
2117397Skan * CDDL HEADER START
3169691Skan *
4169691Skan * The contents of this file are subject to the terms of the
5117397Skan * Common Development and Distribution License, Version 1.0 only
6117397Skan * (the "License").  You may not use this file except in compliance
7117397Skan * with the License.
8117397Skan *
9117397Skan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10117397Skan * or http://www.opensolaris.org/os/licensing.
11117397Skan * See the License for the specific language governing permissions
12117397Skan * and limitations under the License.
13117397Skan *
14117397Skan * When distributing Covered Code, include this CDDL HEADER in each
15117397Skan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16117397Skan * If applicable, add the following below this CDDL HEADER, with the
17117397Skan * fields enclosed by brackets "[]" replaced with your own identifying
18117397Skan * information: Portions Copyright [yyyy] [name of copyright owner]
19169691Skan *
20117397Skan * CDDL HEADER END
21117397Skan *
22117397Skan * $FreeBSD: stable/10/sys/cddl/dev/dtrace/i386/dtrace_isa.c 286396 2015-08-07 04:31:02Z kib $
23117397Skan */
24117397Skan/*
25117397Skan * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26117397Skan * Use is subject to license terms.
27117397Skan */
28117397Skan#include <sys/cdefs.h>
29117397Skan
30117397Skan#include <sys/param.h>
31169691Skan#include <sys/systm.h>
32117397Skan#include <sys/kernel.h>
33169691Skan#include <sys/stack.h>
34169691Skan#include <sys/pcpu.h>
35117397Skan
36132720Skan#include <machine/frame.h>
37132720Skan#include <machine/md_var.h>
38132720Skan#include <machine/pcb.h>
39132720Skan#include <machine/stack.h>
40132720Skan
41132720Skan#include <vm/vm.h>
42117397Skan#include <vm/vm_param.h>
43132720Skan#include <vm/pmap.h>
44132720Skan
45132720Skan#include "regset.h"
46132720Skan
47132720Skanextern uintptr_t kernbase;
48132720Skanuintptr_t kernelbase = (uintptr_t) &kernbase;
49132720Skan
50132720Skanuint8_t dtrace_fuword8_nocheck(void *);
51132720Skanuint16_t dtrace_fuword16_nocheck(void *);
52132720Skanuint32_t dtrace_fuword32_nocheck(void *);
53132720Skanuint64_t dtrace_fuword64_nocheck(void *);
54132720Skan
55132720Skanint	dtrace_ustackdepth_max = 2048;
56132720Skan
57132720Skanvoid
58132720Skandtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
59132720Skan    uint32_t *intrpc)
60132720Skan{
61132720Skan	int depth = 0;
62132720Skan	register_t ebp;
63132720Skan	struct i386_frame *frame;
64132720Skan	vm_offset_t callpc;
65132720Skan	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
66132720Skan
67132720Skan	if (intrpc != 0)
68132720Skan		pcstack[depth++] = (pc_t) intrpc;
69132720Skan
70132720Skan	aframes++;
71117397Skan
72117397Skan	__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
73132720Skan
74132720Skan	frame = (struct i386_frame *)ebp;
75132720Skan	while (depth < pcstack_limit) {
76132720Skan		if (!INKERNEL(frame))
77132720Skan			break;
78117397Skan
79132720Skan		callpc = frame->f_retaddr;
80132720Skan
81132720Skan		if (!INKERNEL(callpc))
82132720Skan			break;
83132720Skan
84132720Skan		if (aframes > 0) {
85132720Skan			aframes--;
86132720Skan			if ((aframes == 0) && (caller != 0)) {
87132720Skan				pcstack[depth++] = caller;
88132720Skan			}
89132720Skan		}
90132720Skan		else {
91132720Skan			pcstack[depth++] = callpc;
92132720Skan		}
93132720Skan
94132720Skan		if (frame->f_frame <= frame ||
95132720Skan		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
96132720Skan		    curthread->td_kstack_pages * PAGE_SIZE)
97132720Skan			break;
98132720Skan		frame = frame->f_frame;
99132720Skan	}
100132720Skan
101132720Skan	for (; depth < pcstack_limit; depth++) {
102132720Skan		pcstack[depth] = 0;
103132720Skan	}
104132720Skan}
105132720Skan
106132720Skanstatic int
107132720Skandtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
108132720Skan    uintptr_t sp)
109132720Skan{
110132720Skan#ifdef notyet
111132720Skan	proc_t *p = curproc;
112132720Skan	uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
113132720Skan	size_t s1, s2;
114132720Skan#endif
115132720Skan	uintptr_t oldsp;
116132720Skan	volatile uint16_t *flags =
117132720Skan	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
118132720Skan	int ret = 0;
119132720Skan
120132720Skan	ASSERT(pcstack == NULL || pcstack_limit > 0);
121132720Skan	ASSERT(dtrace_ustackdepth_max > 0);
122132720Skan
123132720Skan#ifdef notyet /* XXX signal stack. */
124132720Skan	if (p->p_model == DATAMODEL_NATIVE) {
125117397Skan		s1 = sizeof (struct frame) + 2 * sizeof (long);
126169691Skan		s2 = s1 + sizeof (siginfo_t);
127169691Skan	} else {
128		s1 = sizeof (struct frame32) + 3 * sizeof (int);
129		s2 = s1 + sizeof (siginfo32_t);
130	}
131#endif
132
133	while (pc != 0) {
134		/*
135		 * We limit the number of times we can go around this
136		 * loop to account for a circular stack.
137		 */
138		if (ret++ >= dtrace_ustackdepth_max) {
139			*flags |= CPU_DTRACE_BADSTACK;
140			cpu_core[curcpu].cpuc_dtrace_illval = sp;
141			break;
142		}
143
144		if (pcstack != NULL) {
145			*pcstack++ = (uint64_t)pc;
146			pcstack_limit--;
147			if (pcstack_limit <= 0)
148				break;
149		}
150
151		if (sp == 0)
152			break;
153
154		oldsp = sp;
155
156#ifdef notyet /* XXX signal stack. */
157		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
158			if (p->p_model == DATAMODEL_NATIVE) {
159				ucontext_t *ucp = (ucontext_t *)oldcontext;
160				greg_t *gregs = ucp->uc_mcontext.gregs;
161
162				sp = dtrace_fulword(&gregs[REG_FP]);
163				pc = dtrace_fulword(&gregs[REG_PC]);
164
165				oldcontext = dtrace_fulword(&ucp->uc_link);
166			} else {
167				ucontext32_t *ucp = (ucontext32_t *)oldcontext;
168				greg32_t *gregs = ucp->uc_mcontext.gregs;
169
170				sp = dtrace_fuword32(&gregs[EBP]);
171				pc = dtrace_fuword32(&gregs[EIP]);
172
173				oldcontext = dtrace_fuword32(&ucp->uc_link);
174			}
175		} else {
176			if (p->p_model == DATAMODEL_NATIVE) {
177				struct frame *fr = (struct frame *)sp;
178
179				pc = dtrace_fulword(&fr->fr_savpc);
180				sp = dtrace_fulword(&fr->fr_savfp);
181			} else {
182				struct frame32 *fr = (struct frame32 *)sp;
183
184				pc = dtrace_fuword32(&fr->fr_savpc);
185				sp = dtrace_fuword32(&fr->fr_savfp);
186			}
187		}
188#else
189		pc = dtrace_fuword32((void *)(sp +
190			offsetof(struct i386_frame, f_retaddr)));
191		sp = dtrace_fuword32((void *)sp);
192#endif /* ! notyet */
193
194		if (sp == oldsp) {
195			*flags |= CPU_DTRACE_BADSTACK;
196			cpu_core[curcpu].cpuc_dtrace_illval = sp;
197			break;
198		}
199
200		/*
201		 * This is totally bogus:  if we faulted, we're going to clear
202		 * the fault and break.  This is to deal with the apparently
203		 * broken Java stacks on x86.
204		 */
205		if (*flags & CPU_DTRACE_FAULT) {
206			*flags &= ~CPU_DTRACE_FAULT;
207			break;
208		}
209	}
210
211	return (ret);
212}
213
214void
215dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
216{
217	proc_t *p = curproc;
218	struct trapframe *tf;
219	uintptr_t pc, sp, fp;
220	volatile uint16_t *flags =
221	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
222	int n;
223
224	if (*flags & CPU_DTRACE_FAULT)
225		return;
226
227	if (pcstack_limit <= 0)
228		return;
229
230	/*
231	 * If there's no user context we still need to zero the stack.
232	 */
233	if (p == NULL || (tf = curthread->td_frame) == NULL)
234		goto zero;
235
236	*pcstack++ = (uint64_t)p->p_pid;
237	pcstack_limit--;
238
239	if (pcstack_limit <= 0)
240		return;
241
242	pc = tf->tf_eip;
243	fp = tf->tf_ebp;
244	sp = tf->tf_esp;
245
246	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
247		/*
248		 * In an entry probe.  The frame pointer has not yet been
249		 * pushed (that happens in the function prologue).  The
250		 * best approach is to add the current pc as a missing top
251		 * of stack and back the pc up to the caller, which is stored
252		 * at the current stack pointer address since the call
253		 * instruction puts it there right before the branch.
254		 */
255
256		*pcstack++ = (uint64_t)pc;
257		pcstack_limit--;
258		if (pcstack_limit <= 0)
259			return;
260
261		pc = dtrace_fuword32((void *) sp);
262	}
263
264	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
265	ASSERT(n >= 0);
266	ASSERT(n <= pcstack_limit);
267
268	pcstack += n;
269	pcstack_limit -= n;
270
271zero:
272	while (pcstack_limit-- > 0)
273		*pcstack++ = 0;
274}
275
276int
277dtrace_getustackdepth(void)
278{
279	proc_t *p = curproc;
280	struct trapframe *tf;
281	uintptr_t pc, fp, sp;
282	int n = 0;
283
284	if (p == NULL || (tf = curthread->td_frame) == NULL)
285		return (0);
286
287	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
288		return (-1);
289
290	pc = tf->tf_eip;
291	fp = tf->tf_ebp;
292	sp = tf->tf_esp;
293
294	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
295		/*
296		 * In an entry probe.  The frame pointer has not yet been
297		 * pushed (that happens in the function prologue).  The
298		 * best approach is to add the current pc as a missing top
299		 * of stack and back the pc up to the caller, which is stored
300		 * at the current stack pointer address since the call
301		 * instruction puts it there right before the branch.
302		 */
303
304		pc = dtrace_fuword32((void *) sp);
305		n++;
306	}
307
308	n += dtrace_getustack_common(NULL, 0, pc, fp);
309
310	return (n);
311}
312
313void
314dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
315{
316	proc_t *p = curproc;
317	struct trapframe *tf;
318	uintptr_t pc, sp, fp;
319	volatile uint16_t *flags =
320	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
321#ifdef notyet /* XXX signal stack */
322	uintptr_t oldcontext;
323	size_t s1, s2;
324#endif
325
326	if (*flags & CPU_DTRACE_FAULT)
327		return;
328
329	if (pcstack_limit <= 0)
330		return;
331
332	/*
333	 * If there's no user context we still need to zero the stack.
334	 */
335	if (p == NULL || (tf = curthread->td_frame) == NULL)
336		goto zero;
337
338	*pcstack++ = (uint64_t)p->p_pid;
339	pcstack_limit--;
340
341	if (pcstack_limit <= 0)
342		return;
343
344	pc = tf->tf_eip;
345	fp = tf->tf_ebp;
346	sp = tf->tf_esp;
347
348#ifdef notyet /* XXX signal stack */
349	oldcontext = lwp->lwp_oldcontext;
350
351	if (p->p_model == DATAMODEL_NATIVE) {
352		s1 = sizeof (struct frame) + 2 * sizeof (long);
353		s2 = s1 + sizeof (siginfo_t);
354	} else {
355		s1 = sizeof (struct frame32) + 3 * sizeof (int);
356		s2 = s1 + sizeof (siginfo32_t);
357	}
358#endif
359
360	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
361		*pcstack++ = (uint64_t)pc;
362		*fpstack++ = 0;
363		pcstack_limit--;
364		if (pcstack_limit <= 0)
365			return;
366
367		pc = dtrace_fuword32((void *)sp);
368	}
369
370	while (pc != 0) {
371		*pcstack++ = (uint64_t)pc;
372		*fpstack++ = fp;
373		pcstack_limit--;
374		if (pcstack_limit <= 0)
375			break;
376
377		if (fp == 0)
378			break;
379
380#ifdef notyet /* XXX signal stack */
381		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
382			if (p->p_model == DATAMODEL_NATIVE) {
383				ucontext_t *ucp = (ucontext_t *)oldcontext;
384				greg_t *gregs = ucp->uc_mcontext.gregs;
385
386				sp = dtrace_fulword(&gregs[REG_FP]);
387				pc = dtrace_fulword(&gregs[REG_PC]);
388
389				oldcontext = dtrace_fulword(&ucp->uc_link);
390			} else {
391				ucontext_t *ucp = (ucontext_t *)oldcontext;
392				greg_t *gregs = ucp->uc_mcontext.gregs;
393
394				sp = dtrace_fuword32(&gregs[EBP]);
395				pc = dtrace_fuword32(&gregs[EIP]);
396
397				oldcontext = dtrace_fuword32(&ucp->uc_link);
398			}
399		} else
400#endif /* XXX */
401		{
402			pc = dtrace_fuword32((void *)(fp +
403				offsetof(struct i386_frame, f_retaddr)));
404			fp = dtrace_fuword32((void *)fp);
405		}
406
407		/*
408		 * This is totally bogus:  if we faulted, we're going to clear
409		 * the fault and break.  This is to deal with the apparently
410		 * broken Java stacks on x86.
411		 */
412		if (*flags & CPU_DTRACE_FAULT) {
413			*flags &= ~CPU_DTRACE_FAULT;
414			break;
415		}
416	}
417
418zero:
419	while (pcstack_limit-- > 0)
420		*pcstack++ = 0;
421}
422
423uint64_t
424dtrace_getarg(int arg, int aframes)
425{
426	uintptr_t val;
427	struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
428	uintptr_t *stack;
429	int i;
430
431	for (i = 1; i <= aframes; i++) {
432		fp = fp->f_frame;
433
434		if (P2ROUNDUP(fp->f_retaddr, 4) ==
435		    (long)dtrace_invop_callsite) {
436			/*
437			 * If we pass through the invalid op handler, we will
438			 * use the pointer that it passed to the stack as the
439			 * second argument to dtrace_invop() as the pointer to
440			 * the stack.  When using this stack, we must step
441			 * beyond the EIP/RIP that was pushed when the trap was
442			 * taken -- hence the "+ 1" below.
443			 */
444			stack = ((uintptr_t **)&fp[1])[0] + 1;
445			goto load;
446		}
447
448	}
449
450	/*
451	 * We know that we did not come through a trap to get into
452	 * dtrace_probe() -- the provider simply called dtrace_probe()
453	 * directly.  As this is the case, we need to shift the argument
454	 * that we're looking for:  the probe ID is the first argument to
455	 * dtrace_probe(), so the argument n will actually be found where
456	 * one would expect to find argument (n + 1).
457	 */
458	arg++;
459
460	stack = (uintptr_t *)fp + 2;
461
462load:
463	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
464	val = stack[arg];
465	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
466
467	return (val);
468}
469
470int
471dtrace_getstackdepth(int aframes)
472{
473	int depth = 0;
474	struct i386_frame *frame;
475	vm_offset_t ebp;
476
477	aframes++;
478	ebp = dtrace_getfp();
479	frame = (struct i386_frame *)ebp;
480	depth++;
481	for(;;) {
482		if (!INKERNEL((long) frame))
483			break;
484		if (!INKERNEL((long) frame->f_frame))
485			break;
486		depth++;
487		if (frame->f_frame <= frame ||
488		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
489		    curthread->td_kstack_pages * PAGE_SIZE)
490			break;
491		frame = frame->f_frame;
492	}
493	if (depth < aframes)
494		return 0;
495	else
496		return depth - aframes;
497}
498
499ulong_t
500dtrace_getreg(struct trapframe *rp, uint_t reg)
501{
502	struct pcb *pcb;
503	int regmap[] = {  /* Order is dependent on reg.d */
504		REG_GS,		/* 0  GS */
505		REG_FS,		/* 1  FS */
506		REG_ES,		/* 2  ES */
507		REG_DS,		/* 3  DS */
508		REG_RDI,	/* 4  EDI */
509		REG_RSI,	/* 5  ESI */
510		REG_RBP,	/* 6  EBP, REG_FP */
511		REG_RSP,	/* 7  ESP */
512		REG_RBX,	/* 8  EBX */
513		REG_RDX,	/* 9  EDX, REG_R1 */
514		REG_RCX,	/* 10 ECX */
515		REG_RAX,	/* 11 EAX, REG_R0 */
516		REG_TRAPNO,	/* 12 TRAPNO */
517		REG_ERR,	/* 13 ERR */
518		REG_RIP,	/* 14 EIP, REG_PC */
519		REG_CS,		/* 15 CS */
520		REG_RFL,	/* 16 EFL, REG_PS */
521		REG_RSP,	/* 17 UESP, REG_SP */
522		REG_SS		/* 18 SS */
523	};
524
525	if (reg > SS) {
526		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
527		return (0);
528	}
529
530	if (reg >= sizeof (regmap) / sizeof (int)) {
531		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
532		return (0);
533	}
534
535	reg = regmap[reg];
536
537	switch(reg) {
538	case REG_GS:
539		if ((pcb = curthread->td_pcb) == NULL) {
540			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
541			return (0);
542		}
543		return (pcb->pcb_gs);
544	case REG_FS:
545		return (rp->tf_fs);
546	case REG_ES:
547		return (rp->tf_es);
548	case REG_DS:
549		return (rp->tf_ds);
550	case REG_RDI:
551		return (rp->tf_edi);
552	case REG_RSI:
553		return (rp->tf_esi);
554	case REG_RBP:
555		return (rp->tf_ebp);
556	case REG_RSP:
557		return (rp->tf_isp);
558	case REG_RBX:
559		return (rp->tf_ebx);
560	case REG_RCX:
561		return (rp->tf_ecx);
562	case REG_RAX:
563		return (rp->tf_eax);
564	case REG_TRAPNO:
565		return (rp->tf_trapno);
566	case REG_ERR:
567		return (rp->tf_err);
568	case REG_RIP:
569		return (rp->tf_eip);
570	case REG_CS:
571		return (rp->tf_cs);
572	case REG_RFL:
573		return (rp->tf_eflags);
574#if 0
575	case REG_RSP:
576		return (rp->tf_esp);
577#endif
578	case REG_SS:
579		return (rp->tf_ss);
580	default:
581		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
582		return (0);
583	}
584}
585
586static int
587dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
588{
589	ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
590
591	if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
592		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
593		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
594		return (0);
595	}
596
597	return (1);
598}
599
600void
601dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
602    volatile uint16_t *flags)
603{
604	if (dtrace_copycheck(uaddr, kaddr, size))
605		dtrace_copy(uaddr, kaddr, size);
606}
607
608void
609dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
610    volatile uint16_t *flags)
611{
612	if (dtrace_copycheck(uaddr, kaddr, size))
613		dtrace_copy(kaddr, uaddr, size);
614}
615
616void
617dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
618    volatile uint16_t *flags)
619{
620	if (dtrace_copycheck(uaddr, kaddr, size))
621		dtrace_copystr(uaddr, kaddr, size, flags);
622}
623
624void
625dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
626    volatile uint16_t *flags)
627{
628	if (dtrace_copycheck(uaddr, kaddr, size))
629		dtrace_copystr(kaddr, uaddr, size, flags);
630}
631
632uint8_t
633dtrace_fuword8(void *uaddr)
634{
635	if ((uintptr_t)uaddr >= kernelbase) {
636		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
637		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
638		return (0);
639	}
640	return (dtrace_fuword8_nocheck(uaddr));
641}
642
643uint16_t
644dtrace_fuword16(void *uaddr)
645{
646	if ((uintptr_t)uaddr >= kernelbase) {
647		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
648		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
649		return (0);
650	}
651	return (dtrace_fuword16_nocheck(uaddr));
652}
653
654uint32_t
655dtrace_fuword32(void *uaddr)
656{
657	if ((uintptr_t)uaddr >= kernelbase) {
658		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
659		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
660		return (0);
661	}
662	return (dtrace_fuword32_nocheck(uaddr));
663}
664
665uint64_t
666dtrace_fuword64(void *uaddr)
667{
668	if ((uintptr_t)uaddr >= kernelbase) {
669		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
670		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
671		return (0);
672	}
673	return (dtrace_fuword64_nocheck(uaddr));
674}
675