X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..eee3565979933af707c711411001ba11fe406a3c:/libsyscall/wrappers/kdebug_trace.c?ds=inline diff --git a/libsyscall/wrappers/kdebug_trace.c b/libsyscall/wrappers/kdebug_trace.c index 02f074cab..8234f4582 100644 --- a/libsyscall/wrappers/kdebug_trace.c +++ b/libsyscall/wrappers/kdebug_trace.c @@ -22,73 +22,115 @@ */ #include +#include #include +#include #include #include +#include #include +#include +#include +#include +#include +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); + uint64_t arg3, uint64_t arg4); extern uint64_t __kdebug_trace_string(uint32_t debugid, uint64_t str_id, - const char *str); + const char *str); -/* Returns non-zero if tracing is enabled. */ -static int -kdebug_enabled(void) -{ - volatile uint32_t *kdebug_enable_address = - (volatile uint32_t *)(uintptr_t)(_COMM_PAGE_KDEBUG_ENABLE); +static int kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, + uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); - if (*kdebug_enable_address == 0) { - return 0; +/* + * 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. + */ + +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 1; + return typefilter; } -static int -kdebug_validate_debugid(uint32_t debugid) +bool +kdebug_is_enabled(uint32_t debugid) { - uint8_t debugid_class; - - /* - * 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. - */ - debugid_class = KDBG_EXTRACT_CLASS(debugid); - switch (debugid_class) { - case DBG_TRACE: - return EPERM; + 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 0; + return TRUE; } int kdebug_trace(uint32_t debugid, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { - int err; - - if (!kdebug_enabled()) { + if (!kdebug_is_enabled(debugid)) { return 0; } - if ((err = kdebug_validate_debugid(debugid)) != 0) { - errno = err; - return -1; - } - return __kdebug_trace64(debugid, arg1, arg2, arg3, arg4); } uint64_t kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str) { - int err; - - if (!kdebug_enabled()) { + if (!kdebug_is_enabled(debugid)) { return 0; } @@ -102,10 +144,36 @@ kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str) return (uint64_t)-1; } - if ((err = kdebug_validate_debugid(debugid)) != 0) { - errno = err; - 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; } - return __kdebug_trace_string(debugid, str_id, str); + 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); }