]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/cddl/dev/dtrace/i386/dtrace_isa.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / cddl / dev / dtrace / i386 / dtrace_isa.c
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 }