X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/a1c7dba18ef36983396c282fe85292db066e39db..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/libsyscall/wrappers/kdebug_trace.c diff --git a/libsyscall/wrappers/kdebug_trace.c b/libsyscall/wrappers/kdebug_trace.c index 4867f9b51..e42794a49 100644 --- a/libsyscall/wrappers/kdebug_trace.c +++ b/libsyscall/wrappers/kdebug_trace.c @@ -22,40 +22,158 @@ */ #include +#include +#include +#include #include #include +#include #include +#include +#include +#include +#include -#define CLASS_MASK 0xff000000 -#define CLASS_OFFSET 24 -#define SUBCLASS_MASK 0x00ff0000 -#define SUBCLASS_OFFSET 16 +extern int __kdebug_typefilter(void** addr, size_t* size); +extern int __kdebug_trace64(uint32_t code, uint64_t arg1, uint64_t arg2, + uint64_t arg3, uint64_t arg4); +extern uint64_t __kdebug_trace_string(uint32_t debugid, uint64_t str_id, + const char *str); -#define EXTRACT_CLASS(debugid) ((uint8_t)(((debugid) & CLASS_MASK) >> CLASS_OFFSET)) -#define EXTRACT_SUBCLASS(debugid) ( (uint8_t) ( ((debugid) & SUBCLASS_MASK) >> SUBCLASS_OFFSET ) ) +static int kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, + uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); -extern int __kdebug_trace64(uint32_t code, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); +/* + * GENERAL API DESIGN NOTE! + * + * Trace API's are expected to avoid performing checks until tracing has + * been enabled. This includes checks that might cause error codes to be + * returned. + * + * Trace invocations via wrapper and syscall must have the same behavior. + * + * Note that the userspace API is chosing to optimize fastpath, non-error + * performance by eliding validation of each debugid. This means that error + * cases which could have been caught in userspace will make a syscall + * before returning with the correct error code. This tradeoff in performance + * is intentional. + */ -int -kdebug_trace(uint32_t code, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) +void * +kdebug_typefilter(void) +{ + static void* typefilter; + + /* We expect kdebug_typefilter_bitmap to be valid (the if is not executed) */ + if (__builtin_expect(!typefilter, 0)) { + // Map the typefilter if it can be mapped. + void* ptr = NULL; + size_t ptr_size = 0; + + if (__kdebug_typefilter(&ptr, &ptr_size) == 0) { + void* old_value = NULL; + if (ptr && !atomic_compare_exchange_strong((void* _Atomic volatile *)&typefilter, &old_value, ptr)) { + mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)ptr, KDBG_TYPEFILTER_BITMAP_SIZE); + } + } + } + + return typefilter; +} + +bool +kdebug_is_enabled(uint32_t debugid) { - uint8_t code_class; - volatile uint32_t *kdebug_enable_address = (volatile uint32_t *)(uintptr_t)(_COMM_PAGE_KDEBUG_ENABLE); + uint32_t state = *((volatile uint32_t *)(uintptr_t)(_COMM_PAGE_KDEBUG_ENABLE)); + + if (state == 0) { + return FALSE; + } + + if ((state & KDEBUG_COMMPAGE_ENABLE_TYPEFILTER) > 0) { + /* + * Typefilter rules... + * + * If no typefilter is available (even if due to error), + * debugids are allowed. + * + * The typefilter will always allow DBG_TRACE; this is a kernel + * invariant. There is no need for an explicit check here. + * + * NOTE: The typefilter will always allow DBG_TRACE, but + * it is not legal to inject DBG_TRACE via kdebug_trace. + * Attempts to do so will not be detected here, but will be + * detected in the kernel, and an error will be returned. Per + * the API design note at the top of this file, this is a + * deliberate choice. + */ + uint8_t* typefilter = kdebug_typefilter(); + if (typefilter && isset(typefilter, KDBG_EXTRACT_CSC(debugid)) == 0) { + return FALSE; + } + } + + return TRUE; +} - /* - * This filtering is also done in the kernel, but we also do it here so that errors - * are returned in all cases, not just when the system call is actually performed. - */ - code_class = EXTRACT_CLASS(code); - switch (code_class) { - case DBG_TRACE: - errno = EPERM; - return -1; +int +kdebug_trace(uint32_t debugid, uint64_t arg1, uint64_t arg2, uint64_t arg3, + uint64_t arg4) +{ + if (!kdebug_is_enabled(debugid)) { + return 0; } - if (*kdebug_enable_address == 0) { + return __kdebug_trace64(debugid, arg1, arg2, arg3, arg4); +} + +uint64_t +kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str) +{ + if (!kdebug_is_enabled(debugid)) { return 0; } - - return __kdebug_trace64(code, arg1, arg2, arg3, arg4); + + if ((int64_t)str_id == -1) { + errno = EINVAL; + return (uint64_t)-1; + } + + if (str_id == 0 && str == NULL) { + errno = EINVAL; + return (uint64_t)-1; + } + + return __kdebug_trace_string(debugid, str_id, str); +} + +static int +kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) +{ + if (KDBG_EXTRACT_CSC(debugid) != 0) { + errno = EINVAL; + return -1; + } + + debugid |= APPSDBG_CODE(DBG_APP_SIGNPOST, 0); + + return kdebug_trace(debugid, arg1, arg2, arg3, arg4); +} + +int +kdebug_signpost(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) +{ + return kdebug_signpost_internal(code << KDBG_CODE_OFFSET, arg1, arg2, arg3, arg4); +} + +int +kdebug_signpost_start(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) +{ + return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_START, arg1, arg2, arg3, arg4); +} + +int +kdebug_signpost_end(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) +{ + return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_END, arg1, arg2, arg3, arg4); }