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/aarch64/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  * Portions Copyright 2013 Howard Su howardsu@freebsd.org
   24  * Portions Copyright 2015 Ruslan Bukin <br@bsdpad.com>
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 /*
   30  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   31  * Use is subject to license terms.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 #include <sys/param.h>
   36 
   37 #include <sys/dtrace.h>
   38 
   39 #include "fbt.h"
   40 
   41 #define AARCH64_BRK             0xd4200000
   42 #define AARCH64_BRK_IMM16_SHIFT 5
   43 #define AARCH64_BRK_IMM16_VAL   (0x40d << AARCH64_BRK_IMM16_SHIFT)
   44 #define FBT_PATCHVAL            (AARCH64_BRK | AARCH64_BRK_IMM16_VAL)
   45 #define FBT_ENTRY       "entry"
   46 #define FBT_RETURN      "return"
   47 #define FBT_AFRAMES     4
   48 
   49 int
   50 fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
   51 {
   52         solaris_cpu_t *cpu;
   53         fbt_probe_t *fbt;
   54 
   55         cpu = &solaris_cpu[curcpu];
   56         fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
   57 
   58         for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
   59                 if ((uintptr_t)fbt->fbtp_patchpoint != addr)
   60                         continue;
   61 
   62                 cpu->cpu_dtrace_caller = addr;
   63 
   64                 if (fbt->fbtp_roffset == 0) {
   65                         dtrace_probe(fbt->fbtp_id, frame->tf_x[0],
   66                             frame->tf_x[1], frame->tf_x[2],
   67                             frame->tf_x[3], frame->tf_x[4]);
   68                 } else {
   69                         dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, rval,
   70                             0, 0, 0);
   71                 }
   72                 cpu->cpu_dtrace_caller = 0;
   73                 return (fbt->fbtp_savedval);
   74         }
   75 
   76         return (0);
   77 }
   78 
   79 void
   80 fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
   81 {
   82         vm_offset_t addr;
   83 
   84         if (!arm64_get_writable_addr((vm_offset_t)fbt->fbtp_patchpoint, &addr))
   85                 panic("%s: Unable to write new instruction", __func__);
   86 
   87         *(fbt_patchval_t *)addr = val;
   88         cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4);
   89 }
   90 
   91 int
   92 fbt_provide_module_function(linker_file_t lf, int symindx,
   93     linker_symval_t *symval, void *opaque)
   94 {
   95         fbt_probe_t *fbt, *retfbt;
   96         uint32_t *target, *start;
   97         uint32_t *instr, *limit;
   98         const char *name;
   99         char *modname;
  100         bool found;
  101         int offs;
  102 
  103         modname = opaque;
  104         name = symval->name;
  105 
  106         /* Check if function is excluded from instrumentation */
  107         if (fbt_excluded(name))
  108                 return (0);
  109 
  110         /*
  111          * Instrumenting certain exception handling functions can lead to FBT
  112          * recursion, so exclude from instrumentation.
  113          */
  114          if (strcmp(name, "handle_el1h_sync") == 0 ||
  115             strcmp(name, "do_el1h_sync") == 0)
  116                 return (1);
  117 
  118         instr = (uint32_t *)(symval->value);
  119         limit = (uint32_t *)(symval->value + symval->size);
  120 
  121         /*
  122          * Ignore any bti instruction at the start of the function
  123          * we need to keep it there for any indirect branches calling
  124          * the function on Armv8.5+
  125          */
  126         if ((*instr & BTI_MASK) == BTI_INSTR)
  127                 instr++;
  128 
  129         /* Look for stp (pre-indexed) operation */
  130         found = false;
  131         /*
  132          * If the first instruction is a nop it's a specially marked
  133          * asm function. We only support a nop first as it's not a normal
  134          * part of the function prologue.
  135          */
  136         if (*instr == NOP_INSTR)
  137                 found = true;
  138         if (!found) {
  139                 for (; instr < limit; instr++) {
  140                         /*
  141                          * Some functions start with
  142                          * "stp xt1, xt2, [xn, <const>]!"
  143                          */
  144                         if ((*instr & LDP_STP_MASK) == STP_64) {
  145                                 /*
  146                                  * Assume any other store of this type means we
  147                                  * are past the function prolog.
  148                                  */
  149                                 if (((*instr >> ADDR_SHIFT) & ADDR_MASK) == 31)
  150                                         found = true;
  151                                 break;
  152                         }
  153 
  154                         /*
  155                          * Some functions start with a "sub sp, sp, <const>"
  156                          * Sometimes the compiler will have a sub instruction
  157                          * that is not of the above type so don't stop if we
  158                          * see one.
  159                          */
  160                         if ((*instr & SUB_MASK) == SUB_INSTR &&
  161                             ((*instr >> SUB_RD_SHIFT) & SUB_R_MASK) == 31 &&
  162                             ((*instr >> SUB_RN_SHIFT) & SUB_R_MASK) == 31) {
  163                                 found = true;
  164                                 break;
  165                         }
  166                 }
  167         }
  168 
  169         if (!found)
  170                 return (0);
  171 
  172         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  173         fbt->fbtp_name = name;
  174         fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  175             name, FBT_ENTRY, FBT_AFRAMES, fbt);
  176         fbt->fbtp_patchpoint = instr;
  177         fbt->fbtp_ctl = lf;
  178         fbt->fbtp_loadcnt = lf->loadcnt;
  179         fbt->fbtp_savedval = *instr;
  180         fbt->fbtp_patchval = FBT_PATCHVAL;
  181         if ((*instr & SUB_MASK) == SUB_INSTR)
  182                 fbt->fbtp_rval = DTRACE_INVOP_SUB;
  183         else
  184                 fbt->fbtp_rval = DTRACE_INVOP_STP;
  185         fbt->fbtp_symindx = symindx;
  186 
  187         fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
  188         fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
  189 
  190         lf->fbt_nentries++;
  191 
  192         retfbt = NULL;
  193 again:
  194         for (; instr < limit; instr++) {
  195                 if (*instr == RET_INSTR)
  196                         break;
  197                 else if ((*instr & B_MASK) == B_INSTR) {
  198                         offs = (*instr & B_DATA_MASK);
  199                         offs *= 4;
  200                         target = (instr + offs);
  201                         start = (uint32_t *)symval->value;
  202                         if (target >= limit || target < start)
  203                                 break;
  204                 }
  205         }
  206 
  207         if (instr >= limit)
  208                 return (0);
  209 
  210         /*
  211          * We have a winner!
  212          */
  213         fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
  214         fbt->fbtp_name = name;
  215         if (retfbt == NULL) {
  216                 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
  217                     name, FBT_RETURN, FBT_AFRAMES, fbt);
  218         } else {
  219                 retfbt->fbtp_probenext = fbt;
  220                 fbt->fbtp_id = retfbt->fbtp_id;
  221         }
  222         retfbt = fbt;
  223 
  224         fbt->fbtp_patchpoint = instr;
  225         fbt->fbtp_ctl = lf;
  226         fbt->fbtp_loadcnt = lf->loadcnt;
  227         fbt->fbtp_symindx = symindx;
  228         if ((*instr & B_MASK) == B_INSTR)
  229                 fbt->fbtp_rval = DTRACE_INVOP_B;
  230         else
  231                 fbt->fbtp_rval = DTRACE_INVOP_RET;
  232         fbt->fbtp_roffset = (uintptr_t)instr - (uintptr_t)symval->value;
  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++;
  241         goto again;
  242 }

Cache object: f78d7654b815bf2052284c9a570a7e36


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