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/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_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 2013 Justin Hibbits */
   22 /*
   23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   24  * Use is subject to license terms.
   25  */
   26 
   27 #include <sys/fasttrap_isa.h>
   28 #include <sys/fasttrap_impl.h>
   29 #include <sys/dtrace.h>
   30 #include <sys/dtrace_impl.h>
   31 #include <cddl/dev/dtrace/dtrace_cddl.h>
   32 #include <sys/proc.h>
   33 #include <sys/types.h>
   34 #include <sys/uio.h>
   35 #include <sys/ptrace.h>
   36 #include <sys/rmlock.h>
   37 #include <sys/sysent.h>
   38 
   39 #define OP(x)   ((x) >> 26)
   40 #define OPX(x)  (((x) >> 2) & 0x3FF)
   41 #define OP_BO(x) (((x) & 0x03E00000) >> 21)
   42 #define OP_BI(x) (((x) & 0x001F0000) >> 16)
   43 #define OP_RS(x) (((x) & 0x03E00000) >> 21)
   44 #define OP_RA(x) (((x) & 0x001F0000) >> 16)
   45 #define OP_RB(x) (((x) & 0x0000F100) >> 11)
   46 
   47 int
   48 fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
   49 {
   50         fasttrap_instr_t instr = FASTTRAP_INSTR;
   51 
   52         if (uwrite(p, &instr, 4, tp->ftt_pc) != 0)
   53                 return (-1);
   54 
   55         return (0);
   56 }
   57 
   58 int
   59 fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
   60 {
   61         uint32_t instr;
   62 
   63         /*
   64          * Distinguish between read or write failures and a changed
   65          * instruction.
   66          */
   67         if (uread(p, &instr, 4, tp->ftt_pc) != 0)
   68                 return (0);
   69         if (instr != FASTTRAP_INSTR)
   70                 return (0);
   71         if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0)
   72                 return (-1);
   73 
   74         return (0);
   75 }
   76 
   77 int
   78 fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc,
   79     fasttrap_probe_type_t type)
   80 {
   81         uint32_t instr;
   82         //int32_t disp;
   83 
   84         /*
   85          * Read the instruction at the given address out of the process's
   86          * address space. We don't have to worry about a debugger
   87          * changing this instruction before we overwrite it with our trap
   88          * instruction since P_PR_LOCK is set.
   89          */
   90         if (uread(p, &instr, 4, pc) != 0)
   91                 return (-1);
   92 
   93         /*
   94          * Decode the instruction to fill in the probe flags. We can have
   95          * the process execute most instructions on its own using a pc/npc
   96          * trick, but pc-relative control transfer present a problem since
   97          * we're relocating the instruction. We emulate these instructions
   98          * in the kernel. We assume a default type and over-write that as
   99          * needed.
  100          *
  101          * pc-relative instructions must be emulated for correctness;
  102          * other instructions (which represent a large set of commonly traced
  103          * instructions) are emulated or otherwise optimized for performance.
  104          */
  105         tp->ftt_type = FASTTRAP_T_COMMON;
  106         tp->ftt_instr = instr;
  107 
  108         switch (OP(instr)) {
  109         /* The following are invalid for trapping (invalid opcodes, tw/twi). */
  110         case 0:
  111         case 1:
  112         case 2:
  113         case 4:
  114         case 5:
  115         case 6:
  116         case 30:
  117         case 39:
  118         case 58:
  119         case 62:
  120         case 3: /* twi */
  121                 return (-1);
  122         case 31:        /* tw */
  123                 if (OPX(instr) == 4)
  124                         return (-1);
  125                 else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) &&
  126                     OP_RS(instr) == OP_RB(instr))
  127                         tp->ftt_type = FASTTRAP_T_NOP;
  128                 break;
  129         case 16:
  130                 tp->ftt_type = FASTTRAP_T_BC;
  131                 tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */
  132                 if (instr & 0x00008000)
  133                         tp->ftt_dest |= 0xFFFF0000;
  134                 /* Use as offset if not absolute address. */
  135                 if (!(instr & 0x02))
  136                         tp->ftt_dest += pc;
  137                 tp->ftt_bo = OP_BO(instr);
  138                 tp->ftt_bi = OP_BI(instr);
  139                 break;
  140         case 18:
  141                 tp->ftt_type = FASTTRAP_T_B;
  142                 tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */
  143                 if (instr & 0x02000000)
  144                         tp->ftt_dest |= 0xFC000000;
  145                 /* Use as offset if not absolute address. */
  146                 if (!(instr & 0x02))
  147                         tp->ftt_dest += pc;
  148                 break;
  149         case 19:
  150                 switch (OPX(instr)) {
  151                 case 528:       /* bcctr */
  152                         tp->ftt_type = FASTTRAP_T_BCTR;
  153                         tp->ftt_bo = OP_BO(instr);
  154                         tp->ftt_bi = OP_BI(instr);
  155                         break;
  156                 case 16:        /* bclr */
  157                         tp->ftt_type = FASTTRAP_T_BCTR;
  158                         tp->ftt_bo = OP_BO(instr);
  159                         tp->ftt_bi = OP_BI(instr);
  160                         break;
  161                 };
  162                 break;
  163         case 24:
  164                 if (OP_RS(instr) == OP_RA(instr) &&
  165                     (instr & 0x0000FFFF) == 0)
  166                         tp->ftt_type = FASTTRAP_T_NOP;
  167                 break;
  168         };
  169 
  170         /*
  171          * We don't know how this tracepoint is going to be used, but in case
  172          * it's used as part of a function return probe, we need to indicate
  173          * whether it's always a return site or only potentially a return
  174          * site. If it's part of a return probe, it's always going to be a
  175          * return from that function if it's a restore instruction or if
  176          * the previous instruction was a return. If we could reliably
  177          * distinguish jump tables from return sites, this wouldn't be
  178          * necessary.
  179          */
  180 #if 0
  181         if (tp->ftt_type != FASTTRAP_T_RESTORE &&
  182             (uread(p, &instr, 4, pc - sizeof (instr)) != 0 ||
  183             !(OP(instr) == 2 && OP3(instr) == OP3_RETURN)))
  184                 tp->ftt_flags |= FASTTRAP_F_RETMAYBE;
  185 #endif
  186 
  187         return (0);
  188 }
  189 
  190 static uint64_t
  191 fasttrap_anarg(struct reg *rp, int argno)
  192 {
  193         uint64_t value;
  194         proc_t  *p = curproc;
  195 
  196         /* The first 8 arguments are in registers. */
  197         if (argno < 8)
  198                 return rp->fixreg[argno + 3];
  199 
  200         /* Arguments on stack start after SP+LR (2 register slots). */
  201         if (SV_PROC_FLAG(p, SV_ILP32)) {
  202                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
  203                 value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 +
  204                     ((argno - 8) * sizeof(uint32_t))));
  205                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
  206         } else {
  207                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
  208                 value = dtrace_fuword64((void *)(rp->fixreg[1] + 48 +
  209                     ((argno - 8) * sizeof(uint64_t))));
  210                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
  211         }
  212         return value;
  213 }
  214 
  215 uint64_t
  216 fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
  217     int aframes)
  218 {
  219         struct reg r;
  220 
  221         fill_regs(curthread, &r);
  222 
  223         return (fasttrap_anarg(&r, argno));
  224 }
  225 
  226 uint64_t
  227 fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
  228     int aframes)
  229 {
  230         struct reg r;
  231 
  232         fill_regs(curthread, &r);
  233 
  234         return (fasttrap_anarg(&r, argno));
  235 }
  236 
  237 static void
  238 fasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc,
  239     uintptr_t *argv)
  240 {
  241         int i, x, cap = MIN(argc, probe->ftp_nargs);
  242 
  243         for (i = 0; i < cap; i++) {
  244                 x = probe->ftp_argmap[i];
  245 
  246                 if (x < 8)
  247                         argv[i] = rp->fixreg[x];
  248                 else
  249 #ifdef __powerpc64__
  250                         if (SV_PROC_FLAG(curproc, SV_ILP32))
  251 #endif
  252                                 argv[i] = fuword32((void *)(rp->fixreg[1] + 8 +
  253                                     (x * sizeof(uint32_t))));
  254 #ifdef __powerpc64__
  255                         else
  256                                 argv[i] = fuword64((void *)(rp->fixreg[1] + 48 +
  257                                     (x * sizeof(uint64_t))));
  258 #endif
  259         }
  260 
  261         for (; i < argc; i++) {
  262                 argv[i] = 0;
  263         }
  264 }
  265 
  266 static void
  267 fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid,
  268     uintptr_t new_pc)
  269 {
  270         struct rm_priotracker tracker;
  271         fasttrap_tracepoint_t *tp;
  272         fasttrap_bucket_t *bucket;
  273         fasttrap_id_t *id;
  274 
  275         rm_rlock(&fasttrap_tp_lock, &tracker);
  276         bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
  277 
  278         for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
  279                 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
  280                     tp->ftt_proc->ftpc_acount != 0)
  281                         break;
  282         }
  283 
  284         /*
  285          * Don't sweat it if we can't find the tracepoint again; unlike
  286          * when we're in fasttrap_pid_probe(), finding the tracepoint here
  287          * is not essential to the correct execution of the process.
  288          */
  289         if (tp == NULL) {
  290                 rm_runlock(&fasttrap_tp_lock, &tracker);
  291                 return;
  292         }
  293 
  294         for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
  295                 /*
  296                  * If there's a branch that could act as a return site, we
  297                  * need to trace it, and check here if the program counter is
  298                  * external to the function.
  299                  */
  300                 /* Skip function-local branches. */
  301                 if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize)
  302                         continue;
  303 
  304                 dtrace_probe(id->fti_probe->ftp_id,
  305                     pc - id->fti_probe->ftp_faddr,
  306                     rp->fixreg[3], rp->fixreg[4], 0, 0);
  307         }
  308         rm_runlock(&fasttrap_tp_lock, &tracker);
  309 }
  310 
  311 
  312 static int
  313 fasttrap_branch_taken(int bo, int bi, struct reg *regs)
  314 {
  315         int crzero = 0;
  316 
  317         /* Branch always? */
  318         if ((bo & 0x14) == 0x14)
  319                 return 1;
  320 
  321         /* Handle decrementing ctr */
  322         if (!(bo & 0x04)) {
  323                 --regs->ctr;
  324                 crzero = (regs->ctr == 0);
  325                 if (bo & 0x10) {
  326                         return (!(crzero ^ (bo >> 1)));
  327                 }
  328         }
  329 
  330         return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1));
  331 }
  332 
  333 
  334 int
  335 fasttrap_pid_probe(struct trapframe *frame)
  336 {
  337         struct reg reg, *rp;
  338         struct rm_priotracker tracker;
  339         proc_t *p = curproc;
  340         uintptr_t pc;
  341         uintptr_t new_pc = 0;
  342         fasttrap_bucket_t *bucket;
  343         fasttrap_tracepoint_t *tp, tp_local;
  344         pid_t pid;
  345         dtrace_icookie_t cookie;
  346         uint_t is_enabled = 0;
  347 
  348         fill_regs(curthread, &reg);
  349         rp = &reg;
  350         pc = rp->pc;
  351 
  352         /*
  353          * It's possible that a user (in a veritable orgy of bad planning)
  354          * could redirect this thread's flow of control before it reached the
  355          * return probe fasttrap. In this case we need to kill the process
  356          * since it's in a unrecoverable state.
  357          */
  358         if (curthread->t_dtrace_step) {
  359                 ASSERT(curthread->t_dtrace_on);
  360                 fasttrap_sigtrap(p, curthread, pc);
  361                 return (0);
  362         }
  363 
  364         /*
  365          * Clear all user tracing flags.
  366          */
  367         curthread->t_dtrace_ft = 0;
  368         curthread->t_dtrace_pc = 0;
  369         curthread->t_dtrace_npc = 0;
  370         curthread->t_dtrace_scrpc = 0;
  371         curthread->t_dtrace_astpc = 0;
  372 
  373         rm_rlock(&fasttrap_tp_lock, &tracker);
  374         pid = p->p_pid;
  375         bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
  376 
  377         /*
  378          * Lookup the tracepoint that the process just hit.
  379          */
  380         for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
  381                 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
  382                     tp->ftt_proc->ftpc_acount != 0)
  383                         break;
  384         }
  385 
  386         /*
  387          * If we couldn't find a matching tracepoint, either a tracepoint has
  388          * been inserted without using the pid<pid> ioctl interface (see
  389          * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
  390          */
  391         if (tp == NULL) {
  392                 rm_runlock(&fasttrap_tp_lock, &tracker);
  393                 return (-1);
  394         }
  395 
  396         if (tp->ftt_ids != NULL) {
  397                 fasttrap_id_t *id;
  398 
  399                 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
  400                         fasttrap_probe_t *probe = id->fti_probe;
  401 
  402                         if (id->fti_ptype == DTFTP_ENTRY) {
  403                                 /*
  404                                  * We note that this was an entry
  405                                  * probe to help ustack() find the
  406                                  * first caller.
  407                                  */
  408                                 cookie = dtrace_interrupt_disable();
  409                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
  410                                 dtrace_probe(probe->ftp_id, rp->fixreg[3],
  411                                                 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
  412                                                 rp->fixreg[7]);
  413                                 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
  414                                 dtrace_interrupt_enable(cookie);
  415                         } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
  416                                 /*
  417                                  * Note that in this case, we don't
  418                                  * call dtrace_probe() since it's only
  419                                  * an artificial probe meant to change
  420                                  * the flow of control so that it
  421                                  * encounters the true probe.
  422                                  */
  423                                 is_enabled = 1;
  424                         } else if (probe->ftp_argmap == NULL) {
  425                                 dtrace_probe(probe->ftp_id, rp->fixreg[3],
  426                                     rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
  427                                     rp->fixreg[7]);
  428                         } else {
  429                                 uintptr_t t[5];
  430 
  431                                 fasttrap_usdt_args(probe, rp,
  432                                     sizeof (t) / sizeof (t[0]), t);
  433 
  434                                 dtrace_probe(probe->ftp_id, t[0], t[1],
  435                                     t[2], t[3], t[4]);
  436                         }
  437                 }
  438         }
  439 
  440         /*
  441          * We're about to do a bunch of work so we cache a local copy of
  442          * the tracepoint to emulate the instruction, and then find the
  443          * tracepoint again later if we need to light up any return probes.
  444          */
  445         tp_local = *tp;
  446         rm_runlock(&fasttrap_tp_lock, &tracker);
  447         tp = &tp_local;
  448 
  449         /*
  450          * If there's an is-enabled probe connected to this tracepoint it
  451          * means that there was a 'xor r3, r3, r3'
  452          * instruction that was placed there by DTrace when the binary was
  453          * linked. As this probe is, in fact, enabled, we need to stuff 1
  454          * into R3. Accordingly, we can bypass all the instruction
  455          * emulation logic since we know the inevitable result. It's possible
  456          * that a user could construct a scenario where the 'is-enabled'
  457          * probe was on some other instruction, but that would be a rather
  458          * exotic way to shoot oneself in the foot.
  459          */
  460         if (is_enabled) {
  461                 rp->fixreg[3] = 1;
  462                 new_pc = rp->pc + 4;
  463                 goto done;
  464         }
  465 
  466 
  467         switch (tp->ftt_type) {
  468         case FASTTRAP_T_NOP:
  469                 new_pc = rp->pc + 4;
  470                 break;
  471         case FASTTRAP_T_BC:
  472                 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
  473                         break;
  474                 /* FALLTHROUGH */
  475         case FASTTRAP_T_B:
  476                 if (tp->ftt_instr & 0x01)
  477                         rp->lr = rp->pc + 4;
  478                 new_pc = tp->ftt_dest;
  479                 break;
  480         case FASTTRAP_T_BLR:
  481         case FASTTRAP_T_BCTR:
  482                 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
  483                         break;
  484                 /* FALLTHROUGH */
  485                 if (tp->ftt_type == FASTTRAP_T_BCTR)
  486                         new_pc = rp->ctr;
  487                 else
  488                         new_pc = rp->lr;
  489                 if (tp->ftt_instr & 0x01)
  490                         rp->lr = rp->pc + 4;
  491                 break;
  492         case FASTTRAP_T_COMMON:
  493                 curthread->t_dtrace_pc = pc;
  494                 curthread->t_dtrace_npc = pc + 4;
  495                 curthread->t_dtrace_on = 1;
  496                 new_pc = pc;
  497                 break;
  498         };
  499 done:
  500         /*
  501          * If there were no return probes when we first found the tracepoint,
  502          * we should feel no obligation to honor any return probes that were
  503          * subsequently enabled -- they'll just have to wait until the next
  504          * time around.
  505          */
  506         if (tp->ftt_retids != NULL) {
  507                 /*
  508                  * We need to wait until the results of the instruction are
  509                  * apparent before invoking any return probes. If this
  510                  * instruction was emulated we can just call
  511                  * fasttrap_return_common(); if it needs to be executed, we
  512                  * need to wait until the user thread returns to the kernel.
  513                  */
  514                 if (tp->ftt_type != FASTTRAP_T_COMMON) {
  515                         fasttrap_return_common(rp, pc, pid, new_pc);
  516                 } else {
  517                         ASSERT(curthread->t_dtrace_ret != 0);
  518                         ASSERT(curthread->t_dtrace_pc == pc);
  519                         ASSERT(curthread->t_dtrace_scrpc != 0);
  520                         ASSERT(new_pc == curthread->t_dtrace_astpc);
  521                 }
  522         }
  523 
  524         rp->pc = new_pc;
  525         set_regs(curthread, rp);
  526 
  527         return (0);
  528 }
  529 
  530 int
  531 fasttrap_return_probe(struct trapframe *tf)
  532 {
  533         struct reg reg, *rp;
  534         proc_t *p = curproc;
  535         uintptr_t pc = curthread->t_dtrace_pc;
  536         uintptr_t npc = curthread->t_dtrace_npc;
  537 
  538         curthread->t_dtrace_pc = 0;
  539         curthread->t_dtrace_npc = 0;
  540         curthread->t_dtrace_scrpc = 0;
  541         curthread->t_dtrace_astpc = 0;
  542 
  543         fill_regs(curthread, &reg);
  544         rp = &reg;
  545 
  546         /*
  547          * We set rp->pc to the address of the traced instruction so
  548          * that it appears to dtrace_probe() that we're on the original
  549          * instruction.
  550          */
  551         rp->pc = pc;
  552 
  553         fasttrap_return_common(rp, pc, p->p_pid, npc);
  554 
  555         return (0);
  556 }

Cache object: cc92a4fef539a6ab4e0164b5730c63f3


[ 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.