X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..e8c3f78193f1895ea514044358b93b1add9322f3:/bsd/dev/dtrace/systrace.c diff --git a/bsd/dev/dtrace/systrace.c b/bsd/dev/dtrace/systrace.c index c8a6305b1..10ba83433 100644 --- a/bsd/dev/dtrace/systrace.c +++ b/bsd/dev/dtrace/systrace.c @@ -49,10 +49,12 @@ #include #include #include +#include #include #include #include +#include #include "systrace.h" #include #include @@ -64,10 +66,15 @@ #if defined (__x86_64__) #define SYSTRACE_ARTIFICIAL_FRAMES 2 #define MACHTRACE_ARTIFICIAL_FRAMES 3 +#elif defined(__arm__) || defined(__arm64__) +#define SYSTRACE_ARTIFICIAL_FRAMES 2 +#define MACHTRACE_ARTIFICIAL_FRAMES 3 #else #error Unknown Architecture #endif +#define SYSTRACE_NARGS (int)(sizeof(((uthread_t)NULL)->uu_arg) / sizeof(((uthread_t)NULL)->uu_arg[0])) + #include #define sy_callc sy_call /* Map Solaris slot name to Darwin's */ #define NSYSCALL nsysent /* and is less than 500 or so */ @@ -88,7 +95,8 @@ static lck_mtx_t dtrace_systrace_lock; /* probe state lock */ systrace_sysent_t *systrace_sysent = NULL; void (*systrace_probe)(dtrace_id_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); -static uint64_t systrace_getarg(void *, dtrace_id_t, void *, int, int); +static uint64_t systrace_getargval(void *, dtrace_id_t, void *, int, int); +static void systrace_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); void systrace_stub(dtrace_id_t id, uint64_t arg0, uint64_t arg1, @@ -105,10 +113,8 @@ dtrace_systrace_syscall(struct proc *pp, void *uap, int *rv) systrace_sysent_t *sy; dtrace_id_t id; int32_t rval; -#if 0 /* XXX */ - proc_t *p; -#endif syscall_arg_t *ip = (syscall_arg_t *)uap; + uint64_t uargs[SYSTRACE_NARGS] = {0}; #if defined (__x86_64__) { @@ -134,27 +140,74 @@ dtrace_systrace_syscall(struct proc *pp, void *uap, int *rv) } } } +#elif defined(__arm__) + { + /* + * On arm, syscall numbers depend on a flavor (indirect or not) + * and can be in either r0 or r12 (always u32) + */ + + /* See bsd/dev/arm/systemcalls.c:arm_get_syscall_number */ + arm_saved_state_t *arm_regs = (arm_saved_state_t *) find_user_regs(current_thread()); + + /* Check for indirect system call */ + if (arm_regs->r[12] != 0) + code = arm_regs->r[12]; + else + code = arm_regs->r[0]; + } +#elif defined(__arm64__) + { + /* + * On arm64, syscall numbers depend on a flavor (indirect or not) + * ... and for u32 can be in either r0 or r12 + * ... and for u64 can be in either x0 or x16 + */ + + /* see bsd/dev/arm/systemcalls.c:arm_get_syscall_number */ + arm_saved_state_t *arm_regs = (arm_saved_state_t *) find_user_regs(current_thread()); + + if (is_saved_state32(arm_regs)) { + /* Check for indirect system call */ + if (saved_state32(arm_regs)->r[12] != 0) { + code = saved_state32(arm_regs)->r[12]; + } + else { + code = saved_state32(arm_regs)->r[0]; + } + } else { + /* Check for indirect system call */ + if (saved_state64(arm_regs)->x[ARM64_SYSCALL_CODE_REG_NUM] != 0 ) { + code = saved_state64(arm_regs)->x[ARM64_SYSCALL_CODE_REG_NUM]; + } + else { + code = saved_state64(arm_regs)->x[0]; + } + } + } #else #error Unknown Architecture #endif // Bounds "check" the value of code a la unix_syscall - sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code]; + sy = (code >= nsysent) ? &systrace_sysent[SYS_invalid] : &systrace_sysent[code]; + + systrace_args(code, ip, uargs); if ((id = sy->stsy_entry) != DTRACE_IDNONE) { uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread()); if (uthread) - uthread->t_dtrace_syscall_args = (void *)ip; + uthread->t_dtrace_syscall_args = uargs; - if (ip) - (*systrace_probe)(id, *ip, *(ip+1), *(ip+2), *(ip+3), *(ip+4)); - else - (*systrace_probe)(id, 0, 0, 0, 0, 0); + static_assert(SYSTRACE_NARGS >= 5, "not enough system call arguments"); + (*systrace_probe)(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]); if (uthread) - uthread->t_dtrace_syscall_args = (void *)0; + uthread->t_dtrace_syscall_args = NULL; } + + #if 0 /* XXX */ /* * APPLE NOTE: Not implemented. @@ -254,7 +307,7 @@ dtrace_systrace_syscall_return(unsigned short code, int rval, int *rv) dtrace_id_t id; // Bounds "check" the value of code a la unix_syscall_return - sy = (code >= NUM_SYSENT) ? &systrace_sysent[63] : &systrace_sysent[code]; + sy = (code >= nsysent) ? &systrace_sysent[SYS_invalid] : &systrace_sysent[code]; if ((id = sy->stsy_return) != DTRACE_IDNONE) { uint64_t munged_rv0, munged_rv1; @@ -323,7 +376,6 @@ dtrace_systrace_syscall_return(unsigned short code, int rval, int *rv) #error 1 << SYSTRACE_SHIFT must exceed number of system calls #endif -static dev_info_t *systrace_devi; static dtrace_provider_id_t systrace_id; /* @@ -338,7 +390,7 @@ systrace_init(struct sysent *actual, systrace_sysent_t **interposed) systrace_sysent_t *ssysent = *interposed; /* Avoid sysent shadow warning from bsd/sys/sysent.h */ - int i; + unsigned int i; if (ssysent == NULL) { *interposed = ssysent = kmem_zalloc(sizeof (systrace_sysent_t) * @@ -355,11 +407,6 @@ systrace_init(struct sysent *actual, systrace_sysent_t **interposed) if (a->sy_callc == dtrace_systrace_syscall) continue; -#ifdef _SYSCALL32_IMPL - if (a->sy_callc == dtrace_systrace_syscall32) - continue; -#endif - s->stsy_underlying = a->sy_callc; s->stsy_return_type = a->sy_return_type; } @@ -372,15 +419,12 @@ static void systrace_provide(void *arg, const dtrace_probedesc_t *desc) { #pragma unused(arg) /* __APPLE__ */ - int i; + unsigned int i; if (desc != NULL) return; systrace_init(sysent, &systrace_sysent); -#ifdef _SYSCALL32_IMPL - systrace_init(sysent32, &systrace_sysent32); -#endif for (i = 0; i < NSYSCALL; i++) { if (systrace_sysent[i].stsy_underlying == NULL) @@ -399,10 +443,6 @@ systrace_provide(void *arg, const dtrace_probedesc_t *desc) systrace_sysent[i].stsy_entry = DTRACE_IDNONE; systrace_sysent[i].stsy_return = DTRACE_IDNONE; -#ifdef _SYSCALL32_IMPL - systrace_sysent32[i].stsy_entry = DTRACE_IDNONE; - systrace_sysent32[i].stsy_return = DTRACE_IDNONE; -#endif } } #undef systrace_init @@ -422,14 +462,8 @@ systrace_destroy(void *arg, dtrace_id_t id, void *parg) */ if (SYSTRACE_ISENTRY((uintptr_t)parg)) { ASSERT(systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE); -#ifdef _SYSCALL32_IMPL - ASSERT(systrace_sysent32[sysnum].stsy_entry == DTRACE_IDNONE); -#endif } else { ASSERT(systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE); -#ifdef _SYSCALL32_IMPL - ASSERT(systrace_sysent32[sysnum].stsy_return == DTRACE_IDNONE); -#endif } } @@ -445,25 +479,14 @@ systrace_enable(void *arg, dtrace_id_t id, void *parg) if (SYSTRACE_ISENTRY((uintptr_t)parg)) { systrace_sysent[sysnum].stsy_entry = id; -#ifdef _SYSCALL32_IMPL - systrace_sysent32[sysnum].stsy_entry = id; -#endif } else { systrace_sysent[sysnum].stsy_return = id; -#ifdef _SYSCALL32_IMPL - systrace_sysent32[sysnum].stsy_return = id; -#endif } if (enabled) { ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall); return(0); } -#ifdef _SYSCALL32_IMPL - (void) casptr(&sysent32[sysnum].sy_callc, - (void *)systrace_sysent32[sysnum].stsy_underlying, - (void *)dtrace_systrace_syscall32); -#endif lck_mtx_lock(&dtrace_systrace_lock); if (sysent[sysnum].sy_callc == systrace_sysent[sysnum].stsy_underlying) { @@ -490,23 +513,12 @@ systrace_disable(void *arg, dtrace_id_t id, void *parg) ml_nofault_copy((vm_offset_t)&systrace_sysent[sysnum].stsy_underlying, (vm_offset_t)&sysent[sysnum].sy_callc, sizeof(systrace_sysent[sysnum].stsy_underlying)); lck_mtx_unlock(&dtrace_systrace_lock); -#ifdef _SYSCALL32_IMPL - (void) casptr(&sysent32[sysnum].sy_callc, - (void *)dtrace_systrace_syscall32, - (void *)systrace_sysent32[sysnum].stsy_underlying); -#endif } if (SYSTRACE_ISENTRY((uintptr_t)parg)) { systrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE; -#ifdef _SYSCALL32_IMPL - systrace_sysent32[sysnum].stsy_entry = DTRACE_IDNONE; -#endif } else { systrace_sysent[sysnum].stsy_return = DTRACE_IDNONE; -#ifdef _SYSCALL32_IMPL - systrace_sysent32[sysnum].stsy_return = DTRACE_IDNONE; -#endif } } @@ -519,31 +531,22 @@ static dtrace_pattr_t systrace_attr = { }; static dtrace_pops_t systrace_pops = { - systrace_provide, - NULL, - systrace_enable, - systrace_disable, - NULL, - NULL, - NULL, - systrace_getarg, - NULL, - systrace_destroy + .dtps_provide = systrace_provide, + .dtps_provide_module = NULL, + .dtps_enable = systrace_enable, + .dtps_disable = systrace_disable, + .dtps_suspend = NULL, + .dtps_resume = NULL, + .dtps_getargdesc = systrace_getargdesc, + .dtps_getargval = systrace_getargval, + .dtps_usermode = NULL, + .dtps_destroy = systrace_destroy }; static int -systrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +systrace_attach(dev_info_t *devi) { - switch (cmd) { - case DDI_ATTACH: - break; - case DDI_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - - systrace_probe = (void(*))&dtrace_probe; + systrace_probe = (void*)&dtrace_probe; membar_enter(); if (ddi_create_minor_node(devi, "systrace", S_IFCHR, 0, @@ -555,9 +558,6 @@ systrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) return (DDI_FAILURE); } - ddi_report_dev(devi); - systrace_devi = devi; - return (DDI_SUCCESS); } @@ -644,7 +644,6 @@ void (*machtrace_probe)(dtrace_id_t, uint64_t, uint64_t, static uint64_t machtrace_getarg(void *, dtrace_id_t, void *, int, int); -static dev_info_t *machtrace_devi; static dtrace_provider_id_t machtrace_id; static kern_return_t @@ -672,6 +671,28 @@ dtrace_machtrace_syscall(struct mach_call_args *args) code = -saved_state32(tagged_regs)->eax; } } +#elif defined(__arm__) + { + /* r12 has the machcall number, but it is -ve */ + arm_saved_state_t *arm_regs = (arm_saved_state_t *) find_user_regs(current_thread()); + code = (int)arm_regs->r[12]; + ASSERT(code < 0); /* Otherwise it would be a Unix syscall */ + code = -code; + } +#elif defined(__arm64__) + { + /* From arm/thread_status.h:get_saved_state_svc_number */ + arm_saved_state_t *arm_regs = (arm_saved_state_t *) find_user_regs(current_thread()); + if (is_saved_state32(arm_regs)) { + code = (int)saved_state32(arm_regs)->r[12]; + } else { + code = (int)saved_state64(arm_regs)->x[ARM64_SYSCALL_CODE_REG_NUM]; + } + + /* From bsd/arm64.c:mach_syscall */ + ASSERT(code < 0); /* Otherwise it would be a Unix syscall */ + code = -code; + } #else #error Unknown Architecture #endif @@ -862,30 +883,21 @@ static dtrace_pattr_t machtrace_attr = { }; static dtrace_pops_t machtrace_pops = { - machtrace_provide, - NULL, - machtrace_enable, - machtrace_disable, - NULL, - NULL, - NULL, - machtrace_getarg, - NULL, - machtrace_destroy + .dtps_provide = machtrace_provide, + .dtps_provide_module = NULL, + .dtps_enable = machtrace_enable, + .dtps_disable = machtrace_disable, + .dtps_suspend = NULL, + .dtps_resume = NULL, + .dtps_getargdesc = NULL, + .dtps_getargval = machtrace_getarg, + .dtps_usermode = NULL, + .dtps_destroy = machtrace_destroy }; static int -machtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +machtrace_attach(dev_info_t *devi) { - switch (cmd) { - case DDI_ATTACH: - break; - case DDI_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - machtrace_probe = dtrace_probe; membar_enter(); @@ -893,14 +905,11 @@ machtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) DDI_PSEUDO, 0) == DDI_FAILURE || dtrace_register("mach_trap", &machtrace_attr, DTRACE_PRIV_USER, NULL, &machtrace_pops, NULL, &machtrace_id) != 0) { - machtrace_probe = (void (*))&systrace_stub; + machtrace_probe = (void*)&systrace_stub; ddi_remove_minor_node(devi, NULL); return (DDI_FAILURE); } - ddi_report_dev(devi); - machtrace_devi = devi; - return (DDI_SUCCESS); } @@ -936,52 +945,76 @@ static struct cdevsw systrace_cdevsw = 0 /* type */ }; -static int gSysTraceInited = 0; - void systrace_init( void ); void systrace_init( void ) { - if (0 == gSysTraceInited) { - int majdevno = cdevsw_add(SYSTRACE_MAJOR, &systrace_cdevsw); + if (dtrace_sdt_probes_restricted()) { + return; + } - if (majdevno < 0) { - printf("systrace_init: failed to allocate a major number!\n"); - gSysTraceInited = 0; - return; - } + int majdevno = cdevsw_add(SYSTRACE_MAJOR, &systrace_cdevsw); - systrace_attach( (dev_info_t *)(uintptr_t)majdevno, DDI_ATTACH ); - machtrace_attach( (dev_info_t *)(uintptr_t)majdevno, DDI_ATTACH ); + if (majdevno < 0) { + printf("systrace_init: failed to allocate a major number!\n"); + return; + } - gSysTraceInited = 1; - } else - panic("systrace_init: called twice!\n"); + systrace_attach((dev_info_t*)(uintptr_t)majdevno); + machtrace_attach((dev_info_t*)(uintptr_t)majdevno); } #undef SYSTRACE_MAJOR static uint64_t -systrace_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) +systrace_getargval(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { #pragma unused(arg,id,parg,aframes) /* __APPLE__ */ uint64_t val = 0; - syscall_arg_t *stack = (syscall_arg_t *)NULL; + uint64_t *uargs = NULL; uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread()); if (uthread) - stack = (syscall_arg_t *)uthread->t_dtrace_syscall_args; - - if (!stack) + uargs = uthread->t_dtrace_syscall_args; + if (!uargs) + return(0); + if (argno < 0 || argno >= SYSTRACE_NARGS) return(0); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - /* dtrace_probe arguments arg0 .. arg4 are 64bits wide */ - val = (uint64_t)*(stack+argno); + val = uargs[argno]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); } +static void +systrace_getargdesc(void *arg, dtrace_id_t id, void *parg, + dtrace_argdesc_t *desc) +{ +#pragma unused(arg, id) + int sysnum = SYSTRACE_SYSNUM(parg); + uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread()); + uint64_t *uargs = NULL; + + if (!uthread) { + desc->dtargd_ndx = DTRACE_ARGNONE; + return; + } + + uargs = uthread->t_dtrace_syscall_args; + + if (SYSTRACE_ISENTRY((uintptr_t)parg)) { + systrace_entry_setargdesc(sysnum, desc->dtargd_ndx, + desc->dtargd_native, sizeof(desc->dtargd_native)); + } + else { + systrace_return_setargdesc(sysnum, desc->dtargd_ndx, + desc->dtargd_native, sizeof(desc->dtargd_native)); + } + + if (desc->dtargd_native[0] == '\0') + desc->dtargd_ndx = DTRACE_ARGNONE; +} static uint64_t machtrace_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)