aboutsummaryrefslogtreecommitdiff
path: root/lib/darwin/stop-other-threads.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/darwin/stop-other-threads.c')
-rw-r--r--lib/darwin/stop-other-threads.c163
1 files changed, 0 insertions, 163 deletions
diff --git a/lib/darwin/stop-other-threads.c b/lib/darwin/stop-other-threads.c
deleted file mode 100644
index ff239f3..0000000
--- a/lib/darwin/stop-other-threads.c
+++ /dev/null
@@ -1,163 +0,0 @@
-#include "substitute.h"
-#include "substitute-internal.h"
-#include "darwin/mach-decls.h"
-#include "stop-other-threads.h"
-#include "cbit/htab.h"
-#include <pthread.h>
-#include <mach/mach.h>
-
-#define port_hash(portp) (*(portp))
-#define port_eq(port1p, port2p) (*(port1p) == *(port2p))
-#define port_null(portp) (*(portp) == MACH_PORT_NULL)
-DECL_STATIC_HTAB_KEY(mach_port_t, mach_port_t, port_hash, port_eq, port_null, 0);
-struct empty {};
-DECL_HTAB(mach_port_set, mach_port_t, struct empty);
-
-static bool apply_one_pcp(mach_port_t thread,
- uintptr_t (*callback)(void *ctx, uintptr_t pc),
- void *ctx) {
- int flavor;
-#if defined(__x86_64__)
- struct _x86_thread_state_64 state;
- flavor = _x86_thread_state_64_flavor;
-#elif defined(__i386__)
- struct _x86_thread_state_32 state;
- flavor = _x86_thread_state_32_flavor;
-#elif defined(__arm__)
- struct _arm_thread_state_32 state;
- flavor = _arm_thread_state_32_flavor;
-#elif defined(__arm64__)
- struct _arm_thread_state_64 state;
- flavor = _arm_thread_state_64_flavor;
-#else
- #error ?
-#endif
-
- mach_msg_type_number_t real_cnt = sizeof(state) / sizeof(int);
- mach_msg_type_number_t cnt = real_cnt;
- kern_return_t kr = thread_get_state(thread, flavor, (thread_state_t) &state, &cnt);
- if (kr || cnt != real_cnt)
- return false;
-
- uintptr_t *pcp;
-#if defined(__x86_64__)
- pcp = (uintptr_t *) &state.rip;
-#elif defined(__i386__)
- pcp = (uintptr_t *) &state.eip;
-#elif defined(__arm__) || defined(__arm64__)
- pcp = (uintptr_t *) &state.pc;
-#endif
- uintptr_t old = *pcp;
-#ifdef __arm__
- /* thumb */
- if (state.cpsr & 0x20)
- old |= 1;
-#endif
- uintptr_t new = callback(ctx, *pcp);
- if (new != old) {
- *pcp = new;
-#ifdef __arm__
- *pcp &= ~1;
- state.cpsr = (state.cpsr & ~0x20) | ((new & 1) * 0x20);
-#endif
- kr = thread_set_state(thread, flavor, (thread_state_t) &state, real_cnt);
- if (kr)
- return false;
- }
- return true;
-}
-
-int stop_other_threads(void **token_ptr) {
- if (!pthread_main_np())
- return SUBSTITUTE_ERR_NOT_ON_MAIN_THREAD;
-
- int ret;
- mach_port_t self = mach_thread_self();
-
- /* The following shenanigans are for catching any new threads that are
- * created while we're looping, without suspending anything twice. Keep
- * looping until only threads we already suspended before this loop are
- * there. */
- HTAB_STORAGE(mach_port_set) *hs = malloc(sizeof(*hs));
- HTAB_STORAGE_INIT(hs, mach_port_set);
- struct htab_mach_port_set *suspended_set = &hs->h;
-
- thread_act_array_t ports = 0;
- mach_msg_type_number_t nports = 0;
-
- bool got_new = true;
- while (got_new) {
- got_new = false;
-
- kern_return_t kr = task_threads(mach_task_self(), &ports, &nports);
- if (kr) { /* ouch */
- ret = SUBSTITUTE_ERR_ADJUSTING_THREADS;
- goto fail;
- }
-
- for (mach_msg_type_number_t i = 0; i < nports; i++) {
- mach_port_t port = ports[i];
- struct htab_bucket_mach_port_set *bucket;
- if (port == self ||
- (bucket = htab_setbucket_mach_port_set(suspended_set, &port),
- bucket->key)) {
- /* already suspended, ignore */
- mach_port_deallocate(mach_task_self(), port);
- } else {
- got_new = true;
- kr = thread_suspend(port);
- if (kr == KERN_TERMINATED) {
- /* too late */
- mach_port_deallocate(mach_task_self(), port);
- } else if (kr) {
- ret = SUBSTITUTE_ERR_ADJUSTING_THREADS;
- for (; i < nports; i++)
- mach_port_deallocate(mach_task_self(), ports[i]);
- vm_deallocate(mach_task_self(), (vm_address_t) ports,
- nports * sizeof(*ports));
- goto fail;
- }
- bucket->key = port;
- }
- }
- vm_deallocate(mach_task_self(), (vm_address_t) ports,
- nports * sizeof(*ports));
- }
-
- /* Success - keep the set around for when we're done. */
- *token_ptr = suspended_set;
- return SUBSTITUTE_OK;
-
-fail:
- resume_other_threads(suspended_set);
- return ret;
-}
-
-int apply_pc_patch_callback(void *token,
- uintptr_t (*pc_patch_callback)(void *ctx, uintptr_t pc),
- void *ctx) {
- struct htab_mach_port_set *suspended_set = token;
- int ret = SUBSTITUTE_OK;
- HTAB_FOREACH(suspended_set, mach_port_t *threadp,
- UNUSED struct empty *_,
- mach_port_set) {
- if (!apply_one_pcp(*threadp, pc_patch_callback, ctx)) {
- ret = SUBSTITUTE_ERR_ADJUSTING_THREADS;
- break;
- }
- }
- return ret;
-}
-
-int resume_other_threads(void *token) {
- struct htab_mach_port_set *suspended_set = token;
- HTAB_FOREACH(suspended_set, mach_port_t *threadp,
- UNUSED struct empty *_,
- mach_port_set) {
- thread_resume(*threadp);
- mach_port_deallocate(mach_task_self(), *threadp);
- }
- htab_free_storage_mach_port_set(suspended_set);
- free(suspended_set);
- return SUBSTITUTE_OK; /* eh */
-}