diff --git a/gum/backend-arm/gumstalker-arm.c b/gum/backend-arm/gumstalker-arm.c index 175672d956..b89aac83a4 100644 --- a/gum/backend-arm/gumstalker-arm.c +++ b/gum/backend-arm/gumstalker-arm.c @@ -541,6 +541,8 @@ static void gum_exec_ctx_thumb_load_real_register_into (GumExecCtx * ctx, static GumExecBlock * gum_exec_block_new (GumExecCtx * ctx); static void gum_exec_block_clear (GumExecBlock * block); +static void gum_exec_block_cleanup_scratch_block_dirty(GumExecBlock *block, guint8 *scratch_base); +static GumExecBlock *gum_exec_block_get_active_block(GumExecBlock *block); static void gum_exec_block_commit (GumExecBlock * block); static void gum_exec_block_invalidate (GumExecBlock * block); static gpointer gum_exec_block_encode_instruction_pointer ( @@ -2013,7 +2015,7 @@ gum_exec_ctx_may_now_backpatch (GumExecCtx * ctx, if ((target_block->flags & GUM_EXEC_BLOCK_ACTIVATION_TARGET) != 0) return FALSE; - if (target_block->recycle_count < ctx->stalker->trust_threshold) + if (ctx->stalker->trust_threshold < 0 || target_block->recycle_count < ctx->stalker->trust_threshold) return FALSE; return TRUE; @@ -2144,11 +2146,12 @@ gum_exec_ctx_obtain_block_for (GumExecCtx * ctx, { const gint trust_threshold = ctx->stalker->trust_threshold; gboolean still_up_to_date; + GumExecBlock *active_block = gum_exec_block_get_active_block(block); still_up_to_date = (trust_threshold >= 0 && block->recycle_count >= trust_threshold) || - memcmp (block->real_start, gum_exec_block_get_snapshot_start (block), - block->real_size) == 0; + memcmp(block->real_start, gum_exec_block_get_snapshot_start(active_block), + block->real_size) == 0; gum_spinlock_release (&ctx->code_lock); @@ -2244,6 +2247,10 @@ gum_exec_ctx_recompile_block (GumExecCtx * ctx, } else { + guint8 *scratch_base = ctx->scratch_slab->slab.data; + // cleanup scratch written compile affect. + gum_exec_block_cleanup_scratch_block_dirty(block, scratch_base); + GumExecBlock * storage_block; GumAddress external_code_address; @@ -3355,6 +3362,7 @@ gum_stalker_iterator_put_callout (GumStalkerIterator * self, GDestroyNotify data_destroy) { GumExecBlock * block = self->exec_block; + GumExecBlock *active_block = gum_exec_block_get_active_block(block); GumGeneratorContext * gc = self->generator_context; GumCalloutEntry entry, * live_entry; GumAddress entry_address; @@ -3373,12 +3381,12 @@ gum_stalker_iterator_put_callout (GumStalkerIterator * self, live_entry = gum_exec_block_write_thumb_inline_data (cw, &entry, sizeof (entry), &entry_address); - gum_exec_block_thumb_open_prolog (block, gc); + gum_exec_block_thumb_open_prolog(active_block, gc); gum_thumb_writer_put_call_address_with_arguments (cw, GUM_ADDRESS (gum_stalker_invoke_callout), 2, GUM_ARG_ADDRESS, entry_address, GUM_ARG_REGISTER, ARM_REG_R10); - gum_exec_block_thumb_close_prolog (block, gc); + gum_exec_block_thumb_close_prolog(active_block, gc); } else { @@ -3387,16 +3395,16 @@ gum_stalker_iterator_put_callout (GumStalkerIterator * self, live_entry = gum_exec_block_write_arm_inline_data (cw, &entry, sizeof (entry), &entry_address); - gum_exec_block_arm_open_prolog (block, gc); + gum_exec_block_arm_open_prolog(active_block, gc); gum_arm_writer_put_call_address_with_arguments (cw, GUM_ADDRESS (gum_stalker_invoke_callout), 2, GUM_ARG_ADDRESS, entry_address, GUM_ARG_REGISTER, ARM_REG_R10); - gum_exec_block_arm_close_prolog (block, gc); + gum_exec_block_arm_close_prolog(active_block, gc); } - live_entry->next = gum_exec_block_get_last_callout_entry (block); - gum_exec_block_set_last_callout_entry (block, + live_entry->next = gum_exec_block_get_last_callout_entry(active_block); + gum_exec_block_set_last_callout_entry (active_block, GSIZE_TO_POINTER (entry_address)); } @@ -4253,6 +4261,32 @@ gum_exec_block_clear (GumExecBlock * block) block->storage_block = NULL; } +static GumExecBlock * +gum_exec_block_get_active_block(GumExecBlock *block) +{ + return block->storage_block == NULL ? block : block->storage_block; +} + +static void +gum_exec_block_cleanup_scratch_block_dirty(GumExecBlock *block, guint8 *scratch_base) +{ + guint last_callout_offset = block->last_callout_offset; + if (last_callout_offset == 0) + return; + GumCalloutEntry *entry = (GumCalloutEntry *)(scratch_base + last_callout_offset); + + // last_callout_offset base on scratch_base + for (; + entry != NULL; + entry = entry->next == NULL ? NULL : (GumCalloutEntry *)(scratch_base + ((guint8 *)entry->next - block->code_start))) + { + if (entry->data_destroy != NULL) + entry->data_destroy(entry->data); + } + block->last_callout_offset = 0; +} + + static void gum_exec_block_commit (GumExecBlock * block) { diff --git a/gum/backend-arm64/gumstalker-arm64.c b/gum/backend-arm64/gumstalker-arm64.c index f982f80e21..c6e24472d3 100644 --- a/gum/backend-arm64/gumstalker-arm64.c +++ b/gum/backend-arm64/gumstalker-arm64.c @@ -574,11 +574,8 @@ static void gum_exec_ctx_query_block_switch_callback (GumExecCtx * ctx, static GumExecBlock * gum_exec_ctx_obtain_block_for (GumExecCtx * ctx, gpointer real_address, gpointer * code_address); -static void gum_exec_ctx_recompile_block (GumExecCtx * ctx, - GumExecBlock * block); -static void gum_exec_ctx_write_scratch_slab (GumExecCtx * ctx, - GumExecBlock * block, guint * input_size, guint * output_size, - guint * slow_size); +static GumExecBlock * gum_exec_ctx_recompile_block(GumExecCtx *ctx, + GumExecBlock *block); static void gum_exec_ctx_compile_block (GumExecCtx * ctx, GumExecBlock * block, gconstpointer input_code, gpointer output_code, GumAddress output_pc, guint * input_size, guint * output_size, guint * slow_size); @@ -1665,7 +1662,7 @@ gum_stalker_recompile (GumStalker * self, if (block == NULL) return; - gum_exec_ctx_recompile_block (ctx, block); + block = gum_exec_ctx_recompile_block(ctx, block); } gpointer @@ -2411,7 +2408,7 @@ gum_exec_ctx_may_now_backpatch (GumExecCtx * ctx, if ((target_block->flags & GUM_EXEC_BLOCK_ACTIVATION_TARGET) != 0) return FALSE; - if (target_block->recycle_count < ctx->stalker->trust_threshold) + if (ctx->stalker->trust_threshold < 0 || target_block->recycle_count < ctx->stalker->trust_threshold) return FALSE; return TRUE; @@ -2558,7 +2555,7 @@ gum_exec_ctx_recompile_and_switch_block (GumExecCtx * ctx, if (gum_exec_ctx_maybe_unfollow (ctx, start_address)) return; - gum_exec_ctx_recompile_block (ctx, block); + block = gum_exec_ctx_recompile_block (ctx, block); ctx->current_block = block; ctx->resume_at = block->code_start; @@ -2590,7 +2587,7 @@ gum_exec_ctx_obtain_block_for (GumExecCtx * ctx, still_up_to_date = (trust_threshold >= 0 && block->recycle_count >= trust_threshold) || memcmp (block->real_start, gum_exec_block_get_snapshot_start (block), - block->real_size) == 0; + block->real_size) == 0; gum_spinlock_release (&ctx->code_lock); @@ -2601,7 +2598,7 @@ gum_exec_ctx_obtain_block_for (GumExecCtx * ctx, } else { - gum_exec_ctx_recompile_block (ctx, block); + block = gum_exec_ctx_recompile_block (ctx, block); } } else @@ -2627,136 +2624,34 @@ gum_exec_ctx_obtain_block_for (GumExecCtx * ctx, return block; } -static void + +static GumExecBlock* gum_exec_ctx_recompile_block (GumExecCtx * ctx, GumExecBlock * block) { - GumStalker * stalker = ctx->stalker; - guint8 * internal_code = block->code_start; - guint8 * scratch_base = ctx->scratch_slab->slab.data; - guint input_size, output_size, slow_size; - gsize new_block_size, new_snapshot_size; + gpointer real_address = block->real_start; + GumExecBlock *new_block; gum_spinlock_acquire (&ctx->code_lock); - gum_exec_ctx_write_scratch_slab (ctx, block, &input_size, &output_size, - &slow_size); - - new_snapshot_size = - gum_stalker_snapshot_space_needed_for (stalker, input_size); - - new_block_size = output_size + new_snapshot_size; - - gum_stalker_thaw (stalker, internal_code, block->capacity); - - if (new_block_size <= block->capacity) - { - block->real_size = input_size; - block->code_size = output_size; - - memcpy (internal_code, scratch_base, output_size); - memcpy (gum_exec_block_get_snapshot_start (block), block->real_start, - new_snapshot_size); - - gum_stalker_freeze (stalker, internal_code, new_block_size); - } - else - { - GumExecBlock * storage_block; - GumArm64Writer * cw = &ctx->code_writer; - GumAddress external_code_address; - - storage_block = gum_exec_block_new (ctx); - storage_block->real_start = block->real_start; - gum_exec_ctx_compile_block (ctx, storage_block, block->real_start, - storage_block->code_start, GUM_ADDRESS (storage_block->code_start), - &storage_block->real_size, &storage_block->code_size, - &storage_block->slow_size); - gum_exec_block_commit (storage_block); - block->storage_block = storage_block; - - gum_stalker_thaw (stalker, internal_code, block->capacity); - gum_arm64_writer_reset (cw, internal_code); - - external_code_address = GUM_ADDRESS (storage_block->code_start); - if (gum_arm64_writer_can_branch_directly_between (cw, - GUM_ADDRESS (internal_code), external_code_address)) - { - gum_arm64_writer_put_b_imm (cw, external_code_address); - gum_arm64_writer_put_b_imm (cw, external_code_address + sizeof (guint32)); - } - else - { - gconstpointer already_saved = cw->code + 1; - - gum_arm64_writer_put_b_label (cw, already_saved); - gum_arm64_writer_put_stp_reg_reg_reg_offset (cw, ARM64_REG_X16, - ARM64_REG_X17, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), - GUM_INDEX_PRE_ADJUST); - gum_arm64_writer_put_label (cw, already_saved); - gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X16, - external_code_address); - gum_arm64_writer_put_br_reg_no_auth (cw, ARM64_REG_X16); - } - - gum_arm64_writer_flush (cw); - gum_stalker_freeze (stalker, internal_code, block->capacity); - } - + new_block = gum_exec_block_new(ctx); + new_block->real_start = real_address; + gum_exec_block_maybe_inherit_exclusive_access_state(new_block, new_block->next); + gum_exec_ctx_compile_block(ctx, new_block, real_address, new_block->code_start, + GUM_ADDRESS(new_block->code_start), &new_block->real_size, &new_block->code_size, + &new_block->slow_size); + gum_exec_block_commit(new_block); + gum_exec_block_propagate_exclusive_access_state(new_block); + + gum_metal_hash_table_replace(ctx->mappings, real_address, new_block); + gum_spinlock_release (&ctx->code_lock); - gum_exec_ctx_maybe_emit_compile_event (ctx, block); -} - -static void -gum_exec_ctx_write_scratch_slab (GumExecCtx * ctx, - GumExecBlock * block, - guint * input_size, - guint * output_size, - guint * slow_size) -{ - GumStalker * stalker = ctx->stalker; - guint8 * internal_code = block->code_start; - GumSlowSlab * slow_slab; - gsize slow_available; - gpointer slow_start; - GumCodeSlab * prev_code_slab; - GumSlowSlab * prev_slow_slab; - guint8 * scratch_base; - - gum_exec_block_maybe_create_new_code_slabs (ctx); - gum_exec_block_maybe_create_new_data_slab (ctx); - - slow_slab = ctx->slow_slab; - - slow_available = gum_slab_available (&slow_slab->slab); - - gum_scratch_slab_init (ctx->scratch_slab, GUM_SCRATCH_SLAB_SIZE); - - slow_start = gum_slab_cursor (&slow_slab->slab); - slow_available = gum_slab_available (&slow_slab->slab); - gum_stalker_thaw (stalker, slow_start, slow_available); + gum_exec_ctx_maybe_emit_compile_event(ctx, new_block); - if (block->storage_block != NULL) - gum_exec_block_clear (block->storage_block); - gum_exec_block_clear (block); + gum_exec_block_clear(block); - prev_code_slab = block->code_slab; - prev_slow_slab = block->slow_slab; - - block->code_slab = ctx->scratch_slab; - block->slow_slab = ctx->slow_slab; - block->slow_start = gum_slab_cursor (&slow_slab->slab); - scratch_base = ctx->scratch_slab->slab.data; - ctx->scratch_slab->invalidator = prev_code_slab->invalidator; - - gum_exec_ctx_compile_block (ctx, block, block->real_start, scratch_base, - GUM_ADDRESS (internal_code), input_size, output_size, slow_size); - gum_slab_reserve (&slow_slab->slab, *slow_size); - gum_stalker_freeze (stalker, slow_start, *slow_size); - - block->code_slab = prev_code_slab; - block->slow_slab = prev_slow_slab; + return new_block; } static void @@ -3999,6 +3894,7 @@ gum_exec_block_clear (GumExecBlock * block) block->storage_block = NULL; } + static gconstpointer gum_exec_block_check_address_for_exclusion (GumExecBlock * block, gconstpointer address)