Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions gum/backend-arm/gumstalker-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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
{
Expand All @@ -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));
}

Expand Down Expand Up @@ -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)
{
Expand Down
156 changes: 26 additions & 130 deletions gum/backend-arm64/gumstalker-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down