diff --git a/gum/backend-arm/gumstalker-arm.c b/gum/backend-arm/gumstalker-arm.c index 1519a36777..dd6875b15e 100644 --- a/gum/backend-arm/gumstalker-arm.c +++ b/gum/backend-arm/gumstalker-arm.c @@ -1602,6 +1602,7 @@ _gum_stalker_modify_to_run_on_thread (GumStalker * self, GumAddress cpu_context_copy, infect_body; ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL); + if ((cpu_context->cpsr & GUM_PSR_T_BIT) == 0) pc = cpu_context->pc; else diff --git a/gum/backend-arm64/gumstalker-arm64.c b/gum/backend-arm64/gumstalker-arm64.c index 278c168285..a0c79c61f1 100644 --- a/gum/backend-arm64/gumstalker-arm64.c +++ b/gum/backend-arm64/gumstalker-arm64.c @@ -20,6 +20,7 @@ #include "gummemory.h" #include "gummetalhash.h" #include "gumspinlock.h" +#include "gumstalker-priv.h" #ifdef HAVE_LINUX # include "gum-init.h" # include "guminterceptor.h" @@ -88,7 +89,6 @@ typedef struct _GumBackpatchCall GumBackpatchCall; typedef struct _GumBackpatchJmp GumBackpatchJmp; typedef struct _GumBackpatchInlineCache GumBackpatchInlineCache; typedef struct _GumBackpatchExcludedCall GumBackpatchExcludedCall; -typedef struct _GumStalkerRunOnThreadCtx GumStalkerRunOnThreadCtx; #ifdef HAVE_LINUX typedef struct _Unwind_Exception _Unwind_Exception; @@ -482,13 +482,6 @@ struct _GumBackpatch }; }; -struct _GumStalkerRunOnThreadCtx -{ - GumStalker * stalker; - GumStalkerRunOnThreadFunc func; - gpointer user_data; -}; - #ifdef HAVE_LINUX extern _Unwind_Reason_Code __gxx_personality_v0 (int version, @@ -771,9 +764,6 @@ static gpointer gum_find_thread_exit_implementation (void); static gboolean gum_is_bl_imm (guint32 insn) G_GNUC_UNUSED; -static void gum_stalker_do_run_on_thread (GumThreadId thread_id, - GumCpuContext * cpu_context, gpointer user_data); - G_DEFINE_TYPE (GumStalker, gum_stalker, G_TYPE_OBJECT) static GPrivate gum_stalker_exec_ctx_private; @@ -1939,6 +1929,74 @@ gum_call_probe_unref (GumCallProbe * probe) } } +void +_gum_stalker_modify_to_run_on_thread (GumStalker * self, + GumThreadId thread_id, + GumCpuContext * cpu_context, + GumStalkerRunOnThreadFunc func, + gpointer data) +{ + GumExecCtx * ctx; + GumAddress pc; + GumArm64Writer * cw; + GumAddress cpu_context_copy; + + ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL); + + pc = gum_strip_code_address (cpu_context->pc); + + gum_spinlock_acquire (&ctx->code_lock); + + gum_stalker_thaw (self, ctx->thunks, self->thunks_size); + cw = &ctx->code_writer; + gum_arm64_writer_reset (cw, ctx->infect_thunk); + + cpu_context_copy = GUM_ADDRESS (gum_arm64_writer_cur (cw)); + gum_arm64_writer_put_bytes (cw, (guint8 *) cpu_context, + sizeof (GumCpuContext)); + + ctx->infect_body = GUM_ADDRESS (gum_arm64_writer_cur (cw)); + +#ifdef HAVE_PTRAUTH + ctx->infect_body = GPOINTER_TO_SIZE (ptrauth_sign_unauthenticated ( + GSIZE_TO_POINTER (ctx->infect_body), + ptrauth_key_process_independent_code, + ptrauth_string_discriminator ("pc"))); +#endif + gum_exec_ctx_write_prolog (ctx, GUM_PROLOG_MINIMAL, cw); + + gum_arm64_writer_put_call_address_with_arguments (cw, + GUM_ADDRESS (func), 2, + GUM_ARG_ADDRESS, cpu_context_copy, + GUM_ARG_ADDRESS, GUM_ADDRESS (data)); + + gum_arm64_writer_put_call_address_with_arguments (cw, + GUM_ADDRESS (gum_exec_ctx_unfollow), 2, + GUM_ARG_ADDRESS, GUM_ADDRESS (ctx), + GUM_ARG_ADDRESS, pc); + + gum_exec_ctx_write_epilog (ctx, GUM_PROLOG_MINIMAL, cw); + + /* + * Here we spoil x17 since this is a necessity of the AARCH64 architecture + * when performing long branches. However, the documentation states... + * + * "Registers r16 (IP0) and r17 (IP1) may be used by a linker as a scratch + * register between a routine and any subroutine it calls." + * + * This same approach is used elsewhere in Stalker for arm64. + */ + gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X17, pc); + gum_arm64_writer_put_br_reg_no_auth (cw, ARM64_REG_X17); + + gum_arm64_writer_flush (cw); + gum_stalker_freeze (self, cw->base, gum_arm64_writer_offset (cw)); + + gum_spinlock_release (&ctx->code_lock); + + cpu_context->pc = ctx->infect_body; +} + static GumExecCtx * gum_stalker_create_exec_ctx (GumStalker * self, GumThreadId thread_id, @@ -5906,102 +5964,3 @@ gum_is_bl_imm (guint32 insn) } #endif - -gboolean -gum_stalker_run_on_thread (GumStalker * self, - GumThreadId thread_id, - GumStalkerRunOnThreadFunc func, - gpointer user_data) -{ - GumStalkerRunOnThreadCtx ctx; - - if (gum_process_get_current_thread_id () == thread_id) - { - func (NULL, user_data); - return TRUE; - } - else - { - ctx.stalker = self; - ctx.func = func; - ctx.user_data = user_data; - return gum_process_modify_thread (thread_id, gum_stalker_do_run_on_thread, - &ctx, GUM_MODIFY_THREAD_FLAGS_NONE); - } -} - -static void -gum_stalker_do_run_on_thread (GumThreadId thread_id, - GumCpuContext * cpu_context, - gpointer user_data) -{ - GumStalkerRunOnThreadCtx * run_ctx = (GumStalkerRunOnThreadCtx *) user_data; - GumStalker * self = run_ctx->stalker; - GumExecCtx * ctx; - guint8 * pc; - GumArm64Writer * cw; - GumAddress cpu_ctx; - - if (gum_process_get_current_thread_id () == thread_id) - { - run_ctx->func (cpu_context, run_ctx->user_data); - } - else - { - ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL); - - pc = GSIZE_TO_POINTER (gum_strip_code_address (cpu_context->pc)); - - gum_spinlock_acquire (&ctx->code_lock); - - gum_stalker_thaw (self, ctx->thunks, self->thunks_size); - cw = &ctx->code_writer; - gum_arm64_writer_reset (cw, ctx->infect_thunk); - - /* Copy the cpu context for the target thread. */ - cpu_ctx = GUM_ADDRESS (gum_arm64_writer_cur (cw)); - gum_arm64_writer_put_bytes (cw, (gpointer) cpu_context, - sizeof (GumCpuContext)); - - ctx->infect_body = GUM_ADDRESS (gum_arm64_writer_cur (cw)); - -#ifdef HAVE_PTRAUTH - ctx->infect_body = GPOINTER_TO_SIZE (ptrauth_sign_unauthenticated ( - GSIZE_TO_POINTER (ctx->infect_body), - ptrauth_key_process_independent_code, - ptrauth_string_discriminator ("pc"))); -#endif - gum_exec_ctx_write_prolog (ctx, GUM_PROLOG_MINIMAL, cw); - - gum_arm64_writer_put_call_address_with_arguments (cw, - GUM_ADDRESS (run_ctx->func), 2, - GUM_ARG_ADDRESS, GUM_ADDRESS (cpu_ctx), - GUM_ARG_ADDRESS, GUM_ADDRESS (run_ctx->user_data)); - - gum_arm64_writer_put_call_address_with_arguments (cw, - GUM_ADDRESS (gum_exec_ctx_unfollow), 2, - GUM_ARG_ADDRESS, GUM_ADDRESS (ctx), - GUM_ARG_ADDRESS, GUM_ADDRESS (pc)); - - gum_exec_ctx_write_epilog (ctx, GUM_PROLOG_MINIMAL, cw); - - /* - * Here we spoil x17 since this is a necessity of the AARCH64 architecture - * when performing long branches. However, the documentation states... - * - * "Registers r16 (IP0) and r17 (IP1) may be used by a linker as a scratch - * register between a routine and any subroutine it calls." - * - * This same approach is used elsewhere in Stalker for aarch64. - */ - gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X17, GUM_ADDRESS (pc)); - gum_arm64_writer_put_br_reg_no_auth (cw, ARM64_REG_X17); - - gum_arm64_writer_flush (cw); - gum_stalker_freeze (self, cw->base, gum_arm64_writer_offset (cw)); - - gum_spinlock_release (&ctx->code_lock); - - cpu_context->pc = ctx->infect_body; - } -} diff --git a/gum/gumstalker.c b/gum/gumstalker.c index 9dd3ef25cc..ecb107ec90 100644 --- a/gum/gumstalker.c +++ b/gum/gumstalker.c @@ -67,9 +67,6 @@ static void gum_callback_stalker_transformer_transform_block ( static void gum_stalker_observer_default_init ( GumStalkerObserverInterface * iface); -static void gum_stalker_do_run_on_thread_sync ( - const GumCpuContext * cpu_context, gpointer user_data); - G_DEFINE_INTERFACE (GumStalkerTransformer, gum_stalker_transformer, G_TYPE_OBJECT) @@ -209,13 +206,12 @@ gum_stalker_run_on_thread (GumStalker * self, gpointer data, GDestroyNotify data_destroy) { - gboolean done = FALSE; + gboolean accepted = TRUE; + gboolean finished = TRUE; - if (gum_process_get_current_thread_id () == thread_id) + if (thread_id == gum_process_get_current_thread_id ()) { func (NULL, data); - - done = TRUE; } else { @@ -227,16 +223,18 @@ gum_stalker_run_on_thread (GumStalker * self, rc->data = data; rc->data_destroy = data_destroy; - if (!gum_process_modify_thread (thread_id, gum_modify_to_run_on_thread, rc, - GUM_MODIFY_THREAD_FLAGS_NONE)) - { + accepted = gum_process_modify_thread (thread_id, + gum_modify_to_run_on_thread, rc, GUM_MODIFY_THREAD_FLAGS_NONE); + if (accepted) + finished = FALSE; + else g_slice_free (GumRunOnThreadCtx, rc); - done = TRUE; - } } - if (done && data_destroy != NULL) + if (finished && data_destroy != NULL) data_destroy (data); + + return accepted; } static void @@ -269,13 +267,11 @@ gum_stalker_run_on_thread_sync (GumStalker * self, GumStalkerRunOnThreadFunc func, gpointer data) { - gboolean success = FALSE; + gboolean success = TRUE; - if (gum_process_get_current_thread_id () == thread_id) + if (thread_id == gum_process_get_current_thread_id ()) { func (NULL, data); - - success = TRUE; } else { @@ -294,8 +290,10 @@ gum_stalker_run_on_thread_sync (GumStalker * self, { while (!rc.done) g_cond_wait (&rc.cond, &rc.mutex); - - success = TRUE; + } + else + { + success = FALSE; } g_mutex_unlock (&rc.mutex); diff --git a/tests/core/arch-arm/stalker-arm.c b/tests/core/arch-arm/stalker-arm.c index de3da463ad..0a8343c80f 100644 --- a/tests/core/arch-arm/stalker-arm.c +++ b/tests/core/arch-arm/stalker-arm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2023 Ole André Vadla Ravnås + * Copyright (C) 2009-2024 Ole André Vadla Ravnås * Copyright (C) 2017 Antonio Ken Iannillo * Copyright (C) 2023 Håvard Sørbø * @@ -126,6 +126,7 @@ TESTLIST_BEGIN (stalker) #ifdef HAVE_LINUX TESTENTRY (prefetch) #endif + TESTGROUP_BEGIN ("RunOnThread") TESTENTRY (run_on_thread_current) TESTENTRY (run_on_thread_current_sync) @@ -147,9 +148,9 @@ struct _TestThreadSyncData { GMutex mutex; GCond cond; - volatile gboolean started; - volatile GumThreadId thread_id; - volatile gboolean * volatile done; + gboolean started; + GumThreadId thread_id; + gboolean * done; }; static gboolean store_range_of_test_runner (const GumModuleDetails * details, @@ -216,9 +217,10 @@ static void prefetch_read_blocks (int fd, GHashTable * table); static GHashTable * prefetch_compiled = NULL; static GHashTable * prefetch_executed = NULL; #endif + static void run_on_thread (const GumCpuContext * cpu_context, gpointer user_data); -static GThread * create_sleeping_dummy_thread_sync (volatile gboolean * done, +static GThread * create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id); static gpointer sleeping_dummy (gpointer data); @@ -3804,38 +3806,42 @@ prefetch_read_blocks (int fd, TESTCASE (run_on_thread_current) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; - - ctx.caller_id = gum_process_get_current_thread_id (); + gboolean accepted; - success = gum_stalker_run_on_thread (fixture->stalker, thread_id, - run_on_thread, &ctx); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - g_assert_true (success); - g_assert_cmpuint (thread_id, ==, ctx.thread_id); + accepted = gum_stalker_run_on_thread (fixture->stalker, thread_id, + run_on_thread, &ctx, NULL); + g_assert_true (accepted); + g_assert_cmpuint (ctx.thread_id, ==, thread_id); } TESTCASE (run_on_thread_current_sync) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; - - ctx.caller_id = gum_process_get_current_thread_id (); + gboolean accepted; - success = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, - run_on_thread, &ctx); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - g_assert_true (success); + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, + run_on_thread, &ctx); + g_assert_true (accepted); g_assert_cmpuint (thread_id, ==, ctx.thread_id); } static void -run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) +run_on_thread (const GumCpuContext * cpu_context, + gpointer user_data) { - RunOnThreadCtx * ctx = (RunOnThreadCtx *) user_data; + RunOnThreadCtx * ctx = user_data; + g_usleep (250000); ctx->thread_id = gum_process_get_current_thread_id (); @@ -3847,49 +3853,56 @@ run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) TESTCASE (run_on_thread_other) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread (fixture->stalker, other_id, run_on_thread, &ctx); - + accepted = gum_stalker_run_on_thread (fixture->stalker, other_id, + run_on_thread, &ctx, NULL); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmphex (ctx.thread_id, ==, other_id); } TESTCASE (run_on_thread_other_sync) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread_sync (fixture->stalker, other_id, run_on_thread, - &ctx); - + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, other_id, + run_on_thread, &ctx); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmpuint (ctx.thread_id, ==, other_id); } static GThread * -create_sleeping_dummy_thread_sync (volatile gboolean * done, +create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id) { - TestThreadSyncData sync_data; GThread * thread; + TestThreadSyncData sync_data; g_mutex_init (&sync_data.mutex); g_cond_init (&sync_data.cond); @@ -3904,8 +3917,7 @@ create_sleeping_dummy_thread_sync (volatile gboolean * done, while (!sync_data.started) g_cond_wait (&sync_data.cond, &sync_data.mutex); - if (thread_id != NULL) - *thread_id = sync_data.thread_id; + *thread_id = sync_data.thread_id; g_mutex_unlock (&sync_data.mutex); @@ -3919,7 +3931,7 @@ static gpointer sleeping_dummy (gpointer data) { TestThreadSyncData * sync_data = data; - volatile gboolean * done = sync_data->done; + gboolean * done = sync_data->done; g_mutex_lock (&sync_data->mutex); sync_data->started = TRUE; diff --git a/tests/core/arch-arm64/stalker-arm64.c b/tests/core/arch-arm64/stalker-arm64.c index d0acf1c279..e0007557e7 100644 --- a/tests/core/arch-arm64/stalker-arm64.c +++ b/tests/core/arch-arm64/stalker-arm64.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2023 Ole André Vadla Ravnås + * Copyright (C) 2009-2024 Ole André Vadla Ravnås * Copyright (C) 2017 Antonio Ken Iannillo * Copyright (C) 2023 Håvard Sørbø * @@ -80,6 +80,7 @@ TESTLIST_BEGIN (stalker) TESTENTRY (prefetch) TESTENTRY (observer) #endif + TESTGROUP_BEGIN ("RunOnThread") TESTENTRY (run_on_thread_current) TESTENTRY (run_on_thread_current_sync) @@ -88,9 +89,6 @@ TESTLIST_BEGIN (stalker) TESTGROUP_END () TESTLIST_END () -typedef struct _RunOnThreadCtx RunOnThreadCtx; -typedef struct _TestThreadSyncData TestThreadSyncData; - #ifdef HAVE_LINUX struct _GumTestStalkerObserver @@ -102,6 +100,9 @@ struct _GumTestStalkerObserver #endif +typedef struct _RunOnThreadCtx RunOnThreadCtx; +typedef struct _TestThreadSyncData TestThreadSyncData; + struct _RunOnThreadCtx { GumThreadId caller_id; @@ -112,9 +113,9 @@ struct _TestThreadSyncData { GMutex mutex; GCond cond; - volatile gboolean started; - volatile GumThreadId thread_id; - volatile gboolean * volatile done; + gboolean started; + GumThreadId thread_id; + gboolean * done; }; static void insert_extra_add_after_sub (GumStalkerIterator * iterator, @@ -187,9 +188,10 @@ G_DEFINE_TYPE_EXTENDED (GumTestStalkerObserver, G_IMPLEMENT_INTERFACE (GUM_TYPE_STALKER_OBSERVER, gum_test_stalker_observer_iface_init)) #endif + static void run_on_thread (const GumCpuContext * cpu_context, gpointer user_data); -static GThread * create_sleeping_dummy_thread_sync (volatile gboolean * done, +static GThread * create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id); static gpointer sleeping_dummy (gpointer data); @@ -2423,38 +2425,42 @@ gum_test_stalker_observer_increment_total (GumStalkerObserver * observer) TESTCASE (run_on_thread_current) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; + gboolean accepted; - ctx.caller_id = gum_process_get_current_thread_id (); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - success = gum_stalker_run_on_thread (fixture->stalker, thread_id, - run_on_thread, &ctx); - - g_assert_true (success); - g_assert_cmpuint (thread_id, ==, ctx.thread_id); + accepted = gum_stalker_run_on_thread (fixture->stalker, thread_id, + run_on_thread, &ctx, NULL); + g_assert_true (accepted); + g_assert_cmpuint (ctx.thread_id, ==, thread_id); } TESTCASE (run_on_thread_current_sync) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; + gboolean accepted; - ctx.caller_id = gum_process_get_current_thread_id (); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - success = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, run_on_thread, &ctx); - - g_assert_true (success); + g_assert_true (accepted); g_assert_cmpuint (thread_id, ==, ctx.thread_id); } static void -run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) +run_on_thread (const GumCpuContext * cpu_context, + gpointer user_data) { - RunOnThreadCtx * ctx = (RunOnThreadCtx *) user_data; + RunOnThreadCtx * ctx = user_data; + g_usleep (250000); ctx->thread_id = gum_process_get_current_thread_id (); @@ -2466,49 +2472,56 @@ run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) TESTCASE (run_on_thread_other) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread (fixture->stalker, other_id, run_on_thread, &ctx); - + accepted = gum_stalker_run_on_thread (fixture->stalker, other_id, + run_on_thread, &ctx, NULL); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmphex (ctx.thread_id, ==, other_id); } TESTCASE (run_on_thread_other_sync) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread_sync (fixture->stalker, other_id, run_on_thread, - &ctx); - + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, other_id, + run_on_thread, &ctx); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmpuint (ctx.thread_id, ==, other_id); } static GThread * -create_sleeping_dummy_thread_sync (volatile gboolean * done, +create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id) { - TestThreadSyncData sync_data; GThread * thread; + TestThreadSyncData sync_data; g_mutex_init (&sync_data.mutex); g_cond_init (&sync_data.cond); @@ -2523,8 +2536,7 @@ create_sleeping_dummy_thread_sync (volatile gboolean * done, while (!sync_data.started) g_cond_wait (&sync_data.cond, &sync_data.mutex); - if (thread_id != NULL) - *thread_id = sync_data.thread_id; + *thread_id = sync_data.thread_id; g_mutex_unlock (&sync_data.mutex); @@ -2538,7 +2550,7 @@ static gpointer sleeping_dummy (gpointer data) { TestThreadSyncData * sync_data = data; - volatile gboolean * done = sync_data->done; + gboolean * done = sync_data->done; g_mutex_lock (&sync_data->mutex); sync_data->started = TRUE; diff --git a/tests/core/arch-x86/stalker-x86.c b/tests/core/arch-x86/stalker-x86.c index 50a1169425..683afaca62 100644 --- a/tests/core/arch-x86/stalker-x86.c +++ b/tests/core/arch-x86/stalker-x86.c @@ -120,6 +120,7 @@ TESTLIST_BEGIN (stalker) TESTENTRY (try_and_dont_catch_excluded) TESTGROUP_END () #endif + TESTGROUP_BEGIN ("RunOnThread") TESTENTRY (run_on_thread_current) TESTENTRY (run_on_thread_current_sync) @@ -169,9 +170,9 @@ struct _TestThreadSyncData { GMutex mutex; GCond cond; - volatile gboolean started; - volatile GumThreadId thread_id; - volatile gboolean * volatile done; + gboolean started; + GumThreadId thread_id; + gboolean * done; }; static gpointer run_stalked_briefly (gpointer data); @@ -262,9 +263,10 @@ void test_check_bit (guint32 * val, guint8 bit); void test_try_and_catch (guint32 * val); void test_try_and_dont_catch (guint32 * val); #endif + static void run_on_thread (const GumCpuContext * cpu_context, gpointer user_data); -static GThread * create_sleeping_dummy_thread_sync (volatile gboolean * done, +static GThread * create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id); static gpointer sleeping_dummy (gpointer data); @@ -3514,38 +3516,42 @@ test_check_followed (void) TESTCASE (run_on_thread_current) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; + gboolean accepted; - ctx.caller_id = gum_process_get_current_thread_id (); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - success = gum_stalker_run_on_thread (fixture->stalker, thread_id, + accepted = gum_stalker_run_on_thread (fixture->stalker, thread_id, run_on_thread, &ctx, NULL); - - g_assert_true (success); - g_assert_cmpuint (thread_id, ==, ctx.thread_id); + g_assert_true (accepted); + g_assert_cmpuint (ctx.thread_id, ==, thread_id); } TESTCASE (run_on_thread_current_sync) { - GumThreadId thread_id = gum_process_get_current_thread_id (); + GumThreadId thread_id; RunOnThreadCtx ctx; - gboolean success; + gboolean accepted; - ctx.caller_id = gum_process_get_current_thread_id (); + thread_id = gum_process_get_current_thread_id (); + ctx.caller_id = thread_id; + ctx.thread_id = G_MAXSIZE; - success = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, thread_id, run_on_thread, &ctx); - - g_assert_true (success); + g_assert_true (accepted); g_assert_cmpuint (thread_id, ==, ctx.thread_id); } static void -run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) +run_on_thread (const GumCpuContext * cpu_context, + gpointer user_data) { - RunOnThreadCtx * ctx = (RunOnThreadCtx *) user_data; + RunOnThreadCtx * ctx = user_data; + g_usleep (250000); ctx->thread_id = gum_process_get_current_thread_id (); @@ -3557,50 +3563,56 @@ run_on_thread (const GumCpuContext * cpu_context, gpointer user_data) TESTCASE (run_on_thread_other) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread (fixture->stalker, other_id, run_on_thread, &ctx, - NULL); - + accepted = gum_stalker_run_on_thread (fixture->stalker, other_id, + run_on_thread, &ctx, NULL); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmphex (ctx.thread_id, ==, other_id); } TESTCASE (run_on_thread_other_sync) { - GumThreadId this_id, other_id; - volatile gboolean done = FALSE; GThread * thread; + gboolean done = FALSE; + GumThreadId other_id, this_id; RunOnThreadCtx ctx; + gboolean accepted; + + thread = create_sleeping_dummy_thread_sync (&done, &other_id); this_id = gum_process_get_current_thread_id (); + g_assert_cmphex (this_id, !=, other_id); ctx.caller_id = this_id; + ctx.thread_id = G_MAXSIZE; - thread = create_sleeping_dummy_thread_sync (&done, &other_id); - gum_stalker_run_on_thread_sync (fixture->stalker, other_id, run_on_thread, - &ctx); - + accepted = gum_stalker_run_on_thread_sync (fixture->stalker, other_id, + run_on_thread, &ctx); + g_assert_true (accepted); done = TRUE; g_thread_join (thread); - g_assert_cmpuint (this_id, !=, other_id); - g_assert_cmpuint (other_id, ==, ctx.thread_id); + g_assert_cmpuint (ctx.thread_id, ==, other_id); } static GThread * -create_sleeping_dummy_thread_sync (volatile gboolean * done, +create_sleeping_dummy_thread_sync (gboolean * done, GumThreadId * thread_id) { - TestThreadSyncData sync_data; GThread * thread; + TestThreadSyncData sync_data; g_mutex_init (&sync_data.mutex); g_cond_init (&sync_data.cond); @@ -3615,8 +3627,7 @@ create_sleeping_dummy_thread_sync (volatile gboolean * done, while (!sync_data.started) g_cond_wait (&sync_data.cond, &sync_data.mutex); - if (thread_id != NULL) - *thread_id = sync_data.thread_id; + *thread_id = sync_data.thread_id; g_mutex_unlock (&sync_data.mutex); @@ -3630,7 +3641,7 @@ static gpointer sleeping_dummy (gpointer data) { TestThreadSyncData * sync_data = data; - volatile gboolean * done = sync_data->done; + gboolean * done = sync_data->done; g_mutex_lock (&sync_data->mutex); sync_data->started = TRUE;