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