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