move platform specific into arm file

This commit is contained in:
Lysann Tranvouez 2025-10-01 22:43:05 +02:00
parent ccaa4bfbf0
commit db603acded
3 changed files with 193 additions and 156 deletions

View file

@ -305,55 +305,9 @@ static void internal_detour_free_unused_trampoline_regions()
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Trampoline Helpers
static uint8_t internal_detour_align_from_trampoline(const detour_trampoline* trampoline,
const uint8_t offset_trampoline)
{
for (int32_t n = 0; n < ARRAYSIZE(trampoline->align); n++) {
if (trampoline->align[n].offset_trampoline == offset_trampoline) {
return trampoline->align[n].offset_target;
}
}
return 0;
}
static uint8_t internal_detour_align_from_target(const detour_trampoline* trampoline, const uint8_t offset_target)
{
for (int32_t n = 0; n < ARRAYSIZE(trampoline->align); n++) {
if (trampoline->align[n].offset_target == offset_target) {
return trampoline->align[n].offset_trampoline;
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Transactions
typedef enum detour_operation_kind
{
detour_operation_kind_attach,
detour_operation_kind_detach,
} detour_operation_kind;
typedef struct detour_operation
{
struct detour_operation* next;
detour_operation_kind kind;
uint8_t** pointer;
uint8_t* target;
detour_trampoline* trampoline;
vm_prot_t perm;
} detour_operation;
typedef struct detour_pending_thread
{
struct detour_pending_thread* next;
thread_t thread;
} detour_pending_thread;
static bool s_ignore_too_small = false;
static bool s_retain_regions = false;
@ -450,100 +404,60 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target)
// Insert or remove each of the detours.
for (detour_operation* operation = s_pending_operations_head; operation != nullptr; operation = operation->next) {
if (operation->kind == detour_operation_kind_detach) {
memcpy(operation->target, operation->trampoline->restore_code, operation->trampoline->restore_code_size);
#ifdef DETOURS_ARM64
*operation->pointer = operation->target;
#endif
} else {
DETOUR_TRACE(("detours: trampoline=%p, ptr_remain=%p, ptr_detour=%p, restore_code_size=%u\n",
operation->trampoline,
operation->trampoline->ptr_remain,
operation->trampoline->ptr_detour,
operation->trampoline->restore_code_size));
switch (operation->kind) {
case detour_operation_kind_attach: {
DETOUR_TRACE(("detours: trampoline=%p, ptr_remain=%p, ptr_detour=%p, restore_code_size=%u\n",
operation->trampoline,
operation->trampoline->ptr_remain,
operation->trampoline->ptr_detour,
operation->trampoline->restore_code_size));
DETOUR_TRACE(("detours: target=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x [before]\n",
operation->target,
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
DETOUR_TRACE(("detours: target=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x [before]\n",
operation->target,
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
#ifdef DETOURS_ARM64
uint8_t* code = internal_detour_gen_jmp_indirect(operation->target,
(uint64_t*)&(operation->trampoline->ptr_detour));
code = internal_detour_gen_brk(code, operation->trampoline->ptr_remain);
UNUSED_VARIABLE(code);
*operation->pointer = operation->trampoline->code;
#endif // DETOURS_ARM64
internal_detour_operation_commit_detour(operation);
*operation->pointer = internal_detour_operation_get_trampoline_ptr(operation)
DETOUR_TRACE(("detours: target=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x [after]\n",
operation->target,
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
DETOUR_TRACE(("detours: target=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x [after]\n",
operation->target,
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
DETOUR_TRACE(("detours: trampoline=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x\n",
operation->trampoline,
operation->trampoline->code[0], operation->trampoline->code[1],
operation->trampoline->code[2], operation->trampoline->code[3],
operation->trampoline->code[4], operation->trampoline->code[5],
operation->trampoline->code[6], operation->trampoline->code[7],
operation->trampoline->code[8], operation->trampoline->code[9],
operation->trampoline->code[10], operation->trampoline->code[11]));
DETOUR_TRACE(("detours: trampoline=%p: "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x "
"%02x %02x %02x %02x\n",
operation->trampoline,
operation->trampoline->code[0], operation->trampoline->code[1],
operation->trampoline->code[2], operation->trampoline->code[3],
operation->trampoline->code[4], operation->trampoline->code[5],
operation->trampoline->code[6], operation->trampoline->code[7],
operation->trampoline->code[8], operation->trampoline->code[9],
operation->trampoline->code[10], operation->trampoline->code[11]));
break;
}
case detour_operation_kind_detach: {
memcpy(operation->target, operation->trampoline->restore_code,
operation->trampoline->restore_code_size);
*operation->pointer = internal_detour_operation_get_target_ptr(operation);
break;
}
}
}
// Update any suspended threads.
for (detour_pending_thread* thread = s_pending_threads_head; thread != nullptr; thread = thread->next) {
arm_thread_state64_t threadState;
mach_msg_type_number_t threadStateCnt = ARM_THREAD_STATE64_COUNT;
const kern_return_t error = thread_get_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
&threadStateCnt);
if (error != err_none) {
DETOUR_BREAK();
continue;
}
const uintptr_t pc = arm_thread_state64_get_pc(threadState);
for (detour_operation* op = s_pending_operations_head; op != nullptr; op = op->next) {
switch (op->kind) {
case detour_operation_kind_attach: {
const uintptr_t targetAddr = (uintptr_t)op->target;
if (pc >= targetAddr && pc < targetAddr + op->trampoline->restore_code_size) {
uintptr_t new_pc = (uintptr_t)op->trampoline;
new_pc += internal_detour_align_from_target(op->trampoline, pc - targetAddr);
DETOUR_TRACE(("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n",
thread->thread, pc, new_pc));
arm_thread_state64_set_pc_fptr(threadState, new_pc);
thread_set_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
ARM_THREAD_STATE64_COUNT);
}
break;
}
case detour_operation_kind_detach: {
const uintptr_t trampAddr = (uintptr_t)op->trampoline;
if (pc >= trampAddr && pc < trampAddr + sizeof(*op->trampoline)) {
uintptr_t new_pc = (uintptr_t)op->target;
new_pc += internal_detour_align_from_trampoline(op->trampoline, pc - trampAddr);
DETOUR_TRACE(("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n",
thread->thread, pc, new_pc));
arm_thread_state64_set_pc_fptr(threadState, new_pc);
thread_set_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
ARM_THREAD_STATE64_COUNT);
}
break;
}
}
}
internal_detour_update_thread_on_commit(thread, s_pending_operations_head);
}
// Restore all the page permissions