FreeBSD Bugzilla – Attachment 145544 Details for
Bug 192516
DTrace not yet supported on ARM
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch from Howard Su
dtrace.1121.diff (text/plain), 75.70 KB, created by
Rui Paulo
on 2014-08-09 03:39:12 UTC
(
hide
)
Description:
Patch from Howard Su
Filename:
MIME Type:
Creator:
Rui Paulo
Created:
2014-08-09 03:39:12 UTC
Size:
75.70 KB
patch
obsolete
>diff --git a/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c >new file mode 100644 >index 0000000..7e73794 >--- /dev/null >+++ b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c >@@ -0,0 +1,181 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ */ >+/* >+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+#pragma ident "%Z%%M% %I% %E% SMI" >+ >+#include <stdlib.h> >+#include <assert.h> >+#include <errno.h> >+#include <string.h> >+#include <libgen.h> >+ >+#include <dt_impl.h> >+#include <dt_pid.h> >+ >+#define OP(x) ((x) >> 30) >+#define OP2(x) (((x) >> 22) & 0x07) >+#define COND(x) (((x) >> 25) & 0x0f) >+#define A(x) (((x) >> 29) & 0x01) >+ >+#define OP_BRANCH 0 >+ >+#define OP2_BPcc 0x1 >+#define OP2_Bicc 0x2 >+#define OP2_BPr 0x3 >+#define OP2_FBPfcc 0x5 >+#define OP2_FBfcc 0x6 >+ >+/*ARGSUSED*/ >+int >+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, >+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) >+{ >+ ftp->ftps_type = DTFTP_ENTRY; >+ ftp->ftps_pc = (uintptr_t)symp->st_value; >+ ftp->ftps_size = (size_t)symp->st_size; >+ ftp->ftps_noffs = 1; >+ ftp->ftps_offs[0] = 0; >+ >+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { >+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n", >+ strerror(errno)); >+ return (dt_set_errno(dtp, errno)); >+ } >+ >+ return (1); >+} >+ >+int >+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, >+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) >+{ >+ >+ uint32_t *text; >+ int i; >+ int srdepth = 0; >+ >+ dt_dprintf("%s: unimplemented\n", __func__); >+ return (DT_PROC_ERR); >+ >+ if ((text = malloc(symp->st_size + 4)) == NULL) { >+ dt_dprintf("mr sparkle: malloc() failed\n"); >+ return (DT_PROC_ERR); >+ } >+ >+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { >+ dt_dprintf("mr sparkle: Pread() failed\n"); >+ free(text); >+ return (DT_PROC_ERR); >+ } >+ >+ /* >+ * Leave a dummy instruction in the last slot to simplify edge >+ * conditions. >+ */ >+ text[symp->st_size / 4] = 0; >+ >+ ftp->ftps_type = DTFTP_RETURN; >+ ftp->ftps_pc = symp->st_value; >+ ftp->ftps_size = symp->st_size; >+ ftp->ftps_noffs = 0; >+ >+ >+ free(text); >+ if (ftp->ftps_noffs > 0) { >+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { >+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n", >+ strerror(errno)); >+ return (dt_set_errno(dtp, errno)); >+ } >+ } >+ >+ >+ return (ftp->ftps_noffs); >+} >+ >+/*ARGSUSED*/ >+int >+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, >+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) >+{ >+ if (off & 0x3) >+ return (DT_PROC_ALIGN); >+ >+ ftp->ftps_type = DTFTP_OFFSETS; >+ ftp->ftps_pc = (uintptr_t)symp->st_value; >+ ftp->ftps_size = (size_t)symp->st_size; >+ ftp->ftps_noffs = 1; >+ ftp->ftps_offs[0] = off; >+ >+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { >+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n", >+ strerror(errno)); >+ return (dt_set_errno(dtp, errno)); >+ } >+ >+ return (1); >+} >+ >+/*ARGSUSED*/ >+int >+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, >+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) >+{ >+ ulong_t i; >+ >+ ftp->ftps_type = DTFTP_OFFSETS; >+ ftp->ftps_pc = (uintptr_t)symp->st_value; >+ ftp->ftps_size = (size_t)symp->st_size; >+ ftp->ftps_noffs = 0; >+ >+ /* >+ * If we're matching against everything, just iterate through each >+ * instruction in the function, otherwise look for matching offset >+ * names by constructing the string and comparing it against the >+ * pattern. >+ */ >+ if (strcmp("*", pattern) == 0) { >+ for (i = 0; i < symp->st_size; i += 4) { >+ ftp->ftps_offs[ftp->ftps_noffs++] = i; >+ } >+ } else { >+ char name[sizeof (i) * 2 + 1]; >+ >+ for (i = 0; i < symp->st_size; i += 4) { >+ (void) sprintf(name, "%lx", i); >+ if (gmatch(name, pattern)) >+ ftp->ftps_offs[ftp->ftps_noffs++] = i; >+ } >+ } >+ >+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { >+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n", >+ strerror(errno)); >+ return (dt_set_errno(dtp, errno)); >+ } >+ >+ return (ftp->ftps_noffs); >+} >diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c >index 82ec5fa..c6f47af 100644 >--- a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c >+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c >@@ -169,12 +169,12 @@ write_objects(iidesc_t *idp, ctf_buf_t *b) > { > ushort_t id = (idp ? idp->ii_dtype->t_id : 0); > >- ctf_buf_write(b, &id, sizeof (id)); >- > if (target_requires_swap) { > SWAP_16(id); > } > >+ ctf_buf_write(b, &id, sizeof (id)); >+ > debug(3, "Wrote object %s (%d)\n", (idp ? idp->ii_name : "(null)"), id); > } > >diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile >index 53d402a..ff34d68 100644 >--- a/cddl/lib/Makefile >+++ b/cddl/lib/Makefile >@@ -22,7 +22,8 @@ _libzpool= libzpool > .endif > > .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \ >- ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" >+ ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" || \ >+ ${MACHINE_CPUARCH} == "arm" > _drti= drti > _libdtrace= libdtrace > .endif >diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile >index 46f7046..f9b0214 100644 >--- a/cddl/lib/libdtrace/Makefile >+++ b/cddl/lib/libdtrace/Makefile >@@ -79,6 +79,10 @@ CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc > CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips > .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips > .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/mips >+.elif ${MACHINE_CPUARCH} == "arm" >+CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/arm >+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/arm >+.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/arm > .elif ${MACHINE_CPUARCH} == "powerpc" > CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc > .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/powerpc >diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile >index fb2c437..ad8a998 100644 >--- a/cddl/usr.sbin/Makefile >+++ b/cddl/usr.sbin/Makefile >@@ -21,6 +21,12 @@ _dtruss= dtruss > _lockstat= lockstat > .endif > >+.if ${MACHINE_CPUARCH} == "arm" >+_dtrace= dtrace >+_lockstat= lockstat >+_dtruss= dtruss >+.endif >+ > .if ${MACHINE_CPUARCH} == "mips" > _dtrace= dtrace > .endif >diff --git a/lib/Makefile b/lib/Makefile >index bb8a7e1..db0f16d 100644 >--- a/lib/Makefile >+++ b/lib/Makefile >@@ -233,6 +233,12 @@ _libsmb= libsmb > _libsmb= libsmb > .endif > >+.if ${MACHINE_CPUARCH} == "arm" >+_libsmb= libsmb >+_libproc= libproc >+_librtld_db= librtld_db >+.endif >+ > .if ${MK_OPENSSL} != "no" > _libmp= libmp > .endif >diff --git a/lib/libproc/proc_bkpt.c b/lib/libproc/proc_bkpt.c >index 2c2761a..02a7ed6 100644 >--- a/lib/libproc/proc_bkpt.c >+++ b/lib/libproc/proc_bkpt.c >@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$"); > #elif defined(__powerpc__) > #define BREAKPOINT_INSTR 0x7fe00008 /* trap */ > #define BREAKPOINT_INSTR_SZ 4 >+#elif defined(__arm__) >+#define BREAKPOINT_INSTR 0xe7ffffff /* bkpt */ >+#define BREAKPOINT_INSTR_SZ 4 > #else > #error "Add support for your architecture" > #endif >diff --git a/lib/libproc/proc_regs.c b/lib/libproc/proc_regs.c >index 145c8fe..35d8d38 100644 >--- a/lib/libproc/proc_regs.c >+++ b/lib/libproc/proc_regs.c >@@ -56,6 +56,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue) > case REG_PC: > #if defined(__amd64__) > *regvalue = regs.r_rip; >+#elif defined(__arm__) >+ *regvalue = regs.r_pc; > #elif defined(__i386__) > *regvalue = regs.r_eip; > #elif defined(__mips__) >@@ -67,6 +69,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue) > case REG_SP: > #if defined(__amd64__) > *regvalue = regs.r_rsp; >+#elif defined(__arm__) >+ *regvalue = regs.r_sp; > #elif defined(__i386__) > *regvalue = regs.r_esp; > #elif defined(__mips__) >@@ -99,6 +103,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue) > case REG_PC: > #if defined(__amd64__) > regs.r_rip = regvalue; >+#elif defined(__arm__) >+ regs.r_pc = regvalue; > #elif defined(__i386__) > regs.r_eip = regvalue; > #elif defined(__mips__) >@@ -110,6 +116,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue) > case REG_SP: > #if defined(__amd64__) > regs.r_rsp = regvalue; >+#elif defined(__arm__) >+ regs.r_sp = regvalue; > #elif defined(__i386__) > regs.r_esp = regvalue; > #elif defined(__mips__) >diff --git a/sys/arm/arm/exception.S b/sys/arm/arm/exception.S >index 55a4f64..80b1734 100644 >--- a/sys/arm/arm/exception.S >+++ b/sys/arm/arm/exception.S >@@ -47,12 +47,26 @@ > */ > > #include "assym.s" >- >+#include "opt_kdtrace.h" > #include <machine/asm.h> > #include <machine/armreg.h> > #include <machine/asmacros.h> > __FBSDID("$FreeBSD$"); > >+#ifdef KDTRACE_HOOKS >+ .bss >+ .align 4 >+ .global _C_LABEL(dtrace_invop_jump_addr) >+_C_LABEL(dtrace_invop_jump_addr): >+ .word 0 >+ .word 0 >+ >+ .global _C_LABEL(dtrace_invop_calltrap_addr) >+_C_LABEL(dtrace_invop_calltrap_addr): >+ .word 0 >+ .word 0 >+#endif >+ > .text > .align 0 > >@@ -239,7 +253,20 @@ END(undefined_entry) > > ENTRY_NP(undefinedinstruction_bounce) > PUSHFRAMEINSVC >+#ifdef notyet >+ adr r1, dtrace_invop_jump_addr >+ ldr r0, r1 >+ cmp r0, #0 >+ beq normal >+ >+ mrs r2, spsr_all >+ tst r2, #PSR_MODE >+ bne normal > >+ bl r0 >+ >+normal: >+#endif > mov r0, sp > adr lr, exception_exit > b _C_LABEL(undefinedinstruction) >diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c >index 219d49c..1febfcf 100644 >--- a/sys/arm/arm/identcpu.c >+++ b/sys/arm/arm/identcpu.c >@@ -461,7 +461,7 @@ identify_arm_cpu(void) > u_int8_t type, linesize; > int i; > >- cpuid = cpu_id(); >+ cpuid = cpu_ident(); > > if (cpuid == 0) { > printf("Processor failed probe - no CPU ID\n"); >diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c >index c935a82..d9656db 100644 >--- a/sys/arm/arm/machdep.c >+++ b/sys/arm/arm/machdep.c >@@ -835,8 +835,8 @@ fake_preload_metadata(struct arm_boot_params *abp __unused) > strcpy((char*)&fake_preload[i++], "kernel"); > i += 1; > fake_preload[i++] = MODINFO_TYPE; >- fake_preload[i++] = strlen("elf kernel") + 1; >- strcpy((char*)&fake_preload[i++], "elf kernel"); >+ fake_preload[i++] = strlen("/boot/kernel/kernel") + 1; >+ strcpy((char*)&fake_preload[i++], "/boot/kernel/kernel"); > i += 2; > fake_preload[i++] = MODINFO_ADDR; > fake_preload[i++] = sizeof(vm_offset_t); >diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c >index 5021eec..d34846c 100644 >--- a/sys/arm/arm/trap.c >+++ b/sys/arm/arm/trap.c >@@ -80,6 +80,7 @@ > > > #include "opt_ktrace.h" >+#include "opt_kdtrace.h" > > #include <sys/cdefs.h> > __FBSDID("$FreeBSD$"); >@@ -122,6 +123,31 @@ __FBSDID("$FreeBSD$"); > #include <sys/kdb.h> > #endif > >+#ifdef KDTRACE_HOOKS >+#include <sys/dtrace_bsd.h> >+ >+/* >+ * This is a hook which is initialised by the dtrace module >+ * to handle traps which might occur during DTrace probe >+ * execution. >+ */ >+dtrace_trap_func_t dtrace_trap_func; >+ >+dtrace_doubletrap_func_t dtrace_doubletrap_func; >+ >+/* >+ * This is a hook which is initialised by the systrace module >+ * when it is loaded. This keeps the DTrace syscall provider >+ * implementation opaque. >+ */ >+systrace_probe_func_t systrace_probe_func; >+ >+/* >+ * These hooks are necessary for the pid and usdt providers. >+ */ >+dtrace_pid_probe_ptr_t dtrace_pid_probe_ptr; >+dtrace_return_probe_ptr_t dtrace_return_probe_ptr; >+#endif > > void swi_handler(struct trapframe *); > void undefinedinstruction(struct trapframe *); >@@ -452,6 +478,7 @@ data_abort_handler(struct trapframe *tf) > printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, > error); > dab_fatal(tf, fsr, far, td, &ksig); >+ return; > } > > >@@ -492,6 +519,14 @@ dab_fatal(struct trapframe *tf, u_int fsr, u_int far, struct thread *td, > { > const char *mode; > >+#ifdef KDTRACE_HOOKS >+ if (!TRAP_USERMODE(tf)) >+ { >+ if (dtrace_trap_func != NULL && (*dtrace_trap_func)(tf, far & FAULT_TYPE_MASK)) >+ return (0); >+ } >+#endif >+ > mode = TRAP_USERMODE(tf) ? "user" : "kernel"; > > disable_interrupts(I32_bit|F32_bit); >diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE >index 272d3e8..16c9a46 100644 >--- a/sys/arm/conf/BEAGLEBONE >+++ b/sys/arm/conf/BEAGLEBONE >@@ -59,8 +59,8 @@ options KDB > options DDB #Enable the kernel debugger > options INVARIANTS #Enable calls of extra sanity checking > options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS >-options WITNESS #Enable checks to detect deadlocks and cycles >-options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed >+#options WITNESS #Enable checks to detect deadlocks and cycles >+#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed > #options DIAGNOSTIC > > # NFS support >@@ -69,12 +69,12 @@ options NFSCL > options NFSLOCKD > > # Uncomment this for NFS root >-#options NFS_ROOT #NFS usable as /, requires NFSCL >-#options BOOTP_NFSROOT >-#options BOOTP_COMPAT >-#options BOOTP >-#options BOOTP_NFSV3 >-#options BOOTP_WIRED_TO=cpsw0 >+options NFS_ROOT #NFS usable as /, requires NFSCL >+options BOOTP_NFSROOT >+options BOOTP_COMPAT >+options BOOTP >+options BOOTP_NFSV3 >+options BOOTP_WIRED_TO=cpsw0 > > > # MMC/SD/SDIO card slot support >@@ -83,7 +83,8 @@ device mmcsd # mmc/sd flash cards > device sdhci # mmc/sd host controller > > # Boot device is 2nd slice on MMC/SD card >-options ROOTDEVNAME=\"ufs:mmcsd0s2\" >+#options ROOTDEVNAME=\"ufs:mmcsd0s2\" >+options ROOTDEVNAME=\"nfs:192.168.0.123:/bbb\" > > # Console and misc > device uart >@@ -131,4 +132,10 @@ device usfs > # Flattened Device Tree > options FDT > options FDT_DTB_STATIC >-makeoptions FDT_DTS_FILE=beaglebone.dts >+makeoptions FDT_DTS_FILE=beaglebone-black.dts >+ >+#dtrace support >+options KDTRACE_HOOKS # Kernel DTrace hooks >+options DDB_CTF # all architectures - kernel ELF linker loads CTF data >+makeoptions WITH_CTF=1 >+makeoptions MODULES_OVERRIDE="opensolaris dtrace cyclic dtrace/dtnfsclient dtrace/dtnfscl dtrace/lockstat dtrace/profile dtrace/fbt" >diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h >index d3e9ebe..4c96373 100644 >--- a/sys/arm/include/cpufunc.h >+++ b/sys/arm/include/cpufunc.h >@@ -167,7 +167,7 @@ struct cpu_functions { > extern struct cpu_functions cpufuncs; > extern u_int cputype; > >-#define cpu_id() cpufuncs.cf_id() >+#define cpu_ident() cpufuncs.cf_id() > #define cpu_cpwait() cpufuncs.cf_cpwait() > > #define cpu_control(c, e) cpufuncs.cf_control(c, e) >diff --git a/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c >new file mode 100644 >index 0000000..18e3837 >--- /dev/null >+++ b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.c >@@ -0,0 +1,30 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License (the "License"). >+ * You may not use this file except in compliance with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ */ >+ >+/* >+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+ >+/* >+ * XXX: Placeholder for ARM fasttrap code >+ */ >diff --git a/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h >new file mode 100644 >index 0000000..10361cbe >--- /dev/null >+++ b/sys/cddl/contrib/opensolaris/uts/arm/sys/fasttrap_isa.h >@@ -0,0 +1,94 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ */ >+/* >+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+#ifndef _FASTTRAP_ISA_H >+#define _FASTTRAP_ISA_H >+ >+#pragma ident "%Z%%M% %I% %E% SMI" >+ >+#include <sys/types.h> >+ >+#ifdef __cplusplus >+extern "C" { >+#endif >+ >+/* >+ * This is our reserved trap instruction: ta 0x38 >+ */ >+#define FASTTRAP_INSTR 0x91d02038 >+ >+#define FASTTRAP_SUNWDTRACE_SIZE 128 >+ >+typedef uint32_t fasttrap_instr_t; >+ >+typedef struct fasttrap_machtp { >+ fasttrap_instr_t ftmt_instr; /* original instruction */ >+ uintptr_t ftmt_dest; /* destination of DCTI */ >+ uint8_t ftmt_type; /* emulation type */ >+ uint8_t ftmt_flags; /* emulation flags */ >+ uint8_t ftmt_cc; /* which cc to look at */ >+ uint8_t ftmt_code; /* branch condition */ >+} fasttrap_machtp_t; >+ >+#define ftt_instr ftt_mtp.ftmt_instr >+#define ftt_dest ftt_mtp.ftmt_dest >+#define ftt_type ftt_mtp.ftmt_type >+#define ftt_flags ftt_mtp.ftmt_flags >+#define ftt_cc ftt_mtp.ftmt_cc >+#define ftt_code ftt_mtp.ftmt_code >+ >+#define FASTTRAP_T_COMMON 0x00 /* common case -- no emulation */ >+#define FASTTRAP_T_CCR 0x01 /* integer condition code branch */ >+#define FASTTRAP_T_FCC 0x02 /* floating-point branch */ >+#define FASTTRAP_T_REG 0x03 /* register predicated branch */ >+#define FASTTRAP_T_ALWAYS 0x04 /* branch always */ >+#define FASTTRAP_T_CALL 0x05 /* call instruction */ >+#define FASTTRAP_T_JMPL 0x06 /* jmpl instruction */ >+#define FASTTRAP_T_RDPC 0x07 /* rdpc instruction */ >+#define FASTTRAP_T_RETURN 0x08 /* return instruction */ >+ >+/* >+ * For performance rather than correctness. >+ */ >+#define FASTTRAP_T_SAVE 0x10 /* save instruction (func entry only) */ >+#define FASTTRAP_T_RESTORE 0x11 /* restore instruction */ >+#define FASTTRAP_T_OR 0x12 /* mov instruction */ >+#define FASTTRAP_T_SETHI 0x13 /* sethi instruction (includes nop) */ >+ >+#define FASTTRAP_F_ANNUL 0x01 /* branch is annulled */ >+#define FASTTRAP_F_RETMAYBE 0x02 /* not definitely a return site */ >+ >+#define FASTTRAP_AFRAMES 3 >+#define FASTTRAP_RETURN_AFRAMES 4 >+#define FASTTRAP_ENTRY_AFRAMES 3 >+#define FASTTRAP_OFFSET_AFRAMES 3 >+ >+ >+#ifdef __cplusplus >+} >+#endif >+ >+#endif /* _FASTTRAP_ISA_H */ >diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c >index f35cf73..9e4b23d 100644 >--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c >+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c >@@ -10933,7 +10933,7 @@ err: > #else > int i; > >-#if defined(__amd64__) || defined(__mips__) || defined(__powerpc__) >+#if defined(__amd64__) || defined(__mips__) || defined(__powerpc__) || defined(__arm__) > /* > * FreeBSD isn't good at limiting the amount of memory we > * ask to malloc, so let's place a limit here before trying >diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h >index 295457c..671faa9 100644 >--- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h >+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h >@@ -2390,6 +2390,13 @@ extern void dtrace_helpers_destroy(proc_t *); > #define DTRACE_INVOP_MFLR_R0 5 > #define DTRACE_INVOP_NOP 6 > >+#elif defined(__arm__) >+ >+#define DTRACE_INVOP_PUSHM 1 >+#define DTRACE_INVOP_POPM 2 >+#define DTRACE_INVOP_B 3 >+ >+ > #endif > > #ifdef __cplusplus >diff --git a/sys/cddl/dev/dtrace/arm/dtrace_asm.S b/sys/cddl/dev/dtrace/arm/dtrace_asm.S >new file mode 100644 >index 0000000..7898bc4 >--- /dev/null >+++ b/sys/cddl/dev/dtrace/arm/dtrace_asm.S >@@ -0,0 +1,185 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ * >+ * $FreeBSD$ >+ */ >+/* >+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+#define _ASM >+#define _LOCORE >+#define LOCORE >+ >+#include <sys/cpuvar_defs.h> >+#include <sys/dtrace.h> >+ >+#include <machine/asm.h> >+ >+#include "assym.s" >+ >+/* >+void dtrace_membar_producer(void) >+*/ >+ENTRY(dtrace_membar_producer) >+ RET >+ >+/* >+void dtrace_membar_consumer(void) >+*/ >+ENTRY(dtrace_membar_consumer) >+ RET >+ >+/* >+dtrace_icookie_t dtrace_interrupt_disable(void) >+*/ >+ENTRY(dtrace_interrupt_disable) >+ mrs r0, cpsr >+ mov r1, r0 >+ orr r1, r1, #(I32_bit|F32_bit) >+ msr cpsr_c, r1 >+ RET >+/* >+void dtrace_interrupt_enable(dtrace_icookie_t cookie) >+*/ >+ENTRY(dtrace_interrupt_enable) >+ and r0, r0, #(I32_bit|F32_bit) >+ mrs r1, cpsr >+ bic r1, r1, #(I32_bit|F32_bit) >+ orr r1, r1, r0 >+ msr cpsr_c, r1 >+ RET >+ >+/* >+uint8_t >+dtrace_fuword8_nocheck(void *addr) >+*/ >+ENTRY(dtrace_fuword8_nocheck) >+ ldrb r3, [r0] >+ mov r0, r3 >+ RET >+ >+/* >+uint16_t >+dtrace_fuword16_nocheck(void *addr) >+*/ >+ENTRY(dtrace_fuword16_nocheck) >+ ldrh r3, [r0] >+ mov r0, r3 >+ RET >+ >+/* >+uint32_t >+dtrace_fuword32_nocheck(void *addr) >+*/ >+ENTRY(dtrace_fuword32_nocheck) >+ ldr r3, [r0] >+ mov r0, r3 >+ RET >+ >+/* >+uint64_t >+dtrace_fuword64_nocheck(void *addr) >+*/ >+ENTRY(dtrace_fuword64_nocheck) >+ ldm r0, {r2, r3} >+ >+ mov r0, r2 >+ mov r1, r3 >+#if defined(__BIG_ENDIAN__) >+/* big endian */ >+ mov r0, r3 >+ mov r1, r2 >+#else >+/* little endian */ >+ mov r0, r2 >+ mov r1, r3 >+ >+#endif >+ RET >+ >+/* >+void >+dtrace_copy(uintptr_t uaddr, uintptr_t kaddr, size_t size) >+*/ >+ENTRY(dtrace_copy) >+ stmfd sp!, {r4-r5} /* stack is 8 byte aligned */ >+ teq r2, #0x00000000 >+ mov r5, #0x00000000 >+ beq 2f >+ >+1: ldrb r4, [r0], #0x0001 >+ add r5, r5, #0x00000001 >+ strb r4, [r1], #0x0001 >+ teqne r5, r2 >+ bne 1b >+ >+2: ldmfd sp!, {r4-r5} /* stack is 8 byte aligned */ >+ RET >+ >+ >+/* >+void >+dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size, >+ volatile uint16_t *flags) >+XXX: Check for flags? >+*/ >+ENTRY(dtrace_copystr) >+ stmfd sp!, {r4-r5} /* stack is 8 byte aligned */ >+ teq r2, #0x00000000 >+ mov r5, #0x00000000 >+ beq 2f >+ >+1: ldrb r4, [r0], #0x0001 >+ add r5, r5, #0x00000001 >+ teq r4, #0x00000000 >+ strb r4, [r1], #0x0001 >+ teqne r5, r2 >+ bne 1b >+ >+2: ldmfd sp!, {r4-r5} /* stack is 8 byte aligned */ >+ RET >+ >+#if 0 >+/* >+void >+vpanic(const char *format, va_list alist) >+*/ >+ENTRY(vpanic) /* Initial stack layout: */ >+vpanic_common: >+ RET >+#endif >+/* >+void >+dtrace_vpanic(const char *format, va_list alist) >+*/ >+ENTRY(dtrace_vpanic) /* Initial stack layout: */ >+ b vpanic >+ RET >+ >+/* >+uintptr_t >+dtrace_caller(int aframes) >+*/ >+ENTRY(dtrace_caller) >+ mov r0, #-1 >+ RET >diff --git a/sys/cddl/dev/dtrace/arm/dtrace_isa.c b/sys/cddl/dev/dtrace/arm/dtrace_isa.c >new file mode 100644 >index 0000000..e885a60 >--- /dev/null >+++ b/sys/cddl/dev/dtrace/arm/dtrace_isa.c >@@ -0,0 +1,373 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ * >+ * $FreeBSD$ >+ */ >+/* >+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+#include <sys/cdefs.h> >+ >+#include <sys/param.h> >+#include <sys/systm.h> >+#include <sys/kernel.h> >+#include <sys/stack.h> >+#include <sys/pcpu.h> >+ >+#include <machine/frame.h> >+#include <machine/md_var.h> >+#include <machine/reg.h> >+ >+#include <vm/vm.h> >+#include <vm/vm_param.h> >+#include <vm/pmap.h> >+ >+#include <machine/atomic.h> >+#include <machine/db_machdep.h> >+#include <machine/md_var.h> >+#include <machine/vmparam.h> >+#include <machine/stack.h> >+#include <ddb/db_sym.h> >+#include <ddb/ddb.h> >+#include <sys/kdb.h> >+ >+#include "regset.h" >+ >+/* >+ * Wee need some reasonable default to prevent backtrace code >+ * from wandering too far >+ */ >+#define MAX_FUNCTION_SIZE 0x10000 >+#define MAX_PROLOGUE_SIZE 0x100 >+ >+ >+uint8_t dtrace_fuword8_nocheck(void *); >+uint16_t dtrace_fuword16_nocheck(void *); >+uint32_t dtrace_fuword32_nocheck(void *); >+uint64_t dtrace_fuword64_nocheck(void *); >+ >+void >+dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, >+ uint32_t *intrpc) >+{ >+ u_int32_t *frame, *lastframe; >+ int scp_offset; >+ int depth = 0; >+ pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; >+ >+ if (intrpc != 0) >+ pcstack[depth++] = (pc_t) intrpc; >+ >+ aframes++; >+ >+ frame = (u_int32_t *)__builtin_frame_address(0);; >+ lastframe = NULL; >+ scp_offset = -(get_pc_str_offset() >> 2); >+ >+ while ((frame != NULL) && (depth < pcstack_limit)) { >+ db_addr_t scp; >+#if 0 >+ u_int32_t savecode; >+ int r; >+ u_int32_t *rp; >+#endif >+ >+ /* >+ * In theory, the SCP isn't guaranteed to be in the function >+ * that generated the stack frame. We hope for the best. >+ */ >+ scp = frame[FR_SCP]; >+ printf("--> %08x\n", (uint32_t)scp); >+ >+ if (aframes > 0) { >+ aframes--; >+ if ((aframes == 0) && (caller != 0)) { >+ pcstack[depth++] = caller; >+ } >+ } >+ else { >+ printf("++ --> %08x\n", (uint32_t)scp); >+ pcstack[depth++] = scp; >+ } >+ >+#if 0 >+ savecode = ((u_int32_t *)scp)[scp_offset]; >+ if ((savecode & 0x0e100000) == 0x08000000) { >+ /* Looks like an STM */ >+ rp = frame - 4; >+ for (r = 10; r >= 0; r--) { >+ if (savecode & (1 << r)) { >+ /* register r == *rp-- */ >+ } >+ } >+ } >+#endif >+ >+ /* >+ * Switch to next frame up >+ */ >+ if (frame[FR_RFP] == 0) >+ break; /* Top of stack */ >+ >+ lastframe = frame; >+ frame = (u_int32_t *)(frame[FR_RFP]); >+ >+ if (INKERNEL((int)frame)) { >+ /* staying in kernel */ >+ if (frame <= lastframe) { >+ /* bad frame pointer */ >+ break; >+ } >+ } >+ else >+ break; >+ } >+ >+ for (; depth < pcstack_limit; depth++) { >+ pcstack[depth] = 0; >+ } >+} >+ >+void >+dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) >+{ >+ printf("IMPLEMENT ME: %s\n", __func__); >+} >+ >+int >+dtrace_getustackdepth(void) >+{ >+ printf("IMPLEMENT ME: %s\n", __func__); >+ return (0); >+} >+ >+void >+dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) >+{ >+ printf("IMPLEMENT ME: %s\n", __func__); >+} >+ >+/*ARGSUSED*/ >+uint64_t >+dtrace_getarg(int arg, int aframes) >+{ >+ struct arm_frame *fp = (struct arm_frame *)dtrace_getfp(); >+ >+ return (0); >+} >+ >+int >+dtrace_getstackdepth(int aframes) >+{ >+ u_int32_t *frame, *lastframe; >+ int scp_offset; >+ int depth = 1; >+ >+ frame = (u_int32_t *)__builtin_frame_address(0);; >+ lastframe = NULL; >+ scp_offset = -(get_pc_str_offset() >> 2); >+ >+ while (frame != NULL) { >+ db_addr_t scp; >+#if 0 >+ u_int32_t savecode; >+ int r; >+ u_int32_t *rp; >+#endif >+ >+ /* >+ * In theory, the SCP isn't guaranteed to be in the function >+ * that generated the stack frame. We hope for the best. >+ */ >+ scp = frame[FR_SCP]; >+ >+ depth++; >+ >+ /* >+ * Switch to next frame up >+ */ >+ if (frame[FR_RFP] == 0) >+ break; /* Top of stack */ >+ >+ lastframe = frame; >+ frame = (u_int32_t *)(frame[FR_RFP]); >+ >+ if (INKERNEL((int)frame)) { >+ /* staying in kernel */ >+ if (frame <= lastframe) { >+ /* bad frame pointer */ >+ break; >+ } >+ } >+ else >+ break; >+ } >+ >+ if (depth < aframes) >+ return 0; >+ else >+ return depth - aframes; >+ >+} >+ >+ulong_t >+dtrace_getreg(struct trapframe *rp, uint_t reg) >+{ >+ printf("IMPLEMENT ME: %s\n", __func__); >+ >+ return (0); >+} >+ >+static int >+dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) >+{ >+ >+ if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { >+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); >+ cpu_core[curcpu].cpuc_dtrace_illval = uaddr; >+ return (0); >+ } >+ >+ return (1); >+} >+ >+void >+dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, >+ volatile uint16_t *flags) >+{ >+ if (dtrace_copycheck(uaddr, kaddr, size)) >+ dtrace_copy(uaddr, kaddr, size); >+} >+ >+void >+dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, >+ volatile uint16_t *flags) >+{ >+ if (dtrace_copycheck(uaddr, kaddr, size)) >+ dtrace_copy(kaddr, uaddr, size); >+} >+ >+void >+dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, >+ volatile uint16_t *flags) >+{ >+ if (dtrace_copycheck(uaddr, kaddr, size)) >+ dtrace_copystr(uaddr, kaddr, size, flags); >+} >+ >+void >+dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, >+ volatile uint16_t *flags) >+{ >+ if (dtrace_copycheck(uaddr, kaddr, size)) >+ dtrace_copystr(kaddr, uaddr, size, flags); >+} >+ >+uint8_t >+dtrace_fuword8(void *uaddr) >+{ >+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { >+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); >+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; >+ return (0); >+ } >+ return (dtrace_fuword8_nocheck(uaddr)); >+} >+ >+uint16_t >+dtrace_fuword16(void *uaddr) >+{ >+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { >+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); >+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; >+ return (0); >+ } >+ return (dtrace_fuword16_nocheck(uaddr)); >+} >+ >+uint32_t >+dtrace_fuword32(void *uaddr) >+{ >+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { >+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); >+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; >+ return (0); >+ } >+ return (dtrace_fuword32_nocheck(uaddr)); >+} >+ >+uint64_t >+dtrace_fuword64(void *uaddr) >+{ >+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { >+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); >+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; >+ return (0); >+ } >+ return (dtrace_fuword64_nocheck(uaddr)); >+} >+ >+#ifndef I32_bit >+#define I32_bit (1 << 7) /* IRQ disable */ >+#endif >+#ifndef F32_bit >+#define F32_bit (1 << 6) /* FIQ disable */ >+#endif >+ >+#define __with_interrupts_disabled(expr) \ >+ do { \ >+ u_int cpsr_save, tmp; \ >+ \ >+ __asm __volatile( \ >+ "mrs %0, cpsr;" \ >+ "orr %1, %0, %2;" \ >+ "msr cpsr_all, %1;" \ >+ : "=r" (cpsr_save), "=r" (tmp) \ >+ : "I" (I32_bit | F32_bit) \ >+ : "cc" ); \ >+ (expr); \ >+ __asm __volatile( \ >+ "msr cpsr_all, %0" \ >+ : /* no output */ \ >+ : "r" (cpsr_save) \ >+ : "cc" ); \ >+ } while(0) >+ >+uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) >+{ >+ uint32_t ret; >+ __with_interrupts_disabled( >+ { >+ ret = *target; >+ if (*target == cmp) { >+ *target = new; >+ } >+ }); >+ >+ return ret; >+} >+ >+void * dtrace_casptr(volatile void *target, volatile void *cmp, volatile void *new) >+{ >+ return (void*)dtrace_cas32((uint32_t*)target, (uint32_t)cmp, (uint32_t)new); >+} >+ >diff --git a/sys/cddl/dev/dtrace/arm/dtrace_subr.c b/sys/cddl/dev/dtrace/arm/dtrace_subr.c >new file mode 100644 >index 0000000..c24dd9b >--- /dev/null >+++ b/sys/cddl/dev/dtrace/arm/dtrace_subr.c >@@ -0,0 +1,264 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ * >+ * $FreeBSD$ >+ * >+ */ >+/* >+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+#include <sys/cdefs.h> >+__FBSDID("$FreeBSD$"); >+ >+#include <sys/param.h> >+#include <sys/systm.h> >+#include <sys/types.h> >+#include <sys/kernel.h> >+#include <sys/malloc.h> >+#include <sys/kmem.h> >+#include <sys/smp.h> >+#include <sys/dtrace_impl.h> >+#include <sys/dtrace_bsd.h> >+#include <machine/armreg.h> >+#include <machine/clock.h> >+#include <machine/frame.h> >+#include <machine/trap.h> >+#include <vm/pmap.h> >+ >+#define DELAYBRANCH(x) ((int)(x) < 0) >+ >+extern uintptr_t dtrace_in_probe_addr; >+extern int dtrace_in_probe; >+extern dtrace_id_t dtrace_probeid_error; >+extern int (*dtrace_invop_jump_addr)(struct trapframe *); >+ >+int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t); >+void dtrace_invop_init(void); >+void dtrace_invop_uninit(void); >+ >+typedef struct dtrace_invop_hdlr { >+ int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); >+ struct dtrace_invop_hdlr *dtih_next; >+} dtrace_invop_hdlr_t; >+ >+dtrace_invop_hdlr_t *dtrace_invop_hdlr; >+ >+int >+dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) >+{ >+ dtrace_invop_hdlr_t *hdlr; >+ int rval; >+ >+ for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) >+ if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) >+ return (rval); >+ >+ return (0); >+} >+ >+ >+void >+dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) >+{ >+ dtrace_invop_hdlr_t *hdlr; >+ >+ hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); >+ hdlr->dtih_func = func; >+ hdlr->dtih_next = dtrace_invop_hdlr; >+ dtrace_invop_hdlr = hdlr; >+} >+ >+void >+dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) >+{ >+ dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL; >+ >+ for (;;) { >+ if (hdlr == NULL) >+ panic("attempt to remove non-existent invop handler"); >+ >+ if (hdlr->dtih_func == func) >+ break; >+ >+ prev = hdlr; >+ hdlr = hdlr->dtih_next; >+ } >+ >+ if (prev == NULL) { >+ ASSERT(dtrace_invop_hdlr == hdlr); >+ dtrace_invop_hdlr = hdlr->dtih_next; >+ } else { >+ ASSERT(dtrace_invop_hdlr != hdlr); >+ prev->dtih_next = hdlr->dtih_next; >+ } >+ >+ kmem_free(hdlr, 0); >+} >+ >+ >+/*ARGSUSED*/ >+void >+dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) >+{ >+ printf("IMPLEMENT ME: dtrace_toxic_ranges\n"); >+} >+ >+void >+dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) >+{ >+ cpuset_t cpus; >+ >+ if (cpu == DTRACE_CPUALL) >+ cpus = all_cpus; >+ else >+ CPU_SETOF(cpu, &cpus); >+ >+ smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func, >+ smp_no_rendevous_barrier, arg); >+} >+ >+static void >+dtrace_sync_func(void) >+{ >+} >+ >+void >+dtrace_sync(void) >+{ >+ dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); >+} >+ >+/* >+ * DTrace needs a high resolution time function which can >+ * be called from a probe context and guaranteed not to have >+ * instrumented with probes itself. >+ * >+ * Returns nanoseconds since boot. >+ */ >+uint64_t >+dtrace_gethrtime() >+{ >+ struct timespec curtime; >+ >+ nanouptime(&curtime); >+ >+ return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); >+ >+} >+ >+uint64_t >+dtrace_gethrestime(void) >+{ >+ struct timespec curtime; >+ >+ getnanotime(&curtime); >+ >+ return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); >+} >+ >+/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ >+int >+dtrace_trap(struct trapframe *frame, u_int type) >+{ >+ /* >+ * A trap can occur while DTrace executes a probe. Before >+ * executing the probe, DTrace blocks re-scheduling and sets >+ * a flag in it's per-cpu flags to indicate that it doesn't >+ * want to fault. On returning from the probe, the no-fault >+ * flag is cleared and finally re-scheduling is enabled. >+ * >+ * Check if DTrace has enabled 'no-fault' mode: >+ * >+ */ >+ if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { >+ /* >+ * There are only a couple of trap types that are expected. >+ * All the rest will be handled in the usual way. >+ */ >+ switch (type) { >+ /* Page fault. */ >+ case FAULT_WRTBUF_0: >+ case FAULT_WRTBUF_1: >+ case FAULT_ALIGN_0: >+ case FAULT_ALIGN_1: >+ /* Flag a bad address. */ >+ cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; >+ cpu_core[curcpu].cpuc_dtrace_illval = 0; >+ >+ /* >+ * Offset the instruction pointer to the instruction >+ * following the one causing the fault. >+ */ >+ frame->tf_pc += sizeof(int); >+ return (1); >+ default: >+ /* Handle all other traps in the usual way. */ >+ break; >+ } >+ } >+ >+ /* Handle the trap in the usual way. */ >+ return (0); >+} >+ >+void >+dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, >+ int fault, int fltoffs, uintptr_t illval) >+{ >+ >+ dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, >+ (uintptr_t)epid, >+ (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); >+} >+ >+static int >+dtrace_invop_start(struct trapframe *frame) >+{ >+ printf("IMPLEMENT ME: %s\n", __func__); >+ switch (dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc)) { >+ case DTRACE_INVOP_PUSHM: >+ // TODO: >+ break; >+ case DTRACE_INVOP_POPM: >+ // TODO: >+ break; >+ case DTRACE_INVOP_B: >+ // TODO >+ break; >+ default: >+ return (-1); >+ break; >+ } >+ >+ return (0); >+} >+ >+void dtrace_invop_init(void) >+{ >+ dtrace_invop_jump_addr = dtrace_invop_start; >+} >+ >+void dtrace_invop_uninit(void) >+{ >+ dtrace_invop_jump_addr = 0; >+} >diff --git a/sys/cddl/dev/dtrace/arm/regset.h b/sys/cddl/dev/dtrace/arm/regset.h >new file mode 100644 >index 0000000..1ff6463 >--- /dev/null >+++ b/sys/cddl/dev/dtrace/arm/regset.h >@@ -0,0 +1,56 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License, Version 1.0 only >+ * (the "License"). You may not use this file except in compliance >+ * with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ * >+ * $FreeBSD$ >+ */ >+/* >+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ >+ >+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ >+/* All Rights Reserved */ >+ >+#ifndef _REGSET_H >+#define _REGSET_H >+ >+/* >+ * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" >+ */ >+ >+#ifdef __cplusplus >+extern "C" { >+#endif >+ >+#define REG_PC R14 >+#define REG_FP R13 >+#define REG_SP R12 >+#define REG_PS R0 >+#define REG_R0 R0 >+#define REG_R1 R1 >+ >+#ifdef __cplusplus >+} >+#endif >+ >+#endif /* _REGSET_H */ >diff --git a/sys/cddl/dev/fbt/fbt_arm.c b/sys/cddl/dev/fbt/fbt_arm.c >new file mode 100644 >index 0000000..2daefa8 >--- /dev/null >+++ b/sys/cddl/dev/fbt/fbt_arm.c >@@ -0,0 +1,1303 @@ >+/* >+ * CDDL HEADER START >+ * >+ * The contents of this file are subject to the terms of the >+ * Common Development and Distribution License (the "License"). >+ * You may not use this file except in compliance with the License. >+ * >+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE >+ * or http://www.opensolaris.org/os/licensing. >+ * See the License for the specific language governing permissions >+ * and limitations under the License. >+ * >+ * When distributing Covered Code, include this CDDL HEADER in each >+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. >+ * If applicable, add the following below this CDDL HEADER, with the >+ * fields enclosed by brackets "[]" replaced with your own identifying >+ * information: Portions Copyright [yyyy] [name of copyright owner] >+ * >+ * CDDL HEADER END >+ * >+ * Portions Copyright 2006-2008 John Birrell jb@freebsd.org >+ * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org >+ * Portions Copyright 2013 Howard Su howardsu@freebsd.org >+ * >+ * $FreeBSD$ >+ * >+ */ >+ >+/* >+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. >+ * Use is subject to license terms. >+ */ >+ >+#include <sys/cdefs.h> >+#include <sys/param.h> >+#include <sys/systm.h> >+#include <sys/conf.h> >+#include <sys/cpuvar.h> >+#include <sys/fcntl.h> >+#include <sys/filio.h> >+#include <sys/kdb.h> >+#include <sys/kernel.h> >+#include <sys/kmem.h> >+#include <sys/kthread.h> >+#include <sys/limits.h> >+#include <sys/linker.h> >+#include <sys/lock.h> >+#include <sys/malloc.h> >+#include <sys/module.h> >+#include <sys/mutex.h> >+#include <sys/pcpu.h> >+#include <sys/poll.h> >+#include <sys/proc.h> >+#include <sys/selinfo.h> >+#include <sys/smp.h> >+#include <sys/syscall.h> >+#include <sys/sysent.h> >+#include <sys/sysproto.h> >+#include <sys/uio.h> >+#include <sys/unistd.h> >+#include <machine/frame.h> >+#include <machine/md_var.h> >+#include <machine/stdarg.h> >+ >+#include <sys/dtrace.h> >+#include <sys/dtrace_bsd.h> >+ >+static MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing"); >+ >+#define FBT_PATCHVAL 0xe06a0cfe // illegal instruction >+ >+#define FBT_PUSHM 0xe92d0000 >+#define FBT_POPM 0xe8bd0000 >+#define FBT_JUMP 0xea000000 >+ >+static d_open_t fbt_open; >+static int fbt_unload(void); >+static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); >+static void fbt_provide_module(void *, modctl_t *); >+static void fbt_destroy(void *, dtrace_id_t, void *); >+static void fbt_enable(void *, dtrace_id_t, void *); >+static void fbt_disable(void *, dtrace_id_t, void *); >+static void fbt_load(void *); >+static void fbt_suspend(void *, dtrace_id_t, void *); >+static void fbt_resume(void *, dtrace_id_t, void *); >+ >+#define FBT_ENTRY "entry" >+#define FBT_RETURN "return" >+#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask) >+#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */ >+ >+static struct cdevsw fbt_cdevsw = { >+ .d_version = D_VERSION, >+ .d_open = fbt_open, >+ .d_name = "fbt", >+}; >+ >+static dtrace_pattr_t fbt_attr = { >+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, >+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, >+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, >+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, >+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, >+}; >+ >+static dtrace_pops_t fbt_pops = { >+ NULL, >+ fbt_provide_module, >+ fbt_enable, >+ fbt_disable, >+ fbt_suspend, >+ fbt_resume, >+ fbt_getargdesc, >+ NULL, >+ NULL, >+ fbt_destroy >+}; >+ >+typedef struct fbt_probe { >+ struct fbt_probe *fbtp_hashnext; >+ uint32_t *fbtp_patchpoint; >+ int8_t fbtp_rval; >+ uint32_t fbtp_patchval; >+ uint32_t fbtp_savedval; >+ uintptr_t fbtp_roffset; >+ dtrace_id_t fbtp_id; >+ const char *fbtp_name; >+ modctl_t *fbtp_ctl; >+ int fbtp_loadcnt; >+ int fbtp_primary; >+ int fbtp_invop_cnt; >+ int fbtp_symindx; >+ struct fbt_probe *fbtp_next; >+} fbt_probe_t; >+ >+static struct cdev *fbt_cdev; >+static dtrace_provider_id_t fbt_id; >+static fbt_probe_t **fbt_probetab; >+static int fbt_probetab_size; >+static int fbt_probetab_mask; >+static int fbt_verbose = 0; >+ >+static int >+fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) >+{ >+ struct trapframe *frame = (struct trapframe *)stack; >+ solaris_cpu_t *cpu = &solaris_cpu[curcpu]; >+ fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; >+ >+ for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { >+ if ((uintptr_t)fbt->fbtp_patchpoint == addr) { >+ fbt->fbtp_invop_cnt++; >+ cpu->cpu_dtrace_caller = addr; >+ >+ dtrace_probe(fbt->fbtp_id, frame->tf_r0, >+ frame->tf_r1, frame->tf_r2, >+ frame->tf_r3, 0); // TODO: Need 5th parameter from stack >+ >+ cpu->cpu_dtrace_caller = 0; >+ >+ return (fbt->fbtp_rval); >+ } >+ } >+ >+ return (0); >+} >+ >+static int >+fbt_provide_module_function(linker_file_t lf, int symindx, >+ linker_symval_t *symval, void *opaque) >+{ >+ char *modname = opaque; >+ const char *name = symval->name; >+ fbt_probe_t *fbt, *retfbt; >+ int popm; >+ u_int32_t *instr, *limit; >+ >+ if (strncmp(name, "dtrace_", 7) == 0 && >+ strncmp(name, "dtrace_safe_", 12) != 0) { >+ /* >+ * Anything beginning with "dtrace_" may be called >+ * from probe context unless it explicitly indicates >+ * that it won't be called from probe context by >+ * using the prefix "dtrace_safe_". >+ */ >+ return (0); >+ } >+ >+ if (name[0] == '_' && name[1] == '_') >+ return (0); >+ >+ instr = (u_int32_t *) symval->value; >+ limit = (u_int32_t *)(symval->value + symval->size); >+ >+ for (; instr < limit; instr++) >+ if ((*instr & 0xffff0000) == FBT_PUSHM && (*instr & 0x4000) != 0) >+ break; >+ >+ if (instr >= limit) >+ return (0); >+ >+ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); >+ fbt->fbtp_name = name; >+ fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, >+ name, FBT_ENTRY, 3, fbt); >+ fbt->fbtp_patchpoint = instr; >+ fbt->fbtp_ctl = lf; >+ fbt->fbtp_loadcnt = lf->loadcnt; >+ fbt->fbtp_savedval = *instr; >+ fbt->fbtp_patchval = FBT_PATCHVAL; >+ fbt->fbtp_rval = DTRACE_INVOP_PUSHM; >+ fbt->fbtp_symindx = symindx; >+ >+ fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; >+ fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; >+ >+ lf->fbt_nentries++; >+ >+ popm = FBT_POPM | ((*instr) & 0x3FFF) | 0x8000; >+ >+ >+ retfbt = NULL; >+again: >+ for(; instr < limit; instr++) >+ { >+ if (*instr == popm) >+ break; >+ else if ((*instr & 0xff000000) == FBT_JUMP) >+ { >+ int offset; >+ u_int32_t *target, *start; >+ offset = (*instr & 0xffffff); >+ offset <<= 8; >+ offset /= 64; >+ target = instr + (2 + offset); >+ start = (u_int32_t *) symval->value; >+ if (target >= limit || target < start) >+ break; >+ instr++; //skip delay slot >+ } >+ } >+ >+ if (instr >= limit) >+ return (0); >+ >+ /* >+ * We have a winner! >+ */ >+ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); >+ fbt->fbtp_name = name; >+ if (retfbt == NULL) { >+ fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, >+ name, FBT_RETURN, 5, fbt); >+ } else { >+ retfbt->fbtp_next = fbt; >+ fbt->fbtp_id = retfbt->fbtp_id; >+ } >+ retfbt = fbt; >+ >+ fbt->fbtp_patchpoint = instr; >+ fbt->fbtp_ctl = lf; >+ fbt->fbtp_loadcnt = lf->loadcnt; >+ fbt->fbtp_symindx = symindx; >+ if ((*instr & 0xff000000) == FBT_JUMP) >+ fbt->fbtp_rval = DTRACE_INVOP_B; >+ else >+ fbt->fbtp_rval = DTRACE_INVOP_POPM; >+ fbt->fbtp_savedval = *instr; >+ fbt->fbtp_patchval = FBT_PATCHVAL; >+ fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; >+ fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; >+ >+ lf->fbt_nentries++; >+ >+ instr++; >+ goto again; >+} >+ >+static void >+fbt_provide_module(void *arg, modctl_t *lf) >+{ >+ char modname[MAXPATHLEN]; >+ int i; >+ size_t len; >+ >+ strlcpy(modname, lf->filename, sizeof(modname)); >+ len = strlen(modname); >+ if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) >+ modname[len - 3] = '\0'; >+ >+ /* >+ * Employees of dtrace and their families are ineligible. Void >+ * where prohibited. >+ */ >+ if (strcmp(modname, "dtrace") == 0) >+ return; >+ >+ /* >+ * The cyclic timer subsystem can be built as a module and DTrace >+ * depends on that, so it is ineligible too. >+ */ >+ if (strcmp(modname, "cyclic") == 0) >+ return; >+ >+ /* >+ * To register with DTrace, a module must list 'dtrace' as a >+ * dependency in order for the kernel linker to resolve >+ * symbols like dtrace_register(). All modules with such a >+ * dependency are ineligible for FBT tracing. >+ */ >+ for (i = 0; i < lf->ndeps; i++) >+ if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0) >+ return; >+ >+ if (lf->fbt_nentries) { >+ /* >+ * This module has some FBT entries allocated; we're afraid >+ * to screw with it. >+ */ >+ return; >+ } >+ >+ /* >+ * List the functions in the module and the symbol values. >+ */ >+ (void) linker_file_function_listall(lf, fbt_provide_module_function, modname); >+} >+ >+static void >+fbt_destroy(void *arg, dtrace_id_t id, void *parg) >+{ >+ fbt_probe_t *fbt = parg, *next, *hash, *last; >+ modctl_t *ctl; >+ int ndx; >+ >+ do { >+ ctl = fbt->fbtp_ctl; >+ >+ ctl->fbt_nentries--; >+ >+ /* >+ * Now we need to remove this probe from the fbt_probetab. >+ */ >+ ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint); >+ last = NULL; >+ hash = fbt_probetab[ndx]; >+ >+ while (hash != fbt) { >+ ASSERT(hash != NULL); >+ last = hash; >+ hash = hash->fbtp_hashnext; >+ } >+ >+ if (last != NULL) { >+ last->fbtp_hashnext = fbt->fbtp_hashnext; >+ } else { >+ fbt_probetab[ndx] = fbt->fbtp_hashnext; >+ } >+ >+ next = fbt->fbtp_next; >+ free(fbt, M_FBT); >+ >+ fbt = next; >+ } while (fbt != NULL); >+} >+ >+static void >+fbt_enable(void *arg, dtrace_id_t id, void *parg) >+{ >+ fbt_probe_t *fbt = parg; >+ modctl_t *ctl = fbt->fbtp_ctl; >+ >+ ctl->nenabled++; >+ >+ /* >+ * Now check that our modctl has the expected load count. If it >+ * doesn't, this module must have been unloaded and reloaded -- and >+ * we're not going to touch it. >+ */ >+ if (ctl->loadcnt != fbt->fbtp_loadcnt) { >+ if (fbt_verbose) { >+ printf("fbt is failing for probe %s " >+ "(module %s reloaded)", >+ fbt->fbtp_name, ctl->filename); >+ } >+ >+ return; >+ } >+ >+ for (; fbt != NULL; fbt = fbt->fbtp_next) { >+ *fbt->fbtp_patchpoint = fbt->fbtp_patchval; >+ cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); >+ } >+} >+ >+static void >+fbt_disable(void *arg, dtrace_id_t id, void *parg) >+{ >+ fbt_probe_t *fbt = parg; >+ modctl_t *ctl = fbt->fbtp_ctl; >+ >+ ASSERT(ctl->nenabled > 0); >+ ctl->nenabled--; >+ >+ if ((ctl->loadcnt != fbt->fbtp_loadcnt)) >+ return; >+ >+ for (; fbt != NULL; fbt = fbt->fbtp_next) { >+ *fbt->fbtp_patchpoint = fbt->fbtp_savedval; >+ cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); >+ } >+} >+ >+static void >+fbt_suspend(void *arg, dtrace_id_t id, void *parg) >+{ >+ fbt_probe_t *fbt = parg; >+ modctl_t *ctl = fbt->fbtp_ctl; >+ >+ ASSERT(ctl->nenabled > 0); >+ >+ if ((ctl->loadcnt != fbt->fbtp_loadcnt)) >+ return; >+ >+ for (; fbt != NULL; fbt = fbt->fbtp_next) { >+ *fbt->fbtp_patchpoint = fbt->fbtp_savedval; >+ cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); >+ } >+} >+ >+static void >+fbt_resume(void *arg, dtrace_id_t id, void *parg) >+{ >+ fbt_probe_t *fbt = parg; >+ modctl_t *ctl = fbt->fbtp_ctl; >+ >+ ASSERT(ctl->nenabled > 0); >+ >+ if ((ctl->loadcnt != fbt->fbtp_loadcnt)) >+ return; >+ >+ for (; fbt != NULL; fbt = fbt->fbtp_next) { >+ *fbt->fbtp_patchpoint = fbt->fbtp_patchval; >+ cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); >+ } >+} >+ >+static int >+fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc) >+{ >+ const Elf_Sym *symp = lc->symtab;; >+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; >+ const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); >+ int i; >+ uint32_t *ctfoff; >+ uint32_t objtoff = hp->cth_objtoff; >+ uint32_t funcoff = hp->cth_funcoff; >+ ushort_t info; >+ ushort_t vlen; >+ >+ /* Sanity check. */ >+ if (hp->cth_magic != CTF_MAGIC) { >+ printf("Bad magic value in CTF data of '%s'\n",lf->pathname); >+ return (EINVAL); >+ } >+ >+ if (lc->symtab == NULL) { >+ printf("No symbol table in '%s'\n",lf->pathname); >+ return (EINVAL); >+ } >+ >+ if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL) >+ return (ENOMEM); >+ >+ *lc->ctfoffp = ctfoff; >+ >+ for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) { >+ if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) { >+ *ctfoff = 0xffffffff; >+ continue; >+ } >+ >+ switch (ELF_ST_TYPE(symp->st_info)) { >+ case STT_OBJECT: >+ if (objtoff >= hp->cth_funcoff || >+ (symp->st_shndx == SHN_ABS && symp->st_value == 0)) { >+ *ctfoff = 0xffffffff; >+ break; >+ } >+ >+ *ctfoff = objtoff; >+ objtoff += sizeof (ushort_t); >+ break; >+ >+ case STT_FUNC: >+ if (funcoff >= hp->cth_typeoff) { >+ *ctfoff = 0xffffffff; >+ break; >+ } >+ >+ *ctfoff = funcoff; >+ >+ info = *((const ushort_t *)(ctfdata + funcoff)); >+ vlen = CTF_INFO_VLEN(info); >+ >+ /* >+ * If we encounter a zero pad at the end, just skip it. >+ * Otherwise skip over the function and its return type >+ * (+2) and the argument list (vlen). >+ */ >+ if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0) >+ funcoff += sizeof (ushort_t); /* skip pad */ >+ else >+ funcoff += sizeof (ushort_t) * (vlen + 2); >+ break; >+ >+ default: >+ *ctfoff = 0xffffffff; >+ break; >+ } >+ } >+ >+ return (0); >+} >+ >+static ssize_t >+fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep, >+ ssize_t *incrementp) >+{ >+ ssize_t size, increment; >+ >+ if (version > CTF_VERSION_1 && >+ tp->ctt_size == CTF_LSIZE_SENT) { >+ size = CTF_TYPE_LSIZE(tp); >+ increment = sizeof (ctf_type_t); >+ } else { >+ size = tp->ctt_size; >+ increment = sizeof (ctf_stype_t); >+ } >+ >+ if (sizep) >+ *sizep = size; >+ if (incrementp) >+ *incrementp = increment; >+ >+ return (size); >+} >+ >+static int >+fbt_typoff_init(linker_ctf_t *lc) >+{ >+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; >+ const ctf_type_t *tbuf; >+ const ctf_type_t *tend; >+ const ctf_type_t *tp; >+ const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); >+ int ctf_typemax = 0; >+ uint32_t *xp; >+ ulong_t pop[CTF_K_MAX + 1] = { 0 }; >+ >+ >+ /* Sanity check. */ >+ if (hp->cth_magic != CTF_MAGIC) >+ return (EINVAL); >+ >+ tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff); >+ tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff); >+ >+ int child = hp->cth_parname != 0; >+ >+ /* >+ * We make two passes through the entire type section. In this first >+ * pass, we count the number of each type and the total number of types. >+ */ >+ for (tp = tbuf; tp < tend; ctf_typemax++) { >+ ushort_t kind = CTF_INFO_KIND(tp->ctt_info); >+ ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); >+ ssize_t size, increment; >+ >+ size_t vbytes; >+ uint_t n; >+ >+ (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); >+ >+ switch (kind) { >+ case CTF_K_INTEGER: >+ case CTF_K_FLOAT: >+ vbytes = sizeof (uint_t); >+ break; >+ case CTF_K_ARRAY: >+ vbytes = sizeof (ctf_array_t); >+ break; >+ case CTF_K_FUNCTION: >+ vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); >+ break; >+ case CTF_K_STRUCT: >+ case CTF_K_UNION: >+ if (size < CTF_LSTRUCT_THRESH) { >+ ctf_member_t *mp = (ctf_member_t *) >+ ((uintptr_t)tp + increment); >+ >+ vbytes = sizeof (ctf_member_t) * vlen; >+ for (n = vlen; n != 0; n--, mp++) >+ child |= CTF_TYPE_ISCHILD(mp->ctm_type); >+ } else { >+ ctf_lmember_t *lmp = (ctf_lmember_t *) >+ ((uintptr_t)tp + increment); >+ >+ vbytes = sizeof (ctf_lmember_t) * vlen; >+ for (n = vlen; n != 0; n--, lmp++) >+ child |= >+ CTF_TYPE_ISCHILD(lmp->ctlm_type); >+ } >+ break; >+ case CTF_K_ENUM: >+ vbytes = sizeof (ctf_enum_t) * vlen; >+ break; >+ case CTF_K_FORWARD: >+ /* >+ * For forward declarations, ctt_type is the CTF_K_* >+ * kind for the tag, so bump that population count too. >+ * If ctt_type is unknown, treat the tag as a struct. >+ */ >+ if (tp->ctt_type == CTF_K_UNKNOWN || >+ tp->ctt_type >= CTF_K_MAX) >+ pop[CTF_K_STRUCT]++; >+ else >+ pop[tp->ctt_type]++; >+ /*FALLTHRU*/ >+ case CTF_K_UNKNOWN: >+ vbytes = 0; >+ break; >+ case CTF_K_POINTER: >+ case CTF_K_TYPEDEF: >+ case CTF_K_VOLATILE: >+ case CTF_K_CONST: >+ case CTF_K_RESTRICT: >+ child |= CTF_TYPE_ISCHILD(tp->ctt_type); >+ vbytes = 0; >+ break; >+ default: >+ printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); >+ return (EIO); >+ } >+ tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); >+ pop[kind]++; >+ } >+ >+ /* account for a sentinel value below */ >+ ctf_typemax++; >+ *lc->typlenp = ctf_typemax; >+ >+ if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL) >+ return (ENOMEM); >+ >+ *lc->typoffp = xp; >+ >+ /* type id 0 is used as a sentinel value */ >+ *xp++ = 0; >+ >+ /* >+ * In the second pass, fill in the type offset. >+ */ >+ for (tp = tbuf; tp < tend; xp++) { >+ ushort_t kind = CTF_INFO_KIND(tp->ctt_info); >+ ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); >+ ssize_t size, increment; >+ >+ size_t vbytes; >+ uint_t n; >+ >+ (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); >+ >+ switch (kind) { >+ case CTF_K_INTEGER: >+ case CTF_K_FLOAT: >+ vbytes = sizeof (uint_t); >+ break; >+ case CTF_K_ARRAY: >+ vbytes = sizeof (ctf_array_t); >+ break; >+ case CTF_K_FUNCTION: >+ vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); >+ break; >+ case CTF_K_STRUCT: >+ case CTF_K_UNION: >+ if (size < CTF_LSTRUCT_THRESH) { >+ ctf_member_t *mp = (ctf_member_t *) >+ ((uintptr_t)tp + increment); >+ >+ vbytes = sizeof (ctf_member_t) * vlen; >+ for (n = vlen; n != 0; n--, mp++) >+ child |= CTF_TYPE_ISCHILD(mp->ctm_type); >+ } else { >+ ctf_lmember_t *lmp = (ctf_lmember_t *) >+ ((uintptr_t)tp + increment); >+ >+ vbytes = sizeof (ctf_lmember_t) * vlen; >+ for (n = vlen; n != 0; n--, lmp++) >+ child |= >+ CTF_TYPE_ISCHILD(lmp->ctlm_type); >+ } >+ break; >+ case CTF_K_ENUM: >+ vbytes = sizeof (ctf_enum_t) * vlen; >+ break; >+ case CTF_K_FORWARD: >+ case CTF_K_UNKNOWN: >+ vbytes = 0; >+ break; >+ case CTF_K_POINTER: >+ case CTF_K_TYPEDEF: >+ case CTF_K_VOLATILE: >+ case CTF_K_CONST: >+ case CTF_K_RESTRICT: >+ vbytes = 0; >+ break; >+ default: >+ printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); >+ return (EIO); >+ } >+ *xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata); >+ tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); >+ } >+ >+ return (0); >+} >+ >+/* >+ * CTF Declaration Stack >+ * >+ * In order to implement ctf_type_name(), we must convert a type graph back >+ * into a C type declaration. Unfortunately, a type graph represents a storage >+ * class ordering of the type whereas a type declaration must obey the C rules >+ * for operator precedence, and the two orderings are frequently in conflict. >+ * For example, consider these CTF type graphs and their C declarations: >+ * >+ * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)() >+ * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[] >+ * >+ * In each case, parentheses are used to raise operator * to higher lexical >+ * precedence, so the string form of the C declaration cannot be constructed by >+ * walking the type graph links and forming the string from left to right. >+ * >+ * The functions in this file build a set of stacks from the type graph nodes >+ * corresponding to the C operator precedence levels in the appropriate order. >+ * The code in ctf_type_name() can then iterate over the levels and nodes in >+ * lexical precedence order and construct the final C declaration string. >+ */ >+typedef struct ctf_list { >+ struct ctf_list *l_prev; /* previous pointer or tail pointer */ >+ struct ctf_list *l_next; /* next pointer or head pointer */ >+} ctf_list_t; >+ >+#define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev)) >+#define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next)) >+ >+typedef enum { >+ CTF_PREC_BASE, >+ CTF_PREC_POINTER, >+ CTF_PREC_ARRAY, >+ CTF_PREC_FUNCTION, >+ CTF_PREC_MAX >+} ctf_decl_prec_t; >+ >+typedef struct ctf_decl_node { >+ ctf_list_t cd_list; /* linked list pointers */ >+ ctf_id_t cd_type; /* type identifier */ >+ uint_t cd_kind; /* type kind */ >+ uint_t cd_n; /* type dimension if array */ >+} ctf_decl_node_t; >+ >+typedef struct ctf_decl { >+ ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */ >+ int cd_order[CTF_PREC_MAX]; /* storage order of decls */ >+ ctf_decl_prec_t cd_qualp; /* qualifier precision */ >+ ctf_decl_prec_t cd_ordp; /* ordered precision */ >+ char *cd_buf; /* buffer for output */ >+ char *cd_ptr; /* buffer location */ >+ char *cd_end; /* buffer limit */ >+ size_t cd_len; /* buffer space required */ >+ int cd_err; /* saved error value */ >+} ctf_decl_t; >+ >+/* >+ * Simple doubly-linked list append routine. This implementation assumes that >+ * each list element contains an embedded ctf_list_t as the first member. >+ * An additional ctf_list_t is used to store the head (l_next) and tail >+ * (l_prev) pointers. The current head and tail list elements have their >+ * previous and next pointers set to NULL, respectively. >+ */ >+static void >+ctf_list_append(ctf_list_t *lp, void *new) >+{ >+ ctf_list_t *p = lp->l_prev; /* p = tail list element */ >+ ctf_list_t *q = new; /* q = new list element */ >+ >+ lp->l_prev = q; >+ q->l_prev = p; >+ q->l_next = NULL; >+ >+ if (p != NULL) >+ p->l_next = q; >+ else >+ lp->l_next = q; >+} >+ >+/* >+ * Prepend the specified existing element to the given ctf_list_t. The >+ * existing pointer should be pointing at a struct with embedded ctf_list_t. >+ */ >+static void >+ctf_list_prepend(ctf_list_t *lp, void *new) >+{ >+ ctf_list_t *p = new; /* p = new list element */ >+ ctf_list_t *q = lp->l_next; /* q = head list element */ >+ >+ lp->l_next = p; >+ p->l_prev = NULL; >+ p->l_next = q; >+ >+ if (q != NULL) >+ q->l_prev = p; >+ else >+ lp->l_prev = p; >+} >+ >+static void >+ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len) >+{ >+ int i; >+ >+ bzero(cd, sizeof (ctf_decl_t)); >+ >+ for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) >+ cd->cd_order[i] = CTF_PREC_BASE - 1; >+ >+ cd->cd_qualp = CTF_PREC_BASE; >+ cd->cd_ordp = CTF_PREC_BASE; >+ >+ cd->cd_buf = buf; >+ cd->cd_ptr = buf; >+ cd->cd_end = buf + len; >+} >+ >+static void >+ctf_decl_fini(ctf_decl_t *cd) >+{ >+ ctf_decl_node_t *cdp, *ndp; >+ int i; >+ >+ for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) { >+ for (cdp = ctf_list_next(&cd->cd_nodes[i]); >+ cdp != NULL; cdp = ndp) { >+ ndp = ctf_list_next(cdp); >+ free(cdp, M_FBT); >+ } >+ } >+} >+ >+static const ctf_type_t * >+ctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type) >+{ >+ const ctf_type_t *tp; >+ uint32_t offset; >+ uint32_t *typoff = *lc->typoffp; >+ >+ if (type >= *lc->typlenp) { >+ printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp); >+ return(NULL); >+ } >+ >+ /* Check if the type isn't cross-referenced. */ >+ if ((offset = typoff[type]) == 0) { >+ printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type); >+ return(NULL); >+ } >+ >+ tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t)); >+ >+ return (tp); >+} >+ >+static void >+fbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp) >+{ >+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; >+ const ctf_type_t *tp; >+ const ctf_array_t *ap; >+ ssize_t increment; >+ >+ bzero(arp, sizeof(*arp)); >+ >+ if ((tp = ctf_lookup_by_id(lc, type)) == NULL) >+ return; >+ >+ if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY) >+ return; >+ >+ (void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment); >+ >+ ap = (const ctf_array_t *)((uintptr_t)tp + increment); >+ arp->ctr_contents = ap->cta_contents; >+ arp->ctr_index = ap->cta_index; >+ arp->ctr_nelems = ap->cta_nelems; >+} >+ >+static const char * >+ctf_strptr(linker_ctf_t *lc, int name) >+{ >+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;; >+ const char *strp = ""; >+ >+ if (name < 0 || name >= hp->cth_strlen) >+ return(strp); >+ >+ strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t)); >+ >+ return (strp); >+} >+ >+static void >+ctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type) >+{ >+ ctf_decl_node_t *cdp; >+ ctf_decl_prec_t prec; >+ uint_t kind, n = 1; >+ int is_qual = 0; >+ >+ const ctf_type_t *tp; >+ ctf_arinfo_t ar; >+ >+ if ((tp = ctf_lookup_by_id(lc, type)) == NULL) { >+ cd->cd_err = ENOENT; >+ return; >+ } >+ >+ switch (kind = CTF_INFO_KIND(tp->ctt_info)) { >+ case CTF_K_ARRAY: >+ fbt_array_info(lc, type, &ar); >+ ctf_decl_push(cd, lc, ar.ctr_contents); >+ n = ar.ctr_nelems; >+ prec = CTF_PREC_ARRAY; >+ break; >+ >+ case CTF_K_TYPEDEF: >+ if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') { >+ ctf_decl_push(cd, lc, tp->ctt_type); >+ return; >+ } >+ prec = CTF_PREC_BASE; >+ break; >+ >+ case CTF_K_FUNCTION: >+ ctf_decl_push(cd, lc, tp->ctt_type); >+ prec = CTF_PREC_FUNCTION; >+ break; >+ >+ case CTF_K_POINTER: >+ ctf_decl_push(cd, lc, tp->ctt_type); >+ prec = CTF_PREC_POINTER; >+ break; >+ >+ case CTF_K_VOLATILE: >+ case CTF_K_CONST: >+ case CTF_K_RESTRICT: >+ ctf_decl_push(cd, lc, tp->ctt_type); >+ prec = cd->cd_qualp; >+ is_qual++; >+ break; >+ >+ default: >+ prec = CTF_PREC_BASE; >+ } >+ >+ if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) { >+ cd->cd_err = EAGAIN; >+ return; >+ } >+ >+ cdp->cd_type = type; >+ cdp->cd_kind = kind; >+ cdp->cd_n = n; >+ >+ if (ctf_list_next(&cd->cd_nodes[prec]) == NULL) >+ cd->cd_order[prec] = cd->cd_ordp++; >+ >+ /* >+ * Reset cd_qualp to the highest precedence level that we've seen so >+ * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). >+ */ >+ if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) >+ cd->cd_qualp = prec; >+ >+ /* >+ * C array declarators are ordered inside out so prepend them. Also by >+ * convention qualifiers of base types precede the type specifier (e.g. >+ * const int vs. int const) even though the two forms are equivalent. >+ */ >+ if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) >+ ctf_list_prepend(&cd->cd_nodes[prec], cdp); >+ else >+ ctf_list_append(&cd->cd_nodes[prec], cdp); >+} >+ >+static void >+ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...) >+{ >+ size_t len = (size_t)(cd->cd_end - cd->cd_ptr); >+ va_list ap; >+ size_t n; >+ >+ va_start(ap, format); >+ n = vsnprintf(cd->cd_ptr, len, format, ap); >+ va_end(ap); >+ >+ cd->cd_ptr += MIN(n, len); >+ cd->cd_len += n; >+} >+ >+static ssize_t >+fbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len) >+{ >+ ctf_decl_t cd; >+ ctf_decl_node_t *cdp; >+ ctf_decl_prec_t prec, lp, rp; >+ int ptr, arr; >+ uint_t k; >+ >+ if (lc == NULL && type == CTF_ERR) >+ return (-1); /* simplify caller code by permitting CTF_ERR */ >+ >+ ctf_decl_init(&cd, buf, len); >+ ctf_decl_push(&cd, lc, type); >+ >+ if (cd.cd_err != 0) { >+ ctf_decl_fini(&cd); >+ return (-1); >+ } >+ >+ /* >+ * If the type graph's order conflicts with lexical precedence order >+ * for pointers or arrays, then we need to surround the declarations at >+ * the corresponding lexical precedence with parentheses. This can >+ * result in either a parenthesized pointer (*) as in int (*)() or >+ * int (*)[], or in a parenthesized pointer and array as in int (*[])(). >+ */ >+ ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; >+ arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; >+ >+ rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; >+ lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; >+ >+ k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ >+ >+ for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { >+ for (cdp = ctf_list_next(&cd.cd_nodes[prec]); >+ cdp != NULL; cdp = ctf_list_next(cdp)) { >+ >+ const ctf_type_t *tp = >+ ctf_lookup_by_id(lc, cdp->cd_type); >+ const char *name = ctf_strptr(lc, tp->ctt_name); >+ >+ if (k != CTF_K_POINTER && k != CTF_K_ARRAY) >+ ctf_decl_sprintf(&cd, " "); >+ >+ if (lp == prec) { >+ ctf_decl_sprintf(&cd, "("); >+ lp = -1; >+ } >+ >+ switch (cdp->cd_kind) { >+ case CTF_K_INTEGER: >+ case CTF_K_FLOAT: >+ case CTF_K_TYPEDEF: >+ ctf_decl_sprintf(&cd, "%s", name); >+ break; >+ case CTF_K_POINTER: >+ ctf_decl_sprintf(&cd, "*"); >+ break; >+ case CTF_K_ARRAY: >+ ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); >+ break; >+ case CTF_K_FUNCTION: >+ ctf_decl_sprintf(&cd, "()"); >+ break; >+ case CTF_K_STRUCT: >+ case CTF_K_FORWARD: >+ ctf_decl_sprintf(&cd, "struct %s", name); >+ break; >+ case CTF_K_UNION: >+ ctf_decl_sprintf(&cd, "union %s", name); >+ break; >+ case CTF_K_ENUM: >+ ctf_decl_sprintf(&cd, "enum %s", name); >+ break; >+ case CTF_K_VOLATILE: >+ ctf_decl_sprintf(&cd, "volatile"); >+ break; >+ case CTF_K_CONST: >+ ctf_decl_sprintf(&cd, "const"); >+ break; >+ case CTF_K_RESTRICT: >+ ctf_decl_sprintf(&cd, "restrict"); >+ break; >+ } >+ >+ k = cdp->cd_kind; >+ } >+ >+ if (rp == prec) >+ ctf_decl_sprintf(&cd, ")"); >+ } >+ >+ ctf_decl_fini(&cd); >+ return (cd.cd_len); >+} >+ >+static void >+fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc) >+{ >+ const ushort_t *dp; >+ fbt_probe_t *fbt = parg; >+ linker_ctf_t lc; >+ modctl_t *ctl = fbt->fbtp_ctl; >+ int ndx = desc->dtargd_ndx; >+ int symindx = fbt->fbtp_symindx; >+ uint32_t *ctfoff; >+ uint32_t offset; >+ ushort_t info, kind, n; >+ >+ if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { >+ (void) strcpy(desc->dtargd_native, "int"); >+ return; >+ } >+ >+ desc->dtargd_ndx = DTRACE_ARGNONE; >+ >+ /* Get a pointer to the CTF data and it's length. */ >+ if (linker_ctf_get(ctl, &lc) != 0) >+ /* No CTF data? Something wrong? *shrug* */ >+ return; >+ >+ /* Check if this module hasn't been initialised yet. */ >+ if (*lc.ctfoffp == NULL) { >+ /* >+ * Initialise the CTF object and function symindx to >+ * byte offset array. >+ */ >+ if (fbt_ctfoff_init(ctl, &lc) != 0) >+ return; >+ >+ /* Initialise the CTF type to byte offset array. */ >+ if (fbt_typoff_init(&lc) != 0) >+ return; >+ } >+ >+ ctfoff = *lc.ctfoffp; >+ >+ if (ctfoff == NULL || *lc.typoffp == NULL) >+ return; >+ >+ /* Check if the symbol index is out of range. */ >+ if (symindx >= lc.nsym) >+ return; >+ >+ /* Check if the symbol isn't cross-referenced. */ >+ if ((offset = ctfoff[symindx]) == 0xffffffff) >+ return; >+ >+ dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t)); >+ >+ info = *dp++; >+ kind = CTF_INFO_KIND(info); >+ n = CTF_INFO_VLEN(info); >+ >+ if (kind == CTF_K_UNKNOWN && n == 0) { >+ printf("%s(%d): Unknown function!\n",__func__,__LINE__); >+ return; >+ } >+ >+ if (kind != CTF_K_FUNCTION) { >+ printf("%s(%d): Expected a function!\n",__func__,__LINE__); >+ return; >+ } >+ >+ if (fbt->fbtp_roffset != 0) { >+ /* Only return type is available for args[1] in return probe. */ >+ if (ndx > 1) >+ return; >+ ASSERT(ndx == 1); >+ } else { >+ /* Check if the requested argument doesn't exist. */ >+ if (ndx >= n) >+ return; >+ >+ /* Skip the return type and arguments up to the one requested. */ >+ dp += ndx + 1; >+ } >+ >+ if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0) >+ desc->dtargd_ndx = ndx; >+ >+ return; >+} >+ >+static int >+fbt_linker_file_cb(linker_file_t lf, void *arg) >+{ >+ >+ fbt_provide_module(arg, lf); >+ >+ return (0); >+} >+ >+static void >+fbt_load(void *dummy) >+{ >+ /* Create the /dev/dtrace/fbt entry. */ >+ fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, >+ "dtrace/fbt"); >+ >+ /* Default the probe table size if not specified. */ >+ if (fbt_probetab_size == 0) >+ fbt_probetab_size = FBT_PROBETAB_SIZE; >+ >+ /* Choose the hash mask for the probe table. */ >+ fbt_probetab_mask = fbt_probetab_size - 1; >+ >+ /* Allocate memory for the probe table. */ >+ fbt_probetab = >+ malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO); >+ >+ dtrace_invop_add(fbt_invop); >+ >+ if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER, >+ NULL, &fbt_pops, NULL, &fbt_id) != 0) >+ return; >+ >+ /* Create probes for the kernel and already-loaded modules. */ >+ linker_file_foreach(fbt_linker_file_cb, NULL); >+} >+ >+ >+static int >+fbt_unload() >+{ >+ int error = 0; >+ >+ /* De-register the invalid opcode handler. */ >+ dtrace_invop_remove(fbt_invop); >+ >+ /* De-register this DTrace provider. */ >+ if ((error = dtrace_unregister(fbt_id)) != 0) >+ return (error); >+ >+ /* Free the probe table. */ >+ free(fbt_probetab, M_FBT); >+ fbt_probetab = NULL; >+ fbt_probetab_mask = 0; >+ >+ destroy_dev(fbt_cdev); >+ >+ return (error); >+} >+ >+static int >+fbt_modevent(module_t mod __unused, int type, void *data __unused) >+{ >+ int error = 0; >+ >+ switch (type) { >+ case MOD_LOAD: >+ break; >+ >+ case MOD_UNLOAD: >+ break; >+ >+ case MOD_SHUTDOWN: >+ break; >+ >+ default: >+ error = EOPNOTSUPP; >+ break; >+ >+ } >+ >+ return (error); >+} >+ >+static int >+fbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) >+{ >+ return (0); >+} >+ >+SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL); >+SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL); >+ >+DEV_MODULE(fbt, fbt_modevent, NULL); >+MODULE_VERSION(fbt, 1); >+MODULE_DEPEND(fbt, dtrace, 1, 1, 1); >+MODULE_DEPEND(fbt, opensolaris, 1, 1, 1); >diff --git a/sys/cddl/dev/lockstat/lockstat.c b/sys/cddl/dev/lockstat/lockstat.c >index 9b3f7d7..a7e5896 100644 >--- a/sys/cddl/dev/lockstat/lockstat.c >+++ b/sys/cddl/dev/lockstat/lockstat.c >@@ -46,7 +46,8 @@ > #include <sys/lockstat.h> > > #if defined(__i386__) || defined(__amd64__) || \ >- defined(__mips__) || defined(__powerpc__) >+ defined(__mips__) || defined(__powerpc__) || \ >+ defined(__arm__) > #define LOCKSTAT_AFRAMES 1 > #else > #error "architecture not supported" >diff --git a/sys/cddl/dev/profile/profile.c b/sys/cddl/dev/profile/profile.c >index 051ffa1..870c533 100644 >--- a/sys/cddl/dev/profile/profile.c >+++ b/sys/cddl/dev/profile/profile.c >@@ -126,6 +126,16 @@ > #define PROF_ARTIFICIAL_FRAMES 3 > #endif > >+#ifdef __mips >+/* bogus */ >+#define PROF_ARTIFICIAL_FRAMES 3 >+#endif >+ >+#ifdef __arm__ >+/* bogus */ >+#define PROF_ARTIFICIAL_FRAMES 3 >+#endif >+ > typedef struct profile_probe { > char prof_name[PROF_NAMELEN]; > dtrace_id_t prof_id; >diff --git a/sys/modules/dtrace/Makefile b/sys/modules/dtrace/Makefile >index 1b12371..b819316 100644 >--- a/sys/modules/dtrace/Makefile >+++ b/sys/modules/dtrace/Makefile >@@ -24,5 +24,7 @@ SUBDIR+= fbt fasttrap > .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64" > SUBDIR+= systrace_freebsd32 > .endif >- >+.if ${MACHINE_CPUARCH} == "arm" >+SUBDIR+= fbt >+.endif > .include <bsd.subdir.mk> >diff --git a/sys/modules/dtrace/dtrace/Makefile b/sys/modules/dtrace/dtrace/Makefile >index 3299a1e..aa6b83b 100644 >--- a/sys/modules/dtrace/dtrace/Makefile >+++ b/sys/modules/dtrace/dtrace/Makefile >@@ -22,7 +22,7 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/intel > SRCS+= bus_if.h device_if.h vnode_if.h > > # Needed for dtrace_asm.S >-SRCS+= assym.s >+#SRCS+= assym.s > > # These are needed for assym.s > SRCS+= opt_compat.h opt_kstack_pages.h opt_nfs.h opt_hwpmc_hooks.h >diff --git a/sys/modules/dtrace/fbt/Makefile b/sys/modules/dtrace/fbt/Makefile >index 7c03d31..4bb8195 100644 >--- a/sys/modules/dtrace/fbt/Makefile >+++ b/sys/modules/dtrace/fbt/Makefile >@@ -3,8 +3,8 @@ > .PATH: ${.CURDIR}/../../../cddl/dev/fbt > > KMOD= fbt >-.if ${MACHINE_CPUARCH} == "powerpc" >-SRCS= fbt_powerpc.c >+.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" >+SRCS= fbt_${MACHINE_CPUARCH}.c > .else > SRCS= fbt.c > .endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 192516
:
145527
| 145544