Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
3093292237 opened this issue Dec 4, 2024 · 7 comments

Comments

@3093292237
Copy link

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.

@wtdcode
Copy link
Member

wtdcode commented Dec 7, 2024

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

What's your use case?

@3093292237
Copy link
Author

@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
Copy link
Author

@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)

@DualTachyon
Copy link

DualTachyon commented Jan 30, 2025

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
Copy link

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.

@wtdcode
Copy link
Member

wtdcode commented Jan 31, 2025

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?

@DualTachyon
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants