diff --git a/librz/debug/meson.build b/librz/debug/meson.build index c408d3109e..3cc463ffb4 100644 --- a/librz/debug/meson.build +++ b/librz/debug/meson.build @@ -93,8 +93,8 @@ if has_debugger 'p/native/xnu/xnu_debug.c', #'p/native/xnu/trap_arm.c', #'p/native/xnu/trap_x86.c', - #'p/native/xnu/xnu_excthreads.c', - #'p/native/xnu/xnu_threads.c', + 'p/native/xnu/xnu_excthreads.c', + 'p/native/xnu/xnu_threads.c', ] endif diff --git a/librz/debug/p/native/xnu/xnu_debug.c b/librz/debug/p/native/xnu/xnu_debug.c index 126e1185ac..7cfa5029ca 100644 --- a/librz/debug/p/native/xnu/xnu_debug.c +++ b/librz/debug/p/native/xnu/xnu_debug.c @@ -2,10 +2,6 @@ // SPDX-FileCopyrightText: 2015-2019 alvaro_fe // SPDX-License-Identifier: LGPL-3.0-only -#include - -// ------------------------------------ - #include #include #include @@ -21,8 +17,7 @@ static task_t task_dbg = 0; #include "xnu_debug.h" -#include "xnu_threads.c" -#include "xnu_excthreads.c" +#include "xnu_threads.h" extern int proc_regionfilename(int pid, uint64_t address, void *buffer, uint32_t buffersize); @@ -59,50 +54,6 @@ typedef struct { ut64 image_file_mod_date; } DyldImageInfo64; -/* XXX: right now it just returns the first thread, not the one selected in dbg->tid */ -static thread_t getcurthread(RzDebug *dbg) { - thread_t th; - thread_array_t threads = NULL; - unsigned int n_threads = 0; - task_t t = pid_to_task(dbg->pid); - if (!t) { - return -1; - } - if (task_threads(t, &threads, &n_threads) != KERN_SUCCESS) { - return -1; - } - if (n_threads > 0) { - memcpy(&th, threads, sizeof(th)); - } else { - th = -1; - } - vm_deallocate(t, (vm_address_t)threads, n_threads * sizeof(thread_act_t)); - return th; -} - -static xnu_thread_t *get_xnu_thread(RzDebug *dbg, int tid) { - if (!dbg || tid < 0) { - return NULL; - } - if (!xnu_update_thread_list(dbg)) { - eprintf("Failed to update thread_list xnu_udpate_thread_list\n"); - return NULL; - } - // TODO get the current thread - RzListIter *it = rz_list_find(dbg->threads, (const void *)(size_t)&tid, - (RzListComparator)&thread_find); - if (!it) { - tid = getcurthread(dbg); - it = rz_list_find(dbg->threads, (const void *)(size_t)&tid, - (RzListComparator)&thread_find); - if (!it) { - eprintf("Thread not found get_xnu_thread\n"); - return NULL; - } - } - return (xnu_thread_t *)it->data; -} - static task_t task_for_pid_workaround(int Pid) { host_t myhost = mach_host_self(); mach_port_t psDefault = 0; @@ -154,10 +105,6 @@ static task_t task_for_pid_ios9pangu(int pid) { return task; } -int xnu_wait(RzDebug *dbg, int pid) { - return __xnu_wait(dbg, pid); -} - bool xnu_step(RzDebug *dbg) { // we must find a way to get the current thread not just the first one task_t task = pid_to_task(dbg->pid); @@ -165,11 +112,11 @@ bool xnu_step(RzDebug *dbg) { eprintf("step failed on task %d for pid %d\n", task, dbg->tid); return false; } - xnu_thread_t *th = get_xnu_thread(dbg, getcurthread(dbg)); + xnu_thread_t *th = rz_xnu_get_thread(dbg, rz_xnu_get_cur_thread(dbg)); if (!th) { return false; } - int ret = set_trace_bit(dbg, th); + int ret = xnu_set_trace_bit(dbg, th); if (!ret) { eprintf("xnu_step modificy_trace_bit error\n"); return false; @@ -257,14 +204,14 @@ int xnu_continue(RzDebug *dbg, int pid, int tid, int sig) { return false; } // TODO free refs count threads - xnu_thread_t *th = get_xnu_thread(dbg, getcurthread(dbg)); + xnu_thread_t *th = rz_xnu_get_thread(dbg, rz_xnu_get_cur_thread(dbg)); if (!th) { eprintf("failed to get thread in xnu_continue\n"); return false; } // disable trace bit if enable if (th->stepping) { - if (!clear_trace_bit(dbg, th)) { + if (!xnu_clear_trace_bit(dbg, th)) { eprintf("error clearing trace bit in xnu_continue\n"); return false; } @@ -305,7 +252,7 @@ char *xnu_reg_profile(RzDebug *dbg) { // is not implemented yet i don't care so much int xnu_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) { bool ret; - xnu_thread_t *th = get_xnu_thread(dbg, getcurthread(dbg)); + xnu_thread_t *th = rz_xnu_get_thread(dbg, rz_xnu_get_cur_thread(dbg)); if (!th) { return 0; } @@ -324,7 +271,7 @@ int xnu_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) { #elif __arm || __armv7 || __arm__ || __armv7__ memcpy(&th->debug.drx, buf, RZ_MIN(size, sizeof(th->debug.drx))); #endif - ret = xnu_thread_set_drx(dbg, th); + ret = rz_xnu_thread_set_drx(dbg, th); break; default: // th->gpr has a header and the state we should copy on the state only @@ -333,14 +280,14 @@ int xnu_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) { #else memcpy(&th->gpr.uts, buf, RZ_MIN(size, sizeof(th->gpr.uts))); #endif - ret = xnu_thread_set_gpr(dbg, th); + ret = rz_xnu_thread_set_gpr(dbg, th); break; } return ret; } int xnu_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) { - xnu_thread_t *th = get_xnu_thread(dbg, getcurthread(dbg)); + xnu_thread_t *th = rz_xnu_get_thread(dbg, rz_xnu_get_cur_thread(dbg)); if (!th) { return 0; } @@ -348,12 +295,12 @@ int xnu_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) { case RZ_REG_TYPE_SEG: case RZ_REG_TYPE_FLG: case RZ_REG_TYPE_GPR: - if (!xnu_thread_get_gpr(dbg, th)) { + if (!rz_xnu_thread_get_gpr(dbg, th)) { return 0; } break; case RZ_REG_TYPE_DRX: - if (!xnu_thread_get_drx(dbg, th)) { + if (!rz_xnu_thread_get_drx(dbg, th)) { return 0; } break; @@ -373,7 +320,7 @@ int xnu_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) { RzDebugMap *xnu_map_alloc(RzDebug *dbg, ut64 addr, int size) { kern_return_t ret; ut8 *base = (ut8 *)addr; - xnu_thread_t *th = get_xnu_thread(dbg, dbg->tid); + xnu_thread_t *th = rz_xnu_get_thread(dbg, dbg->tid); bool anywhere = !VM_FLAGS_ANYWHERE; if (!th) { return NULL; @@ -393,7 +340,7 @@ RzDebugMap *xnu_map_alloc(RzDebug *dbg, ut64 addr, int size) { } int xnu_map_dealloc(RzDebug *dbg, ut64 addr, int size) { - xnu_thread_t *th = get_xnu_thread(dbg, dbg->tid); + xnu_thread_t *th = rz_xnu_get_thread(dbg, dbg->tid); if (!th) { return false; } @@ -488,10 +435,10 @@ RzList *xnu_thread_list(RzDebug *dbg, int pid, RzList *list) { RzListIter *iter; xnu_thread_t *thread; RZ_REG_T state; - xnu_update_thread_list(dbg); + rz_xnu_update_thread_list(dbg); list->free = (RzListFree)&rz_debug_pid_free; rz_list_foreach (dbg->threads, iter, thread) { - if (!xnu_thread_get_gpr(dbg, thread)) { + if (!rz_xnu_thread_get_gpr(dbg, thread)) { eprintf("Failed to get gpr registers xnu_thread_list\n"); continue; } diff --git a/librz/debug/p/native/xnu/xnu_debug.h b/librz/debug/p/native/xnu/xnu_debug.h index be82c1e3d6..4d00833182 100644 --- a/librz/debug/p/native/xnu/xnu_debug.h +++ b/librz/debug/p/native/xnu/xnu_debug.h @@ -12,6 +12,7 @@ #define _XNU_DEBUG_H #include +#include #define LOG_MACH_ERROR(name, rc) \ do { \ @@ -282,7 +283,7 @@ RzDebugMap *xnu_map_alloc(RzDebug *dbg, ut64 addr, int size); int xnu_map_dealloc(RzDebug *dbg, ut64 addr, int size); int xnu_map_protect(RzDebug *dbg, ut64 addr, int size, int perms); int xnu_init(void); -int xnu_wait(RzDebug *dbg, int pid); +RZ_IPI int xnu_wait(RzDebug *dbg, int pid); RzDebugPid *xnu_get_pid(int pid); RzList *xnu_dbg_maps(RzDebug *dbg, int only_modules); RzList *xnu_thread_list(RzDebug *dbg, int pid, RzList *list); diff --git a/librz/debug/p/native/xnu/xnu_excthreads.c b/librz/debug/p/native/xnu/xnu_excthreads.c index edb20121b5..0fda1836c8 100644 --- a/librz/debug/p/native/xnu/xnu_excthreads.c +++ b/librz/debug/p/native/xnu/xnu_excthreads.c @@ -1,13 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Florian Märkl // SPDX-FileCopyrightText: 2015 alvarofe // SPDX-License-Identifier: LGPL-3.0-only // FIXME deallocate all the port when they are not longer needed +#include "xnu_debug.h" #include "xnu_threads.h" -#define set_trace_bit(dbg, thread) modify_trace_bit(dbg, thread, 1) -#define clear_trace_bit(dbg, thread) modify_trace_bit(dbg, thread, 0) - #if defined __i386__ || __x86_64__ // intel processors /* Set/clear bit 8 (Trap Flag) of the EFLAGS processor control @@ -15,10 +14,10 @@ ENABLE is a boolean, indicating whether to set (1) the Trap Flag or clear it (0). */ -static bool modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { +RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { RZ_REG_T *state; int ret; - ret = xnu_thread_get_gpr(dbg, th); + ret = rz_xnu_thread_get_gpr(dbg, th); if (!ret) { eprintf("error to get gpr registers in trace bit intel\n"); return false; @@ -36,7 +35,7 @@ static bool modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { eprintf("Invalid bit size\n"); return false; } - if (!xnu_thread_set_gpr(dbg, th)) { + if (!rz_xnu_thread_set_gpr(dbg, th)) { eprintf("error xnu_thread_set_gpr in modify_trace_bit intel\n"); return false; } @@ -46,11 +45,11 @@ static bool modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { #elif __POWERPC__ // ppc processor // XXX poor support at this stage i don't care so much. Once intel and arm done it could be done // TODO add better support for ppc -static bool modify_trace_bit(RzDebug *dbg, void *th, int enable) { +RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, void *th, int enable) { return false; } #if 0 -static bool modify_trace_bit(RzDebug *dbg, xnu_thread *th, int enable) { +static bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread *th, int enable) { return false; RZ_REG_T state; unsigned int state_count = RZ_REG_STATE_SZ; @@ -115,8 +114,8 @@ static bool is_thumb_32(ut16 op) { } #endif -static int modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { - int ret = xnu_thread_get_drx(dbg, th); +RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { + int ret = rz_xnu_thread_get_drx(dbg, th); if (!ret) { eprintf("error to get drx registers modificy_trace_bit arm\n"); return false; @@ -142,7 +141,7 @@ static int modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { int i = 0; arm_debug_state_t *state = &th->debug.drx; RZ_REG_T *regs; - ret = xnu_thread_get_gpr(dbg, th); + ret = rz_xnu_thread_get_gpr(dbg, th); if (!ret) { eprintf("error to get gpr register modificy_trace_bit arm\n"); return false; @@ -205,7 +204,7 @@ static int modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) { return false; } // set state - if (!xnu_thread_set_drx(dbg, th)) { + if (!rz_xnu_thread_set_drx(dbg, th)) { eprintf("error to set drx modificy_trace_bit arm\n"); return false; } @@ -224,7 +223,7 @@ static int modify_trace_bit(RzDebug *dbg, xnu_thread *th, int enable) { // TODO: Tuck this into RzDebug; `void *user` seems like a good candidate. static xnu_exception_info ex = { { 0 } }; -static bool xnu_restore_exception_ports(int pid) { +RZ_IPI bool xnu_restore_exception_ports(int pid) { kern_return_t kr; int i; task_t task = pid_to_task(pid); @@ -375,7 +374,7 @@ static int handle_exception_message(RzDebug *dbg, exc_msg *msg, int *ret_code) { } // TODO improve this code -static int __xnu_wait(RzDebug *dbg, int pid) { +RZ_IPI int xnu_wait(RzDebug *dbg, int pid) { // here comes the important thing kern_return_t kr; int ret_code, reason = RZ_DEBUG_REASON_UNKNOWN; @@ -440,7 +439,7 @@ static int __xnu_wait(RzDebug *dbg, int pid) { return reason; } -bool xnu_create_exception_thread(RzDebug *dbg) { +RZ_IPI bool xnu_create_exception_thread(RzDebug *dbg) { #if __POWERPC__ return false; #else diff --git a/librz/debug/p/native/xnu/xnu_threads.c b/librz/debug/p/native/xnu/xnu_threads.c index 11b5d8c9a0..fec58991ce 100644 --- a/librz/debug/p/native/xnu/xnu_threads.c +++ b/librz/debug/p/native/xnu/xnu_threads.c @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2009-2019 pancake // SPDX-License-Identifier: LGPL-3.0-only -#include +#include // TODO much work remains to be done #include "xnu_debug.h" @@ -23,7 +23,7 @@ static void xnu_thread_free(xnu_thread_t *thread) { } // XXX this should work as long as in arm trace bit relies on this -static bool xnu_thread_get_drx(RzDebug *dbg, xnu_thread_t *thread) { +RZ_IPI bool rz_xnu_thread_get_drx(RzDebug *dbg, xnu_thread_t *thread) { rz_return_val_if_fail(dbg && thread, false); kern_return_t rc; #if __x86_64__ || __i386__ @@ -67,7 +67,7 @@ static bool xnu_thread_get_drx(RzDebug *dbg, xnu_thread_t *thread) { return true; } -static bool xnu_thread_set_drx(RzDebug *dbg, xnu_thread_t *thread) { +RZ_IPI bool rz_xnu_thread_set_drx(RzDebug *dbg, xnu_thread_t *thread) { rz_return_val_if_fail(dbg && thread, false); kern_return_t rc; #if __i386__ || __x86_64__ @@ -127,7 +127,7 @@ static bool xnu_thread_set_drx(RzDebug *dbg, xnu_thread_t *thread) { return true; } -static bool xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread) { +RZ_IPI bool rz_xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread) { rz_return_val_if_fail(dbg && thread, false); kern_return_t rc; RZ_REG_T *regs = (RZ_REG_T *)&thread->gpr; @@ -181,7 +181,7 @@ static bool xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread) { return true; } -static bool xnu_thread_get_gpr(RzDebug *dbg, xnu_thread_t *thread) { +RZ_IPI bool rz_xnu_thread_get_gpr(RzDebug *dbg, xnu_thread_t *thread) { rz_return_val_if_fail(dbg && thread, false); RZ_REG_T *regs = &thread->gpr; if (!regs) { @@ -287,7 +287,7 @@ static int thread_find(thread_t *port, xnu_thread_t *a) { return (a && port && (a->port == *port)) ? 0 : 1; } -static int xnu_update_thread_list(RzDebug *dbg) { +RZ_IPI int rz_xnu_update_thread_list(RzDebug *dbg) { thread_array_t thread_list = NULL; unsigned int thread_count = 0; xnu_thread_t *thread; @@ -374,3 +374,47 @@ static int xnu_update_thread_list(RzDebug *dbg) { thread_count * sizeof(thread_t)); return true; } + +RZ_IPI xnu_thread_t *rz_xnu_get_thread(RzDebug *dbg, int tid) { + if (!dbg || tid < 0) { + return NULL; + } + if (!rz_xnu_update_thread_list(dbg)) { + eprintf("Failed to update thread_list xnu_udpate_thread_list\n"); + return NULL; + } + // TODO get the current thread + RzListIter *it = rz_list_find(dbg->threads, (const void *)(size_t)&tid, + (RzListComparator)&thread_find); + if (!it) { + tid = rz_xnu_get_cur_thread(dbg); + it = rz_list_find(dbg->threads, (const void *)(size_t)&tid, + (RzListComparator)&thread_find); + if (!it) { + eprintf("Thread not found get_xnu_thread\n"); + return NULL; + } + } + return (xnu_thread_t *)it->data; +} + +/* XXX: right now it just returns the first thread, not the one selected in dbg->tid */ +RZ_IPI thread_t rz_xnu_get_cur_thread(RzDebug *dbg) { + thread_t th; + thread_array_t threads = NULL; + unsigned int n_threads = 0; + task_t t = pid_to_task(dbg->pid); + if (!t) { + return -1; + } + if (task_threads(t, &threads, &n_threads) != KERN_SUCCESS) { + return -1; + } + if (n_threads > 0) { + memcpy(&th, threads, sizeof(th)); + } else { + th = -1; + } + vm_deallocate(t, (vm_address_t)threads, n_threads * sizeof(thread_act_t)); + return th; +} diff --git a/librz/debug/p/native/xnu/xnu_threads.h b/librz/debug/p/native/xnu/xnu_threads.h index 39f315489d..fa5a964d7f 100644 --- a/librz/debug/p/native/xnu/xnu_threads.h +++ b/librz/debug/p/native/xnu/xnu_threads.h @@ -4,6 +4,9 @@ #ifndef _INCLUDE_XNU_THREADS_H_ #define _INCLUDE_XNU_THREADS_H_ +#include +#include + #if __POWERPC__ // TODO add better support for PPC #define RZ_REG_T ppc_thread_state_t @@ -91,4 +94,23 @@ typedef struct _rep_msg { kern_return_t ret_code; } rep_msg; +RZ_IPI int rz_xnu_update_thread_list(RzDebug *dbg); +RZ_IPI xnu_thread_t *rz_xnu_get_thread(RzDebug *dbg, int tid); +RZ_IPI thread_t rz_xnu_get_cur_thread(RzDebug *dbg); +RZ_IPI bool rz_xnu_thread_set_drx(RzDebug *dbg, xnu_thread_t *thread); +RZ_IPI bool rz_xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread); +RZ_IPI bool rz_xnu_thread_get_gpr(RzDebug *dbg, xnu_thread_t *thread); +RZ_IPI bool rz_xnu_thread_get_drx(RzDebug *dbg, xnu_thread_t *thread); + +RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable); +static inline bool xnu_set_trace_bit(RzDebug *dbg, xnu_thread_t *th) { + return xnu_modify_trace_bit(dbg, th, 1); +} +static inline bool xnu_clear_trace_bit(RzDebug *dbg, xnu_thread_t *th) { + return xnu_modify_trace_bit(dbg, th, 0); +} + +RZ_IPI bool xnu_create_exception_thread(RzDebug *dbg); +RZ_IPI bool xnu_restore_exception_ports(int pid); + #endif