Skip to content

fix: riscv PC advance for compressed instructions and fetch faults - #2400

Closed
Kreijstal wants to merge 1 commit into
unicorn-engine:masterfrom
Kreijstal:fix/riscv-exception-pc-advance
Closed

fix: riscv PC advance for compressed instructions and fetch faults#2400
Kreijstal wants to merge 1 commit into
unicorn-engine:masterfrom
Kreijstal:fix/riscv-exception-pc-advance

Conversation

@Kreijstal

Copy link
Copy Markdown

cpu_handle_exception unconditionally does env->pc += 4 for RISC-V. This corrupts the PC for 16-bit compressed instructions and for instruction access/page faults (where env->pc already holds the faulting address and must not be advanced). It also leaves the faulting address unavailable to UC_HOOK_INTR callbacks.

Changes:

  • Advance env->pc by the real instruction size (2 or 4 bytes, determined by the low two opcode bits) for execution-time exceptions.
  • Skip the advance for INST_ADDR_MIS, INST_ACCESS_FAULT, INST_PAGE_FAULT.
  • Mirror riscv_cpu_do_interrupt and set env->mbadaddr = env->badaddr for every address-bearing exception, so the callback can recover from e.g. PMP faults.

Verified by booting a RISC-V firmware under Unicorn whose syscall/return path is full of compressed instructions and relies on lazy PMP fault recovery.

@Kreijstal Kreijstal changed the title riscv: fix PC advance for compressed instructions and fetch faults fix: riscv PC advance for compressed instructions and fetch faults Aug 19, 2026
@Kreijstal
Kreijstal marked this pull request as draft August 19, 2026 09:48
@Kreijstal
Kreijstal force-pushed the fix/riscv-exception-pc-advance branch 2 times, most recently from e3c2656 to 132a5ac Compare August 19, 2026 11:25
@Kreijstal
Kreijstal marked this pull request as ready for review August 19, 2026 17:23
cpu_handle_exception unconditionally does env->pc += 4 for RISC-V.  That
corrupts the PC for 16-bit compressed instructions and for instruction
access/page faults, where env->pc already holds the faulting address and
must not be advanced.

Move the logic into a RISC-V helper, riscv_cpu_prepare_exception_pc(),
which mirrors the trap state riscv_cpu_do_interrupt would set up:

- load mbadaddr from badaddr for every address-bearing exception so the
  UC_HOOK_INTR callback can inspect the faulting address
- advance the PC by the real instruction size (2 or 4 bytes, from the low
  two opcode bits) for execution-time exceptions
- leave the PC untouched for INST_ADDR_MIS / INST_ACCESS_FAULT /
  INST_PAGE_FAULT

Extract the address-bearing exception list into a shared
riscv_cpu_exception_has_badaddr() predicate used by both do_interrupt and
the new helper, instead of duplicating the switch.
@Kreijstal
Kreijstal force-pushed the fix/riscv-exception-pc-advance branch from 132a5ac to 9e66abe Compare August 19, 2026 17:24
@Kreijstal

Kreijstal commented Aug 20, 2026

Copy link
Copy Markdown
Author

Closing this as superseded by #2384. That PR preserves the faulting PC while the hook runs and advances to the translator-recorded next PC only after a handled ecall, which also covers compressed instructions.

One part is missing from #2384. For instruction, load, and store address faults, RISC-V places the faulting address in mtval. UC_HOOK_INTR should be able to read that value. I split the fix into a patch on top of #2384:

Kreijstal@c3cb167

I built that commit with RISC-V enabled. All 30 tests from #2384 pass.

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

Successfully merging this pull request may close these issues.

1 participant