Path: blob/main/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c
48375 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright 2005 Sun Microsystems, Inc. All rights reserved.23* Use is subject to license terms.24*/25#include <sys/cdefs.h>2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/dtrace_impl.h>30#include <sys/kernel.h>31#include <sys/stack.h>32#include <sys/pcpu.h>3334#include <machine/frame.h>35#include <machine/md_var.h>3637#include <vm/vm.h>38#include <vm/vm_param.h>39#include <vm/pmap.h>4041#include <machine/atomic.h>42#include <machine/db_machdep.h>43#include <machine/md_var.h>44#include <machine/stack.h>45#include <ddb/db_sym.h>46#include <ddb/ddb.h>47#include <sys/kdb.h>4849#include <cddl/dev/dtrace/dtrace_cddl.h>5051#include "regset.h"5253#define MAX_USTACK_DEPTH 20485455uint8_t dtrace_fuword8_nocheck(void *);56uint16_t dtrace_fuword16_nocheck(void *);57uint32_t dtrace_fuword32_nocheck(void *);58uint64_t dtrace_fuword64_nocheck(void *);5960void61dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,62uint32_t *intrpc)63{64struct unwind_state state;65int scp_offset;66int depth;6768depth = 0;6970if (intrpc != 0) {71pcstack[depth++] = (pc_t) intrpc;72}7374aframes++;7576state.fp = (uintptr_t)__builtin_frame_address(0);77state.pc = (uintptr_t)dtrace_getpcstack;7879while (depth < pcstack_limit) {80if (!unwind_frame(curthread, &state))81break;82if (!INKERNEL(state.pc))83break;8485/*86* NB: Unlike some other architectures, we don't need to87* explicitly insert cpu_dtrace_caller as it appears in the88* normal kernel stack trace rather than a special trap frame.89*/90if (aframes > 0) {91aframes--;92} else {93pcstack[depth++] = state.pc;94}9596}9798for (; depth < pcstack_limit; depth++) {99pcstack[depth] = 0;100}101}102103static int104dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,105uintptr_t fp)106{107volatile uint16_t *flags =108(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;109int ret = 0;110uintptr_t oldfp = fp;111112ASSERT(pcstack == NULL || pcstack_limit > 0);113114while (pc != 0) {115/*116* We limit the number of times we can go around this117* loop to account for a circular stack.118*/119if (ret++ >= MAX_USTACK_DEPTH) {120*flags |= CPU_DTRACE_BADSTACK;121cpu_core[curcpu].cpuc_dtrace_illval = fp;122break;123}124125if (pcstack != NULL) {126*pcstack++ = (uint64_t)pc;127pcstack_limit--;128if (pcstack_limit <= 0)129break;130}131132if (fp == 0)133break;134135pc = dtrace_fuword64((void *)(fp +136offsetof(struct unwind_state, pc)));137fp = dtrace_fuword64((void *)fp);138139if (fp == oldfp) {140*flags |= CPU_DTRACE_BADSTACK;141cpu_core[curcpu].cpuc_dtrace_illval = fp;142break;143}144145/*146* ARM64TODO:147* This workaround might not be necessary. It needs to be148* revised and removed from all architectures if found149* unwanted. Leaving the original x86 comment for reference.150*151* This is totally bogus: if we faulted, we're going to clear152* the fault and break. This is to deal with the apparently153* broken Java stacks on x86.154*/155if (*flags & CPU_DTRACE_FAULT) {156*flags &= ~CPU_DTRACE_FAULT;157break;158}159160oldfp = fp;161}162163return (ret);164}165166void167dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)168{169proc_t *p = curproc;170struct trapframe *tf;171uintptr_t pc, fp;172volatile uint16_t *flags =173(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;174int n;175176if (*flags & CPU_DTRACE_FAULT)177return;178179if (pcstack_limit <= 0)180return;181182/*183* If there's no user context we still need to zero the stack.184*/185if (p == NULL || (tf = curthread->td_frame) == NULL)186goto zero;187188*pcstack++ = (uint64_t)p->p_pid;189pcstack_limit--;190191if (pcstack_limit <= 0)192return;193194pc = tf->tf_elr;195fp = tf->tf_x[29];196197if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {198/*199* In an entry probe. The frame pointer has not yet been200* pushed (that happens in the function prologue). The201* best approach is to add the current pc as a missing top202* of stack and back the pc up to the caller, which is stored203* at the current stack pointer address since the call204* instruction puts it there right before the branch.205*/206207*pcstack++ = (uint64_t)pc;208pcstack_limit--;209if (pcstack_limit <= 0)210return;211212pc = tf->tf_lr;213}214215n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);216ASSERT(n >= 0);217ASSERT(n <= pcstack_limit);218219pcstack += n;220pcstack_limit -= n;221222zero:223while (pcstack_limit-- > 0)224*pcstack++ = 0;225}226227int228dtrace_getustackdepth(void)229{230231printf("IMPLEMENT ME: %s\n", __func__);232233return (0);234}235236void237dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)238{239240printf("IMPLEMENT ME: %s\n", __func__);241}242243uint64_t244dtrace_getarg(int arg, int aframes __unused)245{246struct trapframe *tf;247248/*249* We only handle invop providers here.250*/251if ((tf = curthread->t_dtrace_trapframe) == NULL) {252DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);253return (0);254} else if (arg < 8) {255return (tf->tf_x[arg]);256} else {257uintptr_t p;258uint64_t val;259260p = (tf->tf_sp + (arg - 8) * sizeof(uint64_t));261if ((p & 7) != 0) {262DTRACE_CPUFLAG_SET(CPU_DTRACE_BADALIGN);263cpu_core[curcpu].cpuc_dtrace_illval = p;264return (0);265}266if (!kstack_contains(curthread, p, sizeof(uint64_t))) {267DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);268cpu_core[curcpu].cpuc_dtrace_illval = p;269return (0);270}271memcpy(&val, (void *)p, sizeof(uint64_t));272return (val);273}274}275276int277dtrace_getstackdepth(int aframes)278{279struct unwind_state state;280int scp_offset;281int depth;282bool done;283284depth = 1;285done = false;286287state.fp = (uintptr_t)__builtin_frame_address(0);288state.pc = (uintptr_t)dtrace_getstackdepth;289290do {291done = !unwind_frame(curthread, &state);292if (!INKERNEL(state.pc) || !INKERNEL(state.fp))293break;294depth++;295} while (!done);296297if (depth < aframes)298return (0);299else300return (depth - aframes);301}302303ulong_t304dtrace_getreg(struct trapframe *frame, uint_t reg)305{306switch (reg) {307case REG_X0 ... REG_X29:308return (frame->tf_x[reg]);309case REG_LR:310return (frame->tf_lr);311case REG_SP:312return (frame->tf_sp);313case REG_PC:314return (frame->tf_elr);315default:316DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);317return (0);318}319/* NOTREACHED */320}321322static int323dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)324{325326if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {327DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);328cpu_core[curcpu].cpuc_dtrace_illval = uaddr;329return (0);330}331332return (1);333}334335void336dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,337volatile uint16_t *flags)338{339340if (dtrace_copycheck(uaddr, kaddr, size))341dtrace_copy(uaddr, kaddr, size);342}343344void345dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,346volatile uint16_t *flags)347{348349if (dtrace_copycheck(uaddr, kaddr, size))350dtrace_copy(kaddr, uaddr, size);351}352353void354dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,355volatile uint16_t *flags)356{357358if (dtrace_copycheck(uaddr, kaddr, size))359dtrace_copystr(uaddr, kaddr, size, flags);360}361362void363dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,364volatile uint16_t *flags)365{366367if (dtrace_copycheck(uaddr, kaddr, size))368dtrace_copystr(kaddr, uaddr, size, flags);369}370371uint8_t372dtrace_fuword8(void *uaddr)373{374375if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {376DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);377cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;378return (0);379}380381return (dtrace_fuword8_nocheck(uaddr));382}383384uint16_t385dtrace_fuword16(void *uaddr)386{387388if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {389DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);390cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;391return (0);392}393394return (dtrace_fuword16_nocheck(uaddr));395}396397uint32_t398dtrace_fuword32(void *uaddr)399{400401if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {402DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);403cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;404return (0);405}406407return (dtrace_fuword32_nocheck(uaddr));408}409410uint64_t411dtrace_fuword64(void *uaddr)412{413414if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {415DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);416cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;417return (0);418}419420return (dtrace_fuword64_nocheck(uaddr));421}422423424