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