Path: blob/main/sys/cddl/dev/dtrace/i386/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>36#include <machine/pcb.h>37#include <machine/stack.h>3839#include <vm/vm.h>40#include <vm/vm_param.h>41#include <vm/pmap.h>4243#include "regset.h"4445extern uintptr_t kernbase;46uintptr_t kernelbase = (uintptr_t) &kernbase;4748uint8_t dtrace_fuword8_nocheck(void *);49uint16_t dtrace_fuword16_nocheck(void *);50uint32_t dtrace_fuword32_nocheck(void *);51uint64_t dtrace_fuword64_nocheck(void *);5253int dtrace_ustackdepth_max = 2048;5455void56dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,57uint32_t *intrpc)58{59int depth = 0;60register_t ebp;61struct i386_frame *frame;62vm_offset_t callpc;63pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;6465if (intrpc != 0)66pcstack[depth++] = (pc_t) intrpc;6768aframes++;6970__asm __volatile("movl %%ebp,%0" : "=r" (ebp));7172frame = (struct i386_frame *)ebp;73while (depth < pcstack_limit) {74if (!kstack_contains(curthread, (vm_offset_t)frame,75sizeof(*frame)))76break;7778callpc = frame->f_retaddr;7980if (!INKERNEL(callpc))81break;8283if (aframes > 0) {84aframes--;85if ((aframes == 0) && (caller != 0)) {86pcstack[depth++] = caller;87}88}89else {90pcstack[depth++] = callpc;91}9293if (frame->f_frame <= frame)94break;95frame = frame->f_frame;96}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 sp)106{107#ifdef notyet108proc_t *p = curproc;109uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */110size_t s1, s2;111#endif112uintptr_t oldsp;113volatile uint16_t *flags =114(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;115int ret = 0;116117ASSERT(pcstack == NULL || pcstack_limit > 0);118ASSERT(dtrace_ustackdepth_max > 0);119120#ifdef notyet /* XXX signal stack. */121if (p->p_model == DATAMODEL_NATIVE) {122s1 = sizeof (struct frame) + 2 * sizeof (long);123s2 = s1 + sizeof (siginfo_t);124} else {125s1 = sizeof (struct frame32) + 3 * sizeof (int);126s2 = s1 + sizeof (siginfo32_t);127}128#endif129130while (pc != 0) {131/*132* We limit the number of times we can go around this133* loop to account for a circular stack.134*/135if (ret++ >= dtrace_ustackdepth_max) {136*flags |= CPU_DTRACE_BADSTACK;137cpu_core[curcpu].cpuc_dtrace_illval = sp;138break;139}140141if (pcstack != NULL) {142*pcstack++ = (uint64_t)pc;143pcstack_limit--;144if (pcstack_limit <= 0)145break;146}147148if (sp == 0)149break;150151oldsp = sp;152153#ifdef notyet /* XXX signal stack. */154if (oldcontext == sp + s1 || oldcontext == sp + s2) {155if (p->p_model == DATAMODEL_NATIVE) {156ucontext_t *ucp = (ucontext_t *)oldcontext;157greg_t *gregs = ucp->uc_mcontext.gregs;158159sp = dtrace_fulword(&gregs[REG_FP]);160pc = dtrace_fulword(&gregs[REG_PC]);161162oldcontext = dtrace_fulword(&ucp->uc_link);163} else {164ucontext32_t *ucp = (ucontext32_t *)oldcontext;165greg32_t *gregs = ucp->uc_mcontext.gregs;166167sp = dtrace_fuword32(&gregs[EBP]);168pc = dtrace_fuword32(&gregs[EIP]);169170oldcontext = dtrace_fuword32(&ucp->uc_link);171}172} else {173if (p->p_model == DATAMODEL_NATIVE) {174struct frame *fr = (struct frame *)sp;175176pc = dtrace_fulword(&fr->fr_savpc);177sp = dtrace_fulword(&fr->fr_savfp);178} else {179struct frame32 *fr = (struct frame32 *)sp;180181pc = dtrace_fuword32(&fr->fr_savpc);182sp = dtrace_fuword32(&fr->fr_savfp);183}184}185#else186pc = dtrace_fuword32((void *)(sp +187offsetof(struct i386_frame, f_retaddr)));188sp = dtrace_fuword32((void *)sp);189#endif /* ! notyet */190191if (sp == oldsp) {192*flags |= CPU_DTRACE_BADSTACK;193cpu_core[curcpu].cpuc_dtrace_illval = sp;194break;195}196197/*198* This is totally bogus: if we faulted, we're going to clear199* the fault and break. This is to deal with the apparently200* broken Java stacks on x86.201*/202if (*flags & CPU_DTRACE_FAULT) {203*flags &= ~CPU_DTRACE_FAULT;204break;205}206}207208return (ret);209}210211void212dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)213{214proc_t *p = curproc;215struct trapframe *tf;216uintptr_t pc, sp, fp;217volatile uint16_t *flags =218(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;219int n;220221if (*flags & CPU_DTRACE_FAULT)222return;223224if (pcstack_limit <= 0)225return;226227/*228* If there's no user context we still need to zero the stack.229*/230if (p == NULL || (tf = curthread->td_frame) == NULL)231goto zero;232233*pcstack++ = (uint64_t)p->p_pid;234pcstack_limit--;235236if (pcstack_limit <= 0)237return;238239pc = tf->tf_eip;240fp = tf->tf_ebp;241sp = tf->tf_esp;242243if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {244/*245* In an entry probe. The frame pointer has not yet been246* pushed (that happens in the function prologue). The247* best approach is to add the current pc as a missing top248* of stack and back the pc up to the caller, which is stored249* at the current stack pointer address since the call250* instruction puts it there right before the branch.251*/252253*pcstack++ = (uint64_t)pc;254pcstack_limit--;255if (pcstack_limit <= 0)256return;257258pc = dtrace_fuword32((void *) sp);259}260261n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);262ASSERT(n >= 0);263ASSERT(n <= pcstack_limit);264265pcstack += n;266pcstack_limit -= n;267268zero:269while (pcstack_limit-- > 0)270*pcstack++ = 0;271}272273int274dtrace_getustackdepth(void)275{276proc_t *p = curproc;277struct trapframe *tf;278uintptr_t pc, fp, sp;279int n = 0;280281if (p == NULL || (tf = curthread->td_frame) == NULL)282return (0);283284if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))285return (-1);286287pc = tf->tf_eip;288fp = tf->tf_ebp;289sp = tf->tf_esp;290291if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {292/*293* In an entry probe. The frame pointer has not yet been294* pushed (that happens in the function prologue). The295* best approach is to add the current pc as a missing top296* of stack and back the pc up to the caller, which is stored297* at the current stack pointer address since the call298* instruction puts it there right before the branch.299*/300301pc = dtrace_fuword32((void *) sp);302n++;303}304305n += dtrace_getustack_common(NULL, 0, pc, fp);306307return (n);308}309310void311dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)312{313proc_t *p = curproc;314struct trapframe *tf;315uintptr_t pc, sp, fp;316volatile uint16_t *flags =317(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;318#ifdef notyet /* XXX signal stack */319uintptr_t oldcontext;320size_t s1, s2;321#endif322323if (*flags & CPU_DTRACE_FAULT)324return;325326if (pcstack_limit <= 0)327return;328329/*330* If there's no user context we still need to zero the stack.331*/332if (p == NULL || (tf = curthread->td_frame) == NULL)333goto zero;334335*pcstack++ = (uint64_t)p->p_pid;336pcstack_limit--;337338if (pcstack_limit <= 0)339return;340341pc = tf->tf_eip;342fp = tf->tf_ebp;343sp = tf->tf_esp;344345#ifdef notyet /* XXX signal stack */346oldcontext = lwp->lwp_oldcontext;347348if (p->p_model == DATAMODEL_NATIVE) {349s1 = sizeof (struct frame) + 2 * sizeof (long);350s2 = s1 + sizeof (siginfo_t);351} else {352s1 = sizeof (struct frame32) + 3 * sizeof (int);353s2 = s1 + sizeof (siginfo32_t);354}355#endif356357if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {358*pcstack++ = (uint64_t)pc;359*fpstack++ = 0;360pcstack_limit--;361if (pcstack_limit <= 0)362return;363364pc = dtrace_fuword32((void *)sp);365}366367while (pc != 0) {368*pcstack++ = (uint64_t)pc;369*fpstack++ = fp;370pcstack_limit--;371if (pcstack_limit <= 0)372break;373374if (fp == 0)375break;376377#ifdef notyet /* XXX signal stack */378if (oldcontext == sp + s1 || oldcontext == sp + s2) {379if (p->p_model == DATAMODEL_NATIVE) {380ucontext_t *ucp = (ucontext_t *)oldcontext;381greg_t *gregs = ucp->uc_mcontext.gregs;382383sp = dtrace_fulword(&gregs[REG_FP]);384pc = dtrace_fulword(&gregs[REG_PC]);385386oldcontext = dtrace_fulword(&ucp->uc_link);387} else {388ucontext_t *ucp = (ucontext_t *)oldcontext;389greg_t *gregs = ucp->uc_mcontext.gregs;390391sp = dtrace_fuword32(&gregs[EBP]);392pc = dtrace_fuword32(&gregs[EIP]);393394oldcontext = dtrace_fuword32(&ucp->uc_link);395}396} else397#endif /* XXX */398{399pc = dtrace_fuword32((void *)(fp +400offsetof(struct i386_frame, f_retaddr)));401fp = dtrace_fuword32((void *)fp);402}403404/*405* This is totally bogus: if we faulted, we're going to clear406* the fault and break. This is to deal with the apparently407* broken Java stacks on x86.408*/409if (*flags & CPU_DTRACE_FAULT) {410*flags &= ~CPU_DTRACE_FAULT;411break;412}413}414415zero:416while (pcstack_limit-- > 0)417*pcstack++ = 0;418}419420uint64_t421dtrace_getarg(int arg, int aframes)422{423struct trapframe *frame;424struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();425uintptr_t *stack, val;426int i;427428for (i = 1; i <= aframes; i++) {429fp = fp->f_frame;430431if (roundup2(fp->f_retaddr, 4) ==432(long)dtrace_invop_callsite) {433/*434* If we pass through the invalid op handler, we will435* use the trap frame pointer that it pushed on the436* stack as the second argument to dtrace_invop() as437* the pointer to the stack. When using this stack, we438* must skip the third argument to dtrace_invop(),439* which is included in the i386_frame.440*/441frame = (struct trapframe *)(((uintptr_t **)&fp[1])[0]);442/*443* Skip the three hardware-saved registers and the444* return address.445*/446stack = (uintptr_t *)frame->tf_isp + 4;447goto load;448}449450}451452/*453* We know that we did not come through a trap to get into454* dtrace_probe() -- the provider simply called dtrace_probe()455* directly. As this is the case, we need to shift the argument456* that we're looking for: the probe ID is the first argument to457* dtrace_probe(), so the argument n will actually be found where458* one would expect to find argument (n + 1).459*/460arg++;461462stack = (uintptr_t *)fp + 2;463464load:465DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);466val = stack[arg];467DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);468469return (val);470}471472int473dtrace_getstackdepth(int aframes)474{475int depth = 0;476struct i386_frame *frame;477vm_offset_t ebp;478479aframes++;480ebp = dtrace_getfp();481frame = (struct i386_frame *)ebp;482depth++;483for(;;) {484if (!kstack_contains(curthread, (vm_offset_t)frame,485sizeof(*frame)))486break;487depth++;488if (frame->f_frame <= frame)489break;490frame = frame->f_frame;491}492if (depth < aframes)493return 0;494else495return depth - aframes;496}497498ulong_t499dtrace_getreg(struct trapframe *frame, uint_t reg)500{501struct pcb *pcb;502int regmap[] = { /* Order is dependent on reg.d */503REG_GS, /* 0 GS */504REG_FS, /* 1 FS */505REG_ES, /* 2 ES */506REG_DS, /* 3 DS */507REG_RDI, /* 4 EDI */508REG_RSI, /* 5 ESI */509REG_RBP, /* 6 EBP, REG_FP */510REG_RSP, /* 7 ESP */511REG_RBX, /* 8 EBX */512REG_RDX, /* 9 EDX, REG_R1 */513REG_RCX, /* 10 ECX */514REG_RAX, /* 11 EAX, REG_R0 */515REG_TRAPNO, /* 12 TRAPNO */516REG_ERR, /* 13 ERR */517REG_RIP, /* 14 EIP, REG_PC */518REG_CS, /* 15 CS */519REG_RFL, /* 16 EFL, REG_PS */520REG_RSP, /* 17 UESP, REG_SP */521REG_SS /* 18 SS */522};523524if (reg > SS) {525DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);526return (0);527}528529if (reg >= sizeof (regmap) / sizeof (int)) {530DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);531return (0);532}533534reg = regmap[reg];535536switch(reg) {537case REG_GS:538if ((pcb = curthread->td_pcb) == NULL) {539DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);540return (0);541}542return (pcb->pcb_gs);543case REG_FS:544return (frame->tf_fs);545case REG_ES:546return (frame->tf_es);547case REG_DS:548return (frame->tf_ds);549case REG_RDI:550return (frame->tf_edi);551case REG_RSI:552return (frame->tf_esi);553case REG_RBP:554return (frame->tf_ebp);555case REG_RSP:556return (frame->tf_isp);557case REG_RBX:558return (frame->tf_ebx);559case REG_RCX:560return (frame->tf_ecx);561case REG_RAX:562return (frame->tf_eax);563case REG_TRAPNO:564return (frame->tf_trapno);565case REG_ERR:566return (frame->tf_err);567case REG_RIP:568return (frame->tf_eip);569case REG_CS:570return (frame->tf_cs);571case REG_RFL:572return (frame->tf_eflags);573#if 0574case REG_RSP:575return (frame->tf_esp);576#endif577case REG_SS:578return (frame->tf_ss);579default:580DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);581return (0);582}583}584585static int586dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)587{588ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);589590if (uaddr + size >= kernelbase || uaddr + size < uaddr) {591DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);592cpu_core[curcpu].cpuc_dtrace_illval = uaddr;593return (0);594}595596return (1);597}598599void600dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,601volatile uint16_t *flags)602{603if (dtrace_copycheck(uaddr, kaddr, size))604dtrace_copy(uaddr, kaddr, size);605}606607void608dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,609volatile uint16_t *flags)610{611if (dtrace_copycheck(uaddr, kaddr, size))612dtrace_copy(kaddr, uaddr, size);613}614615void616dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,617volatile uint16_t *flags)618{619if (dtrace_copycheck(uaddr, kaddr, size))620dtrace_copystr(uaddr, kaddr, size, flags);621}622623void624dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,625volatile uint16_t *flags)626{627if (dtrace_copycheck(uaddr, kaddr, size))628dtrace_copystr(kaddr, uaddr, size, flags);629}630631uint8_t632dtrace_fuword8(void *uaddr)633{634if ((uintptr_t)uaddr >= kernelbase) {635DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);636cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;637return (0);638}639return (dtrace_fuword8_nocheck(uaddr));640}641642uint16_t643dtrace_fuword16(void *uaddr)644{645if ((uintptr_t)uaddr >= kernelbase) {646DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);647cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;648return (0);649}650return (dtrace_fuword16_nocheck(uaddr));651}652653uint32_t654dtrace_fuword32(void *uaddr)655{656if ((uintptr_t)uaddr >= kernelbase) {657DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);658cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;659return (0);660}661return (dtrace_fuword32_nocheck(uaddr));662}663664uint64_t665dtrace_fuword64(void *uaddr)666{667if ((uintptr_t)uaddr >= kernelbase) {668DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);669cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;670return (0);671}672return (dtrace_fuword64_nocheck(uaddr));673}674675676