xref: /freebsd/sys/cddl/dev/dtrace/i386/dtrace_isa.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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$
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 
47 extern uintptr_t kernbase;
48 uintptr_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 
53 uint8_t dtrace_fuword8_nocheck(void *);
54 uint16_t dtrace_fuword16_nocheck(void *);
55 uint32_t dtrace_fuword32_nocheck(void *);
56 uint64_t dtrace_fuword64_nocheck(void *);
57 
58 void
59 dtrace_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 
107 static int
108 dtrace_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 
196 void
197 dtrace_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 
253 zero:
254 	while (pcstack_limit-- > 0)
255 		*pcstack++ = 0;
256 }
257 
258 int
259 dtrace_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 
295 void
296 dtrace_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 
400 zero:
401 	while (pcstack_limit-- > 0)
402 		*pcstack++ = 0;
403 }
404 
405 uint64_t
406 dtrace_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 (fp->f_retaddr == (long)dtrace_invop_callsite) {
417 			/*
418 			 * If we pass through the invalid op handler, we will
419 			 * use the pointer that it passed to the stack as the
420 			 * second argument to dtrace_invop() as the pointer to
421 			 * the stack.  When using this stack, we must step
422 			 * beyond the EIP/RIP that was pushed when the trap was
423 			 * taken -- hence the "+ 1" below.
424 			 */
425 			stack = ((uintptr_t **)&fp[1])[1] + 1;
426 			goto load;
427 		}
428 
429 	}
430 
431 	/*
432 	 * We know that we did not come through a trap to get into
433 	 * dtrace_probe() -- the provider simply called dtrace_probe()
434 	 * directly.  As this is the case, we need to shift the argument
435 	 * that we're looking for:  the probe ID is the first argument to
436 	 * dtrace_probe(), so the argument n will actually be found where
437 	 * one would expect to find argument (n + 1).
438 	 */
439 	arg++;
440 
441 	stack = (uintptr_t *)&fp[1];
442 
443 load:
444 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
445 	val = stack[arg];
446 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
447 
448 	return (val);
449 }
450 
451 int
452 dtrace_getstackdepth(int aframes)
453 {
454 	int depth = 0;
455 	struct i386_frame *frame;
456 	vm_offset_t ebp;
457 
458 	aframes++;
459 	ebp = dtrace_getfp();
460 	frame = (struct i386_frame *)ebp;
461 	depth++;
462 	for(;;) {
463 		if (!INKERNEL((long) frame))
464 			break;
465 		if (!INKERNEL((long) frame->f_frame))
466 			break;
467 		depth++;
468 		if (frame->f_frame <= frame ||
469 		    (vm_offset_t)frame->f_frame >=
470 		    (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
471 			break;
472 		frame = frame->f_frame;
473 	}
474 	if (depth < aframes)
475 		return 0;
476 	else
477 		return depth - aframes;
478 }
479 
480 ulong_t
481 dtrace_getreg(struct trapframe *rp, uint_t reg)
482 {
483 	struct pcb *pcb;
484 	int regmap[] = {  /* Order is dependent on reg.d */
485 		REG_GS,		/* 0  GS */
486 		REG_FS,		/* 1  FS */
487 		REG_ES,		/* 2  ES */
488 		REG_DS,		/* 3  DS */
489 		REG_RDI,	/* 4  EDI */
490 		REG_RSI,	/* 5  ESI */
491 		REG_RBP,	/* 6  EBP, REG_FP */
492 		REG_RSP,	/* 7  ESP */
493 		REG_RBX,	/* 8  EBX */
494 		REG_RDX,	/* 9  EDX, REG_R1 */
495 		REG_RCX,	/* 10 ECX */
496 		REG_RAX,	/* 11 EAX, REG_R0 */
497 		REG_TRAPNO,	/* 12 TRAPNO */
498 		REG_ERR,	/* 13 ERR */
499 		REG_RIP,	/* 14 EIP, REG_PC */
500 		REG_CS,		/* 15 CS */
501 		REG_RFL,	/* 16 EFL, REG_PS */
502 		REG_RSP,	/* 17 UESP, REG_SP */
503 		REG_SS		/* 18 SS */
504 	};
505 
506 	if (reg > SS) {
507 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
508 		return (0);
509 	}
510 
511 	if (reg >= sizeof (regmap) / sizeof (int)) {
512 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
513 		return (0);
514 	}
515 
516 	reg = regmap[reg];
517 
518 	switch(reg) {
519 	case REG_GS:
520 		if ((pcb = curthread->td_pcb) == NULL) {
521 			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
522 			return (0);
523 		}
524 		return (pcb->pcb_gs);
525 	case REG_FS:
526 		return (rp->tf_fs);
527 	case REG_ES:
528 		return (rp->tf_es);
529 	case REG_DS:
530 		return (rp->tf_ds);
531 	case REG_RDI:
532 		return (rp->tf_edi);
533 	case REG_RSI:
534 		return (rp->tf_esi);
535 	case REG_RBP:
536 		return (rp->tf_ebp);
537 	case REG_RSP:
538 		return (rp->tf_isp);
539 	case REG_RBX:
540 		return (rp->tf_ebx);
541 	case REG_RCX:
542 		return (rp->tf_ecx);
543 	case REG_RAX:
544 		return (rp->tf_eax);
545 	case REG_TRAPNO:
546 		return (rp->tf_trapno);
547 	case REG_ERR:
548 		return (rp->tf_err);
549 	case REG_RIP:
550 		return (rp->tf_eip);
551 	case REG_CS:
552 		return (rp->tf_cs);
553 	case REG_RFL:
554 		return (rp->tf_eflags);
555 #if 0
556 	case REG_RSP:
557 		return (rp->tf_esp);
558 #endif
559 	case REG_SS:
560 		return (rp->tf_ss);
561 	default:
562 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
563 		return (0);
564 	}
565 }
566 
567 static int
568 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
569 {
570 	ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
571 
572 	if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
573 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
574 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
575 		return (0);
576 	}
577 
578 	return (1);
579 }
580 
581 void
582 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
583     volatile uint16_t *flags)
584 {
585 	if (dtrace_copycheck(uaddr, kaddr, size))
586 		dtrace_copy(uaddr, kaddr, size);
587 }
588 
589 void
590 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
591     volatile uint16_t *flags)
592 {
593 	if (dtrace_copycheck(uaddr, kaddr, size))
594 		dtrace_copy(kaddr, uaddr, size);
595 }
596 
597 void
598 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
599     volatile uint16_t *flags)
600 {
601 	if (dtrace_copycheck(uaddr, kaddr, size))
602 		dtrace_copystr(uaddr, kaddr, size, flags);
603 }
604 
605 void
606 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
607     volatile uint16_t *flags)
608 {
609 	if (dtrace_copycheck(uaddr, kaddr, size))
610 		dtrace_copystr(kaddr, uaddr, size, flags);
611 }
612 
613 uint8_t
614 dtrace_fuword8(void *uaddr)
615 {
616 	if ((uintptr_t)uaddr >= kernelbase) {
617 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
618 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
619 		return (0);
620 	}
621 	return (dtrace_fuword8_nocheck(uaddr));
622 }
623 
624 uint16_t
625 dtrace_fuword16(void *uaddr)
626 {
627 	if ((uintptr_t)uaddr >= kernelbase) {
628 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
629 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
630 		return (0);
631 	}
632 	return (dtrace_fuword16_nocheck(uaddr));
633 }
634 
635 uint32_t
636 dtrace_fuword32(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_fuword32_nocheck(uaddr));
644 }
645 
646 uint64_t
647 dtrace_fuword64(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_fuword64_nocheck(uaddr));
655 }
656