The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cddl/dev/fbt/x86/fbt_isa.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or http://www.opensolaris.org/os/licensing.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  *
   21  * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
   22  *
   23  * $FreeBSD$
   24  *
   25  */
   26 
   27 /*
   28  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   29  * Use is subject to license terms.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 #include <sys/param.h>
   34 
   35 #include <sys/dtrace.h>
   36 
   37 #include <machine/cpufunc.h>
   38 #include <machine/md_var.h>
   39 
   40 #include "fbt.h"
   41 
   42 #define FBT_PUSHL_EBP           0x55
   43 #define FBT_MOVL_ESP_EBP0_V0    0x8b
   44 #define FBT_MOVL_ESP_EBP1_V0    0xec
   45 #define FBT_MOVL_ESP_EBP0_V1    0x89
   46 #define FBT_MOVL_ESP_EBP1_V1    0xe5
   47 #define FBT_REX_RSP_RBP         0x48
   48 
   49 #define FBT_POPL_EBP            0x5d
   50 #define FBT_RET                 0xc3
   51 #define FBT_RET_IMM16           0xc2
   52 #define FBT_LEAVE               0xc9
   53 
   54 #ifdef __amd64__
   55 #define FBT_PATCHVAL            0xcc
   56 #else
   57 #define FBT_PATCHVAL            0xf0
   58 #endif
   59 
   60 #define FBT_ENTRY       "entry"
   61 #define FBT_RETURN      "return"
   62 
   63 int
   64 fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t scratch __unused)
   65 {
   66         solaris_cpu_t *cpu;
   67         uintptr_t *stack;
   68         uintptr_t arg0, arg1, arg2, arg3, arg4, rval;
   69         fbt_probe_t *fbt;
   70         int8_t fbtrval;
   71 
   72 #ifdef __amd64__
   73         stack = (uintptr_t *)frame->tf_rsp;
   74         rval = frame->tf_rax;
   75 #else
   76         /* Skip hardware-saved registers. */
   77         stack = (uintptr_t *)frame->tf_isp + 3;
   78         rval = frame->tf_eax;
   79 #endif
   80 
   81         cpu = &solaris_cpu[curcpu];
   82         fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
   83         for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
   84                 if ((uintptr_t)fbt->fbtp_patchpoint != addr)
   85                         continue;
   86                 fbtrval = fbt->fbtp_rval;
   87 
   88                 /*
   89                  * Report the address of the breakpoint for the benefit
   90                  * of consumers fetching register values with regs[].
   91                  */
   92 #ifdef __i386__
   93                 frame->tf_eip--;
   94 #else
   95                 frame->tf_rip--;
   96 #endif
   97                 for (; fbt != NULL; fbt = fbt->fbtp_tracenext) {
   98                         ASSERT(fbt->fbtp_rval == fbtrval);
   99                         if (fbt->fbtp_roffset == 0) {
  100 #ifdef __amd64__
  101                                 /* fbt->fbtp_rval == DTRACE_INVOP_PUSHQ_RBP */
  102                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
  103                                 cpu->cpu_dtrace_caller = stack[0];
  104                                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
  105                                     CPU_DTRACE_BADADDR);
  106 
  107                                 arg0 = frame->tf_rdi;
  108                                 arg1 = frame->tf_rsi;
  109                                 arg2 = frame->tf_rdx;
  110                                 arg3 = frame->tf_rcx;
  111                                 arg4 = frame->tf_r8;
  112 #else
  113                                 int i = 0;
  114 
  115                                 /*
  116                                  * When accessing the arguments on the stack,
  117                                  * we must protect against accessing beyond
  118                                  * the stack.  We can safely set NOFAULT here
  119                                  * -- we know that interrupts are already
  120                                  * disabled.
  121                                  */
  122                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
  123                                 cpu->cpu_dtrace_caller = stack[i++];
  124                                 arg0 = stack[i++];
  125                                 arg1 = stack[i++];
  126                                 arg2 = stack[i++];
  127                                 arg3 = stack[i++];
  128                                 arg4 = stack[i++];
  129                                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
  130                                     CPU_DTRACE_BADADDR);
  131 #endif
  132 
  133                                 dtrace_probe(fbt->fbtp_id, arg0, arg1,
  134                                     arg2, arg3, arg4);
  135 
  136                                 cpu->cpu_dtrace_caller = 0;
  137                         } else {
  138 #ifdef __amd64__
  139                                 /*
  140                                  * On amd64, we instrument the ret, not the
  141                                  * leave.  We therefore need to set the caller
  142                                  * to ensure that the top frame of a stack()
  143                                  * action is correct.
  144                                  */
  145                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
  146                                 cpu->cpu_dtrace_caller = stack[0];
  147                                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
  148                                     CPU_DTRACE_BADADDR);
  149 #endif
  150 
  151                                 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
  152                                     rval, 0, 0, 0);
  153                                 cpu->cpu_dtrace_caller = 0;
  154                         }
  155                 }
  156                 /* Advance to the instruction following the breakpoint. */
  157 #ifdef __i386__
  158                 frame->tf_eip++;
  159 #else
  160                 frame->tf_rip++;
  161 #endif
  162                 return (fbtrval);
  163         }
  164 
  165         return (0);
  166 }
  167 
  168 void
  169 fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
  170 {
  171         register_t intr;
  172         bool old_wp;
  173 
  174         intr = intr_disable();
  175         old_wp = disable_wp();
  176         *fbt->fbtp_patchpoint = val;
  177         restore_wp(old_wp);
  178         intr_restore(intr);
  179 }
  180 
  181 int
  182 fbt_provide_module_function(linker_file_t lf, int symindx,
  183     linker_symval_t *symval, void *opaque)
  184 {
  185         char *modname = opaque;
  186         const char *name = symval->name;
  187         fbt_probe_t *fbt, *hash, *retfbt;
  188         int j;
  189         int size;
  190         uint8_t *instr, *limit;
  191 
  192         if (fbt_excluded(name))
  193                 return (0);
  194 
  195         /*
  196          * trap_check() is a wrapper for DTrace's fault handler, so we don't
  197          * want to be able to instrument it.
  198          */
  199         if (strcmp(name, "trap_check") == 0)
  200                 return (0);
  201 
  202         size = symval->size;
  203 
  204         instr = (uint8_t *) symval->value;
  205         limit = (uint8_t *) symval->value + symval->size;
  206 
  207 #ifdef __amd64__
  208         while (instr < limit) {
  209                 if (*instr == FBT_PUSHL_EBP)
  210                         break;
  211 
  212                 if ((size = dtrace_instr_size(instr)) <= 0)
  213                         break;
  214 
  215                 instr += size;
  216         }
  217 
  218         if (instr >= limit || *instr != FBT_PUSHL_EBP) {
  219                 /*
  220                  * We either don't save the frame pointer in this
  221                  * function, or we ran into some disassembly
  222                  * screw-up.  Either way, we bail.
  223                  */
  224                 return (0);
  225         }
  226 #else
  227         if (instr[0] != FBT_PUSHL_EBP)
  228                 return (0);
  229 
  230         if (!(instr[1] == FBT_MOVL_ESP_EBP0_V0 &&
  231             instr[2] == FBT_MOVL_ESP_EBP1_V0) &&
  232             !(instr[1] == FBT_MOVL_ESP_EBP0_V1 &&
  233             instr[2] == FBT_MOVL_ESP_EBP1_V1))
  234                 return (0);
  235 #endif
  236 
  237         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  238         fbt->fbtp_name = name;
  239         fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  240             name, FBT_ENTRY, 3, fbt);
  241         fbt->fbtp_patchpoint = instr;
  242         fbt->fbtp_ctl = lf;
  243         fbt->fbtp_loadcnt = lf->loadcnt;
  244         fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP;
  245         fbt->fbtp_savedval = *instr;
  246         fbt->fbtp_patchval = FBT_PATCHVAL;
  247         fbt->fbtp_symindx = symindx;
  248 
  249         for (hash = fbt_probetab[FBT_ADDR2NDX(instr)]; hash != NULL;
  250             hash = hash->fbtp_hashnext) {
  251                 if (hash->fbtp_patchpoint == fbt->fbtp_patchpoint) {
  252                         fbt->fbtp_tracenext = hash->fbtp_tracenext;
  253                         hash->fbtp_tracenext = fbt;
  254                         break;
  255                 }
  256         }
  257         if (hash == NULL) {
  258                 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
  259                 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
  260         }
  261 
  262         lf->fbt_nentries++;
  263 
  264         retfbt = NULL;
  265 again:
  266         if (instr >= limit)
  267                 return (0);
  268 
  269         /*
  270          * If this disassembly fails, then we've likely walked off into
  271          * a jump table or some other unsuitable area.  Bail out of the
  272          * disassembly now.
  273          */
  274         if ((size = dtrace_instr_size(instr)) <= 0)
  275                 return (0);
  276 
  277 #ifdef __amd64__
  278         /*
  279          * We only instrument "ret" on amd64 -- we don't yet instrument
  280          * ret imm16, largely because the compiler doesn't seem to
  281          * (yet) emit them in the kernel...
  282          */
  283         if (*instr != FBT_RET) {
  284                 instr += size;
  285                 goto again;
  286         }
  287 #else
  288         if (!(size == 1 &&
  289             (*instr == FBT_POPL_EBP || *instr == FBT_LEAVE) &&
  290             (*(instr + 1) == FBT_RET ||
  291             *(instr + 1) == FBT_RET_IMM16))) {
  292                 instr += size;
  293                 goto again;
  294         }
  295 #endif
  296 
  297         /*
  298          * We (desperately) want to avoid erroneously instrumenting a
  299          * jump table, especially given that our markers are pretty
  300          * short:  two bytes on x86, and just one byte on amd64.  To
  301          * determine if we're looking at a true instruction sequence
  302          * or an inline jump table that happens to contain the same
  303          * byte sequences, we resort to some heuristic sleeze:  we
  304          * treat this instruction as being contained within a pointer,
  305          * and see if that pointer points to within the body of the
  306          * function.  If it does, we refuse to instrument it.
  307          */
  308         for (j = 0; j < sizeof (uintptr_t); j++) {
  309                 caddr_t check = (caddr_t) instr - j;
  310                 uint8_t *ptr;
  311 
  312                 if (check < symval->value)
  313                         break;
  314 
  315                 if (check + sizeof (caddr_t) > (caddr_t)limit)
  316                         continue;
  317 
  318                 ptr = *(uint8_t **)check;
  319 
  320                 if (ptr >= (uint8_t *) symval->value && ptr < limit) {
  321                         instr += size;
  322                         goto again;
  323                 }
  324         }
  325 
  326         /*
  327          * We have a winner!
  328          */
  329         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  330         fbt->fbtp_name = name;
  331 
  332         if (retfbt == NULL) {
  333                 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  334                     name, FBT_RETURN, 3, fbt);
  335         } else {
  336                 retfbt->fbtp_probenext = fbt;
  337                 fbt->fbtp_id = retfbt->fbtp_id;
  338         }
  339 
  340         retfbt = fbt;
  341         fbt->fbtp_patchpoint = instr;
  342         fbt->fbtp_ctl = lf;
  343         fbt->fbtp_loadcnt = lf->loadcnt;
  344         fbt->fbtp_symindx = symindx;
  345 
  346 #ifndef __amd64__
  347         if (*instr == FBT_POPL_EBP) {
  348                 fbt->fbtp_rval = DTRACE_INVOP_POPL_EBP;
  349         } else {
  350                 ASSERT(*instr == FBT_LEAVE);
  351                 fbt->fbtp_rval = DTRACE_INVOP_LEAVE;
  352         }
  353         fbt->fbtp_roffset =
  354             (uintptr_t)(instr - (uint8_t *) symval->value) + 1;
  355 
  356 #else
  357         ASSERT(*instr == FBT_RET);
  358         fbt->fbtp_rval = DTRACE_INVOP_RET;
  359         fbt->fbtp_roffset =
  360             (uintptr_t)(instr - (uint8_t *) symval->value);
  361 #endif
  362 
  363         fbt->fbtp_savedval = *instr;
  364         fbt->fbtp_patchval = FBT_PATCHVAL;
  365         fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
  366         fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
  367 
  368         lf->fbt_nentries++;
  369 
  370         instr += size;
  371         goto again;
  372 }

Cache object: 692a606e58772e965875b2e03b782ea5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.