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/powerpc/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  * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org
   23  *
   24  * $FreeBSD$
   25  *
   26  */
   27 
   28 /*
   29  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   30  * Use is subject to license terms.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 #include <sys/param.h>
   35 #include <sys/dtrace.h>
   36 #include <machine/md_var.h>
   37 
   38 #include "fbt.h"
   39 
   40 #define FBT_PATCHVAL            0x7ffff808
   41 #define FBT_MFLR_R0             0x7c0802a6
   42 #define FBT_MTLR_R0             0x7c0803a6
   43 #define FBT_BLR                 0x4e800020
   44 #define FBT_BCTR                0x4e800030
   45 #define FBT_BRANCH              0x48000000
   46 #define FBT_BR_MASK             0x03fffffc
   47 #define FBT_IS_JUMP(instr)      ((instr & ~FBT_BR_MASK) == FBT_BRANCH)
   48 
   49 #define FBT_ENTRY       "entry"
   50 #define FBT_RETURN      "return"
   51 #define FBT_AFRAMES     7
   52 
   53 int
   54 fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
   55 {
   56         solaris_cpu_t *cpu = &solaris_cpu[curcpu];
   57         fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
   58         uintptr_t tmp;
   59 
   60         for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
   61                 if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
   62                         if (fbt->fbtp_roffset == 0) {
   63                                 cpu->cpu_dtrace_caller = addr;
   64 
   65                                 dtrace_probe(fbt->fbtp_id, frame->fixreg[3],
   66                                     frame->fixreg[4], frame->fixreg[5],
   67                                     frame->fixreg[6], frame->fixreg[7]);
   68 
   69                                 cpu->cpu_dtrace_caller = 0;
   70                         } else {
   71 
   72                                 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
   73                                     rval, 0, 0, 0);
   74                                 /*
   75                                  * The caller doesn't have the fbt item, so
   76                                  * fixup tail calls here.
   77                                  */
   78                                 if (fbt->fbtp_rval == DTRACE_INVOP_JUMP) {
   79                                         frame->srr0 = (uintptr_t)fbt->fbtp_patchpoint;
   80                                         tmp = fbt->fbtp_savedval & FBT_BR_MASK;
   81                                         /* Sign extend. */
   82                                         if (tmp & 0x02000000)
   83 #ifdef __powerpc64__
   84                                                 tmp |= 0xfffffffffc000000ULL;
   85 #else
   86                                                 tmp |= 0xfc000000UL;
   87 #endif
   88                                         frame->srr0 += tmp;
   89                                 }
   90                                 cpu->cpu_dtrace_caller = 0;
   91                         }
   92 
   93                         return (fbt->fbtp_rval);
   94                 }
   95         }
   96 
   97         return (0);
   98 }
   99 
  100 void
  101 fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
  102 {
  103 
  104         *fbt->fbtp_patchpoint = val;
  105         __syncicache(fbt->fbtp_patchpoint, 4);
  106 }
  107 
  108 int
  109 fbt_provide_module_function(linker_file_t lf, int symindx,
  110     linker_symval_t *symval, void *opaque)
  111 {
  112         char *modname = opaque;
  113         const char *name = symval->name;
  114         fbt_probe_t *fbt, *retfbt;
  115         int j;
  116         uint32_t *instr, *limit;
  117 
  118 #ifdef __powerpc64__
  119 #if !defined(_CALL_ELF) || _CALL_ELF == 1
  120         /*
  121          * PowerPC64 uses '.' prefixes on symbol names, ignore it, but only
  122          * allow symbols with the '.' prefix, so that we don't get the function
  123          * descriptor instead.
  124          */
  125         if (name[0] == '.')
  126                 name++;
  127         else
  128                 return (0);
  129 #endif
  130 #endif
  131 
  132         if (fbt_excluded(name))
  133                 return (0);
  134 
  135         instr = (uint32_t *) symval->value;
  136         limit = (uint32_t *) (symval->value + symval->size);
  137 
  138         for (; instr < limit; instr++)
  139                 if (*instr == FBT_MFLR_R0)
  140                         break;
  141 
  142         if (*instr != FBT_MFLR_R0)
  143                 return (0);
  144 
  145         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  146         fbt->fbtp_name = name;
  147         fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  148             name, FBT_ENTRY, FBT_AFRAMES, fbt);
  149         fbt->fbtp_patchpoint = instr;
  150         fbt->fbtp_ctl = lf;
  151         fbt->fbtp_loadcnt = lf->loadcnt;
  152         fbt->fbtp_savedval = *instr;
  153         fbt->fbtp_patchval = FBT_PATCHVAL;
  154         fbt->fbtp_rval = DTRACE_INVOP_MFLR_R0;
  155         fbt->fbtp_symindx = symindx;
  156 
  157         fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
  158         fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
  159 
  160         lf->fbt_nentries++;
  161 
  162         retfbt = NULL;
  163 again:
  164         if (instr >= limit)
  165                 return (0);
  166 
  167         /*
  168          * We (desperately) want to avoid erroneously instrumenting a
  169          * jump table. To determine if we're looking at a true instruction
  170          * sequence or an inline jump table that happens to contain the same
  171          * byte sequences, we resort to some heuristic sleeze:  we treat this
  172          * instruction as being contained within a pointer, and see if that
  173          * pointer points to within the body of the function.  If it does, we
  174          * refuse to instrument it.
  175          */
  176         {
  177                 uint32_t *ptr;
  178 
  179                 ptr = *(uint32_t **)instr;
  180 
  181                 if (ptr >= (uint32_t *) symval->value && ptr < limit) {
  182                         instr++;
  183                         goto again;
  184                 }
  185         }
  186 
  187         if (*instr != FBT_MTLR_R0) {
  188                 instr++;
  189                 goto again;
  190         }
  191 
  192         instr++;
  193 
  194         for (j = 0; j < 12 && instr < limit; j++, instr++) {
  195                 if ((*instr == FBT_BCTR) || (*instr == FBT_BLR) ||
  196                     FBT_IS_JUMP(*instr))
  197                         break;
  198         }
  199 
  200         if (!(*instr == FBT_BCTR || *instr == FBT_BLR || FBT_IS_JUMP(*instr)))
  201                 goto again;
  202 
  203         /*
  204          * We have a winner!
  205          */
  206         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  207         fbt->fbtp_name = name;
  208 
  209         if (retfbt == NULL) {
  210                 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  211                     name, FBT_RETURN, FBT_AFRAMES, fbt);
  212         } else {
  213                 retfbt->fbtp_probenext = fbt;
  214                 fbt->fbtp_id = retfbt->fbtp_id;
  215         }
  216 
  217         retfbt = fbt;
  218         fbt->fbtp_patchpoint = instr;
  219         fbt->fbtp_ctl = lf;
  220         fbt->fbtp_loadcnt = lf->loadcnt;
  221         fbt->fbtp_symindx = symindx;
  222 
  223         if (*instr == FBT_BCTR)
  224                 fbt->fbtp_rval = DTRACE_INVOP_BCTR;
  225         else if (*instr == FBT_BLR)
  226                 fbt->fbtp_rval = DTRACE_INVOP_BLR;
  227         else
  228                 fbt->fbtp_rval = DTRACE_INVOP_JUMP;
  229 
  230         fbt->fbtp_roffset =
  231             (uintptr_t)((uint8_t *)instr - (uint8_t *)symval->value);
  232 
  233         fbt->fbtp_savedval = *instr;
  234         fbt->fbtp_patchval = FBT_PATCHVAL;
  235         fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
  236         fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
  237 
  238         lf->fbt_nentries++;
  239 
  240         instr += 4;
  241         goto again;
  242 }

Cache object: ed80f31ce08f74a6b73ac857f42dfa0f


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