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/dtrace/riscv/dtrace_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, 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  * Portions Copyright 2016 Ruslan Bukin <br@bsdpad.com>
   23  *
   24  * $FreeBSD$
   25  */
   26 /*
   27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
   28  * Use is subject to license terms.
   29  */
   30 #include <sys/cdefs.h>
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/stack.h>
   36 #include <sys/pcpu.h>
   37 
   38 #include <machine/frame.h>
   39 #include <machine/md_var.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/vm_param.h>
   43 #include <vm/pmap.h>
   44 
   45 #include <machine/atomic.h>
   46 #include <machine/db_machdep.h>
   47 #include <machine/md_var.h>
   48 #include <machine/stack.h>
   49 #include <ddb/db_sym.h>
   50 #include <ddb/ddb.h>
   51 #include <sys/kdb.h>
   52 
   53 #include "regset.h"
   54 
   55 #define MAX_USTACK_DEPTH  2048
   56 
   57 uint8_t dtrace_fuword8_nocheck(void *);
   58 uint16_t dtrace_fuword16_nocheck(void *);
   59 uint32_t dtrace_fuword32_nocheck(void *);
   60 uint64_t dtrace_fuword64_nocheck(void *);
   61 
   62 void
   63 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
   64     uint32_t *intrpc)
   65 {
   66         struct unwind_state state;
   67         uintptr_t caller;
   68         register_t sp;
   69         int scp_offset;
   70         int depth;
   71 
   72         depth = 0;
   73         caller = solaris_cpu[curcpu].cpu_dtrace_caller;
   74 
   75         if (intrpc != 0) {
   76                 pcstack[depth++] = (pc_t)intrpc;
   77         }
   78 
   79         /*
   80          * Construct the unwind state, starting from this function. This frame,
   81          * and 'aframes' others will be skipped.
   82          */
   83         __asm __volatile("mv %0, sp" : "=&r" (sp));
   84 
   85         state.fp = (uintptr_t)__builtin_frame_address(0);
   86         state.sp = (uintptr_t)sp;
   87         state.pc = (uintptr_t)dtrace_getpcstack;
   88 
   89         while (depth < pcstack_limit) {
   90                 if (!unwind_frame(curthread, &state))
   91                         break;
   92 
   93                 if (!INKERNEL(state.pc) || !kstack_contains(curthread,
   94                     (vm_offset_t)state.fp, sizeof(uintptr_t)))
   95                         break;
   96 
   97                 if (aframes > 0) {
   98                         aframes--;
   99 
  100                         /*
  101                          * fbt_invop() records the return address at the time
  102                          * the FBT probe fires. We need to insert this into the
  103                          * backtrace manually, since the stack frame state at
  104                          * the time of the probe does not capture it.
  105                          */
  106                         if (aframes == 0 && caller != 0)
  107                                 pcstack[depth++] = caller;
  108                 } else {
  109                         pcstack[depth++] = state.pc;
  110                 }
  111         }
  112 
  113         for (; depth < pcstack_limit; depth++) {
  114                 pcstack[depth] = 0;
  115         }
  116 }
  117 
  118 static int
  119 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
  120     uintptr_t fp)
  121 {
  122         volatile uint16_t *flags;
  123         uintptr_t oldfp;
  124         int ret;
  125 
  126         oldfp = fp;
  127         ret = 0;
  128         flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
  129 
  130         ASSERT(pcstack == NULL || pcstack_limit > 0);
  131 
  132         while (pc != 0) {
  133                 /*
  134                  * We limit the number of times we can go around this
  135                  * loop to account for a circular stack.
  136                  */
  137                 if (ret++ >= MAX_USTACK_DEPTH) {
  138                         *flags |= CPU_DTRACE_BADSTACK;
  139                         cpu_core[curcpu].cpuc_dtrace_illval = fp;
  140                         break;
  141                 }
  142 
  143                 if (pcstack != NULL) {
  144                         *pcstack++ = (uint64_t)pc;
  145                         pcstack_limit--;
  146                         if (pcstack_limit <= 0)
  147                                 break;
  148                 }
  149 
  150                 if (fp == 0)
  151                         break;
  152 
  153                 pc = dtrace_fuword64((void *)(fp +
  154                     offsetof(struct riscv_frame, f_retaddr)));
  155                 fp = dtrace_fuword64((void *)fp);
  156 
  157                 if (fp == oldfp) {
  158                         *flags |= CPU_DTRACE_BADSTACK;
  159                         cpu_core[curcpu].cpuc_dtrace_illval = fp;
  160                         break;
  161                 }
  162                 oldfp = fp;
  163         }
  164 
  165         return (ret);
  166 }
  167 
  168 void
  169 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
  170 {
  171         volatile uint16_t *flags;
  172         struct trapframe *tf;
  173         uintptr_t pc, sp, fp;
  174         proc_t *p;
  175         int n;
  176 
  177         p = curproc;
  178         flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
  179 
  180         if (*flags & CPU_DTRACE_FAULT)
  181                 return;
  182 
  183         if (pcstack_limit <= 0)
  184                 return;
  185 
  186         /*
  187          * If there's no user context we still need to zero the stack.
  188          */
  189         if (p == NULL || (tf = curthread->td_frame) == NULL)
  190                 goto zero;
  191 
  192         *pcstack++ = (uint64_t)p->p_pid;
  193         pcstack_limit--;
  194 
  195         if (pcstack_limit <= 0)
  196                 return;
  197 
  198         pc = tf->tf_sepc;
  199         sp = tf->tf_sp;
  200         fp = tf->tf_s[0];
  201 
  202         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
  203                 /*
  204                  * In an entry probe.  The frame pointer has not yet been
  205                  * pushed (that happens in the function prologue).  The
  206                  * best approach is to add the current pc as a missing top
  207                  * of stack and back the pc up to the caller, which is stored
  208                  * at the current stack pointer address since the call
  209                  * instruction puts it there right before the branch.
  210                  */
  211 
  212                 *pcstack++ = (uint64_t)pc;
  213                 pcstack_limit--;
  214                 if (pcstack_limit <= 0)
  215                         return;
  216 
  217                 pc = tf->tf_ra;
  218         }
  219 
  220         n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
  221         ASSERT(n >= 0);
  222         ASSERT(n <= pcstack_limit);
  223 
  224         pcstack += n;
  225         pcstack_limit -= n;
  226 
  227 zero:
  228         while (pcstack_limit-- > 0)
  229                 *pcstack++ = 0;
  230 }
  231 
  232 int
  233 dtrace_getustackdepth(void)
  234 {
  235 
  236         printf("IMPLEMENT ME: %s\n", __func__);
  237 
  238         return (0);
  239 }
  240 
  241 void
  242 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
  243 {
  244 
  245         printf("IMPLEMENT ME: %s\n", __func__);
  246 }
  247 
  248 /*ARGSUSED*/
  249 uint64_t
  250 dtrace_getarg(int arg, int aframes)
  251 {
  252 
  253         printf("IMPLEMENT ME: %s\n", __func__);
  254 
  255         return (0);
  256 }
  257 
  258 int
  259 dtrace_getstackdepth(int aframes)
  260 {
  261         struct unwind_state state;
  262         int scp_offset;
  263         register_t sp;
  264         int depth;
  265         bool done;
  266 
  267         depth = 1;
  268         done = false;
  269 
  270         __asm __volatile("mv %0, sp" : "=&r" (sp));
  271 
  272         state.fp = (uintptr_t)__builtin_frame_address(0);
  273         state.sp = sp;
  274         state.pc = (uintptr_t)dtrace_getstackdepth;
  275 
  276         do {
  277                 done = !unwind_frame(curthread, &state);
  278                 if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
  279                         break;
  280                 depth++;
  281         } while (!done);
  282 
  283         if (depth < aframes)
  284                 return (0);
  285         else
  286                 return (depth - aframes);
  287 }
  288 
  289 ulong_t
  290 dtrace_getreg(struct trapframe *rp, uint_t reg)
  291 {
  292 
  293         printf("IMPLEMENT ME: %s\n", __func__);
  294 
  295         return (0);
  296 }
  297 
  298 static int
  299 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
  300 {
  301 
  302         if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
  303                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
  304                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
  305                 return (0);
  306         }
  307 
  308         return (1);
  309 }
  310 
  311 void
  312 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
  313     volatile uint16_t *flags)
  314 {
  315 
  316         if (dtrace_copycheck(uaddr, kaddr, size))
  317                 dtrace_copy(uaddr, kaddr, size);
  318 }
  319 
  320 void
  321 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
  322     volatile uint16_t *flags)
  323 {
  324 
  325         if (dtrace_copycheck(uaddr, kaddr, size))
  326                 dtrace_copy(kaddr, uaddr, size);
  327 }
  328 
  329 void
  330 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
  331     volatile uint16_t *flags)
  332 {
  333 
  334         if (dtrace_copycheck(uaddr, kaddr, size))
  335                 dtrace_copystr(uaddr, kaddr, size, flags);
  336 }
  337 
  338 void
  339 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
  340     volatile uint16_t *flags)
  341 {
  342 
  343         if (dtrace_copycheck(uaddr, kaddr, size))
  344                 dtrace_copystr(kaddr, uaddr, size, flags);
  345 }
  346 
  347 uint8_t
  348 dtrace_fuword8(void *uaddr)
  349 {
  350 
  351         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
  352                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
  353                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
  354                 return (0);
  355         }
  356 
  357         return (dtrace_fuword8_nocheck(uaddr));
  358 }
  359 
  360 uint16_t
  361 dtrace_fuword16(void *uaddr)
  362 {
  363 
  364         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
  365                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
  366                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
  367                 return (0);
  368         }
  369 
  370         return (dtrace_fuword16_nocheck(uaddr));
  371 }
  372 
  373 uint32_t
  374 dtrace_fuword32(void *uaddr)
  375 {
  376 
  377         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
  378                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
  379                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
  380                 return (0);
  381         }
  382 
  383         return (dtrace_fuword32_nocheck(uaddr));
  384 }
  385 
  386 uint64_t
  387 dtrace_fuword64(void *uaddr)
  388 {
  389 
  390         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
  391                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
  392                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
  393                 return (0);
  394         }
  395 
  396         return (dtrace_fuword64_nocheck(uaddr));
  397 }

Cache object: 7117dcd849b7b371f432b7e9eef37045


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