xref: /freebsd/sys/cddl/dev/dtrace/i386/dtrace_isa.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
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 (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 
444 load:
445 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
446 	val = stack[arg];
447 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
448 
449 	return (val);
450 }
451 
452 int
453 dtrace_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 
481 ulong_t
482 dtrace_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 
568 static int
569 dtrace_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 
582 void
583 dtrace_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 
590 void
591 dtrace_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 
598 void
599 dtrace_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 
606 void
607 dtrace_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 
614 uint8_t
615 dtrace_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 
625 uint16_t
626 dtrace_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 
636 uint32_t
637 dtrace_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 
647 uint64_t
648 dtrace_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