unicorn icon indicating copy to clipboard operation
unicorn copied to clipboard

Setting PC in uc_cb_insn_sys_t callback does not take effect in ARM64 architecture

Open 3093292237 opened this issue 1 year ago • 7 comments

I am encountering an issue with the Unicorn Engine where setting the PC (Program Counter) in the uc_cb_insn_sys_t callback does not appear to take effect. Despite writing a new value to the PC register within the callback, the emulation continues to execute from the original PC value. Notice that the emulation continues executing from the original PC address, not the updated one.

3093292237 avatar Dec 04 '24 08:12 3093292237

That should be expected because PC is not synced for those hooks.

What's your use case?

wtdcode avatar Dec 07 '24 09:12 wtdcode

@wtdcode I'm using the C API and I have added the following hook with the type UC_HOOK_INSN. When I try to modify the value of the PC in the callback, it doesn't take effect. This issue can be easily reproduced with the following code: uc_hook_add(uc, &hook_INSN_MRS, UC_HOOK_INSN, (void*) instruction_handler, nullptr, 1, 0, UC_ARM64_INS_MRS) This should clearly convey your issue with modifying the PC within the UC_HOOK_INSN callback.

3093292237 avatar Dec 08 '24 06:12 3093292237

@wtdcode The prototype of this hook is as follows: uint32_t instruction_handler(uc_engine *uc, uc_arm64_reg reg, const uc_arm64_cp_reg *cp_reg, void *user_data)

3093292237 avatar Dec 08 '24 06:12 3093292237

I have a related / similar issue to this one...

If I hook mrs/msr to support unhandled system registers, then the "skip" feature doesn't work as I would expect. If I return 0, then the instruction will cause an unexpected CPU instruction. If I return 1, then the instruction is retried. The PC does not move forward by +4. I have to actually modify the UC_ARM64_REG_PC manually and unlike the original poster, changing the PC works for me.

I'm having issues with system registers seemingly supported by UC, but they give me "Unexpected CPU exception". In the mean time, I have been hooking them to emulate their behaviour and skip such instructions. For example, CPTR_EL3 is part of the standard EL3 register set according to the latest UC source code but it doesn't work for me.

Below is my current code:

static void skip_pc(uc_engine *uc)
{
        uint64_t pc;

        uc_reg_read(uc, UC_ARM64_REG_PC, &pc);
        pc += 4;
        uc_reg_write(uc, UC_ARM64_REG_PC, &pc);
}

uint32_t msr(uc_engine *uc, uc_arm64_reg reg, const uc_arm64_cp_reg *cp_reg, void *user_data)
{
        uint64_t pc;

        if (cp_reg->crn == 1 && cp_reg->crm == 1 && cp_reg->op0 == 3 && cp_reg->op1 == 6 && cp_reg->op2 == 2) {
                skip_pc(uc); // Without this, the instruction is retried!
                printf("Ignored CPTR_EL3\n");
                return 1;
        }
...
        error = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &engine);
...
        error = uc_ctl_set_cpu_model(engine, UC_CPU_ARM64_A53);
...
        error = uc_hook_add(engine, &handle, UC_HOOK_INSN, msr, NULL, 1, 0, UC_ARM64_INS_MSR);
...
        state = 0x400003CD; // Start at EL3h
        uc_reg_write(engine, UC_ARM64_REG_PSTATE, &state);

DualTachyon avatar Jan 30 '25 13:01 DualTachyon

I somehow fixed the "system register doesn't exist" problem, the machine was in EL2h despite my pstate change. However, the skip problem still remains. On the code I'm emulating, there's a CPUECTLR_EL1 register that UC doesn't have and unless I skip the PC by 4, return 1 will always retry the instruction.

DualTachyon avatar Jan 30 '25 23:01 DualTachyon

I somehow fixed the "system register doesn't exist" problem, the machine was in EL2h despite my pstate change. However, the skip problem still remains. On the code I'm emulating, there's a CPUECTLR_EL1 register that UC doesn't have and unless I skip the PC by 4, return 1 will always retry the instruction.

Are you on dev branch?

wtdcode avatar Jan 31 '25 02:01 wtdcode

I somehow fixed the "system register doesn't exist" problem, the machine was in EL2h despite my pstate change. However, the skip problem still remains. On the code I'm emulating, there's a CPUECTLR_EL1 register that UC doesn't have and unless I skip the PC by 4, return 1 will always retry the instruction.

Are you on dev branch?

I'm on "master" branch.

DualTachyon avatar Jan 31 '25 14:01 DualTachyon