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