|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33). More...
Go to the source code of this file.
Enumerations | |
| enum | div0_field_t : uint32_t { k_div0_hw1_mask = 0xFFF0U , k_div0_hw1_udiv = 0xFBB0U , k_div0_hw1_sdiv = 0xFB90U , k_div0_hw2_mask = 0xF0F0U , k_div0_hw2_fixed = 0xF0F0U , k_div0_reg_mask = 0x000FU , k_div0_rd_shift = 8U , k_div0_reg_sp = 13U , k_div0_reg_pc = 15U , k_div0_insn_len = 4U , k_div0_cfsr_divzero = 1U << 25U , k_div0_int32_min = 0x80000000U , k_div0_udf_b0 = 0xF0U , k_div0_udf_b1 = 0xF7U , k_div0_udf_b3 = 0xA0U } |
| UDIV/SDIV decode masks + fault field bits for the div-0 seam. More... | |
Functions | |
| bool | emulate_mve (uc_engine *uc, uint32_t pc0, const uint8_t code0[4]) |
| Emulate a run of consecutive auto-vectoriser MVE instructions. | |
| bool | emu_mve_nocp_emulate (uc_engine *uc, uint32_t pc) |
| Emulate an MVE contiguous load/store from the NoCP UsageFault. | |
| bool | emu_mve_nocp_take (void) |
| Test and clear the "NoCP fault serviced by the MVE seam" latch. | |
| bool | emu_mve_nocp_spurious (uint32_t pc) |
Report whether an invalid-instruction trap at pc is the bogus one Unicorn raises just after the MVE seam serviced a NoCP fault. | |
| uint64_t | emu_mve_emulated_count (void) |
| Count of MVE instructions emulated this run (run-end telemetry). | |
| void | long_shift_seam_install (uc_engine *uc, const emu_elf_source_t *elf) |
| Scan the loaded image and install a hook at every immediate long-shift. | |
| bool | emulate_long_shift_reg (uc_engine *uc, uint32_t pc, const uint8_t code[4]) |
| Emulate a register-form Armv8.1-M long shift (LSLL/ASRL) that trapped. | |
| void | div0_seam_install (const emu_elf_source_t *elf) |
| Scan the image for UDIV/SDIV sites so the div-0 trap can arm later. | |
| void | div0_patch_sites (uc_engine *uc) |
| Overwrite every tracked divide with UDF so divide-by-zero can trap. | |
| bool | emulate_div0_patched (uc_engine *uc, uint32_t pc, const uint8_t code[4]) |
| Service an undefined-instruction trap that landed on an armed divide. | |
| bool | emu_div0_fault_pending (void) |
| Whether a trapping divide-by-zero is latched for the run loop. | |
| void | emu_div0_clear_fault (void) |
| Clear the latched divide-by-zero fault. | |
| uint32_t | emu_div0_fault_pc (void) |
| PC of the divide that latched the pending fault. | |
| void | emu_div0_count_trap (void) |
| Count one synthesised divide-by-zero UsageFault (telemetry). | |
| void | emu_div0_disarm (void) |
| Drop the armed state after a warm reboot re-loads the image. | |
| bool | on_invalid_insn (uc_engine *uc, void *user) |
| UC_HOOK_INSN_INVALID dispatcher: service or report a trapped opcode. | |
| void | emu_insn_seams_install (uc_engine *uc) |
| Arm the invalid-instruction dispatcher on the engine. | |
| uint64_t | emu_lob_emulated_count (void) |
| Count of LOB (DLS/LE) instructions emulated this run (telemetry). | |
| void | div0_synth_usagefault (uc_engine *uc, uint32_t vtor_base) |
| Synthesise a UsageFault (#6) for a trapped divide-by-zero. | |
| void | emu_fast_sd_enable (void) |
| Opt in to the –fast-sd block-serving seam for this run. | |
| void | fast_sd_seam_install (uc_engine *uc, const emu_elf_source_t *elf) |
| Install the --fast-sd block-read hook if opted-in and the symbol exists. | |
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
The RA8D2's Cortex-M85 executes Armv8.1-M instructions that Unicorn's nearest core (Cortex-M33, Armv8-M) either traps as invalid or silently mis-executes. Each seam closes one gap:
Split out of the ra8_emulator main translation unit; behaviour unchanged.
Definition in file emu_seams.h.
| enum div0_field_t : uint32_t |
UDIV/SDIV decode masks + fault field bits for the div-0 seam.
Definition at line 230 of file emu_seams.h.
| void div0_patch_sites | ( | uc_engine * | uc | ) |
Overwrite every tracked divide with UDF so divide-by-zero can trap.
Called from the SCB control-register write hook the first time the firmware sets CCR.DIV_0_TRP. The patch is deferred to opt-in so a firmware that never arms the trap keeps its original divides (native, quotient-0 semantics) and pays nothing. Patching to UDF – rather than installing a UC_HOOK_CODE at each site – is deliberate: a code hook disables Unicorn's engine-wide block chaining and would roughly quarter the throughput of any busy loop in a DIV_0_TRP firmware, whereas the already-armed undefined-instruction hook has no such cost. Idempotent; re-applied after a warm reboot re-loads the image (the reboot path calls emu_div0_disarm()).
| [in,out] | uc | Unicorn engine whose memory is patched. |
uc permits uc_mem_write to the code image. Called from ::on_scb_ctrl_write the first time the firmware sets CCR.DIV_0_TRP. The patch is deferred to opt-in so a firmware that never arms the trap keeps its original divides (native, quotient-0 semantics) and pays nothing. Patching to UDF – rather than installing a UC_HOOK_CODE at each site – is deliberate: UC_HOOK_CODE disables Unicorn's engine-wide block chaining and would roughly quarter the throughput of any busy loop in a DIV_0_TRP firmware, whereas the already-armed undefined-instruction hook (on_invalid_insn) has no such cost. Idempotent via s_div0_armed. Re-applied after a warm reboot re-loads the image (see the run loop's reboot paths, which clear s_div0_armed).
| [in,out] | uc | Unicorn engine whose memory is patched. |
uc permits uc_mem_write to the (host-side) code image. Definition at line 301 of file emu_seam_div0.c.
References emu_mem_write(), priv_emu_io_errf(), s_div0_armed, s_div0_site, s_div0_site_n, and s_k_div0_udf.
Referenced by internal_on_scb_ctrl_write().
| void div0_seam_install | ( | const emu_elf_source_t * | elf | ) |
Scan the image for UDIV/SDIV sites so the div-0 trap can arm later.
Walks the ELF32 PT_LOAD executable segments on 2-byte boundaries for the UDIV/SDIV encoding, recording each site's VMA (p_vaddr based, so a ramfunc is tracked at its execution address) and its original halfwords. Nothing is patched here; the SCB control-write watcher overwrites the sites with UDF via div0_patch_sites() only if the firmware sets CCR.DIV_0_TRP. Tracked for every core (UDIV/SDIV exist on the M85 and the M33 alike). A scan false-positive is harmless: the site is only ever patched after opt-in, and emulate_div0_patched() re-decodes before acting.
| [in] | elf | Open immutable ELF source. |
elf is a 32-bit ARM ELF (already validated by load_elf). elf remains open throughout the bounded segment scan. Walks the ELF32 PT_LOAD executable segments on 2-byte boundaries for the UDIV/SDIV encoding (internal_udiv_sdiv_decode), recording each site's VMA (p_vaddr based, so a ramfunc is tracked at its execution address) and its original halfwords. Nothing is patched here; the always-on SCB control-write watcher (::on_scb_ctrl_write) overwrites the sites with UDF via div0_patch_sites only if the firmware sets CCR.DIV_0_TRP. Tracked for every core (UDIV/SDIV exist on the M85 and the M33 alike). A scan false-positive is harmless: the site is only ever patched after opt-in, and emulate_div0_patched re-decodes before acting.
| [in] | elf | In-memory ELF image (still alive at call time). |
elf is a 32-bit ARM ELF (already validated by load_elf). Definition at line 409 of file emu_seam_div0.c.
References elf_foreach_exec_segment(), internal_div0_scan_segment(), priv_emu_io_errf(), s_div0_armed, and s_div0_site_n.
Referenced by internal_main_install_run_seams().
| void div0_synth_usagefault | ( | uc_engine * | uc, |
| uint32_t | vtor_base ) |
Synthesise a UsageFault (#6) for a trapped divide-by-zero.
Called by the run loop after emulate_div0_patched() latched a trapping div-0. Latches CFSR.UFSR.DIVBYZERO (so a fault handler – and the HIL alive probe – see the architectural status), forces PC back to the faulting divide so the exception entry stacks that address, and vectors into the application's UsageFault_Handler. If no handler is installed the trap is dropped (no HardFault escalation is modelled).
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base if VTOR reads as 0. |
Called by the run loop after emulate_div0_patched latched a trapping div-0. Latches CFSR.UFSR.DIVBYZERO (so a fault handler – and the HIL alive probe – see the architectural status: cfsr == 0x02000000), forces PC back to the faulting divide so exc_enter stacks that address (a real div-0 UsageFault stacks the divide), and vectors into the application's UsageFault_Handler. If no handler is installed the trap is dropped (no HardFault escalation is modelled – the firmware that arms DIV_0_TRP always installs the handler).
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base if VTOR reads as 0. |
Definition at line 448 of file emu_seam_div0.c.
References emu_div0_count_trap(), emu_div0_fault_pc(), exc_enter(), exc_vector(), k_div0_cfsr_divzero, k_exc_usagefault, k_scb_cfsr, rd32(), and wr32().
Referenced by internal_run_inner_take_exception().
| void emu_div0_clear_fault | ( | void | ) |
Clear the latched divide-by-zero fault.
The run loop clears the latch right before synthesising the UsageFault; the warm-reboot path clears it so a rebooted image starts clean.
Clear the latched divide-by-zero fault.
Definition at line 468 of file emu_seam_div0.c.
References s_div0_fault.
Referenced by internal_run_inner_take_exception(), and warm_reboot().
| void emu_div0_count_trap | ( | void | ) |
Count one synthesised divide-by-zero UsageFault (telemetry).
Count one synthesised divide-by-zero usagefault (telemetry); this step is contained within the emu seams model and uses bounded caller or module-owned storage.
Count one synthesised divide-by-zero UsageFault (telemetry).
Definition at line 480 of file emu_seam_div0.c.
References s_div0_traps.
Referenced by div0_synth_usagefault().
| void emu_div0_disarm | ( | void | ) |
Drop the armed state after a warm reboot re-loads the image.
Re-loading the ELF restores the original divide encodings, so the seam must re-arm on the next CCR.DIV_0_TRP write; this clears the idempotence latch.
Drop the armed state after a warm reboot re-loads the image.
Definition at line 486 of file emu_seam_div0.c.
References s_div0_armed.
Referenced by warm_reboot().
| uint32_t emu_div0_fault_pc | ( | void | ) |
PC of the divide that latched the pending fault.
| 0 | No fault has ever been latched. |
Pc of the divide that latched the pending fault; this step is contained within the emu seams model and uses bounded caller or module-owned storage.
PC of the divide that latched the pending fault.
Definition at line 474 of file emu_seam_div0.c.
References s_div0_fault_pc.
Referenced by div0_synth_usagefault().
| bool emu_div0_fault_pending | ( | void | ) |
Whether a trapping divide-by-zero is latched for the run loop.
| false | No divide-by-zero is pending. |
Whether a trapping divide-by-zero is latched for the run loop; this step is contained within the emu seams model and uses bounded caller or module-owned storage.
Whether a trapping divide-by-zero is latched for the run loop.
Definition at line 462 of file emu_seam_div0.c.
References s_div0_fault.
Referenced by internal_run_inner_take_exception().
| void emu_fast_sd_enable | ( | void | ) |
Opt in to the –fast-sd block-serving seam for this run.
Opt in to the –fast-sd block-serving seam for this run; this step is contained within the emu seams model and uses bounded caller or module-owned storage.
Opt in to the –fast-sd block-serving seam for this run.
Definition at line 149 of file emu_seam_sd.c.
References s_fast_sd.
Referenced by internal_args_try_mode().
| void emu_insn_seams_install | ( | uc_engine * | uc | ) |
Arm the invalid-instruction dispatcher on the engine.
uc is initialised (no code has run yet). Arm the invalid-instruction dispatcher on the engine; this step is contained within the emu seams model and uses bounded caller or module-owned storage.
| [in,out] | uc | Unicorn engine whose emulated state is read or updated. |
Arm the invalid-instruction dispatcher on the engine.
Definition at line 586 of file emu_insn_seams.c.
References on_invalid_insn().
Referenced by internal_main_install_core_seams().
| uint64_t emu_lob_emulated_count | ( | void | ) |
Count of LOB (DLS/LE) instructions emulated this run (telemetry).
| 0 | No LOB instruction was emulated. |
Count of lob (dls/le) instructions emulated this run (telemetry); this step is contained within the emu seams model and uses bounded caller or module-owned storage.
Count of LOB (DLS/LE) instructions emulated this run (telemetry).
Definition at line 593 of file emu_insn_seams.c.
References s_lob_emulated.
Referenced by internal_run_print_stop_summary().
| uint64_t emu_mve_emulated_count | ( | void | ) |
Count of MVE instructions emulated this run (run-end telemetry).
| 0 | No MVE instruction was emulated (e.g. an M33 image). |
Count of mve instructions emulated this run (run-end telemetry); this step is contained within the emu seams model and uses bounded caller or module-owned storage.
Count of MVE instructions emulated this run (run-end telemetry).
Definition at line 490 of file emu_seam_mve.c.
References s_mve_emulated.
Referenced by internal_run_print_stop_summary().
| bool emu_mve_nocp_emulate | ( | uc_engine * | uc, |
| uint32_t | pc ) |
Emulate an MVE contiguous load/store from the NoCP UsageFault.
Armv8.1-M reallocates coprocessor space 0b1110 / 0b1111 to MVE, so VLDRB/VLDRH/VLDRW and VSTRB/VSTRH/VSTRW (immediate offset) reuse the legacy STC/LDC encodings byte for byte – stc p15, c7, [r0, #196] and vstrw.32 q3, [r0, #196] are both ED80 7F31. Unicorn's M33 implements neither MVE nor coprocessor 14/15, so it does not trap them as invalid instructions: it raises a NoCP UsageFault with PC still at the faulting word. This decodes that word straight from its two halfwords (capstone renders the family as a legacy stc, so it cannot be used), moves the 16-byte vector, applies write-back, and advances PC past the instruction. Anything outside the family – including the neighbouring FP stores, which differ only in hw2[12:9] and which Unicorn executes correctly – is rejected so it still faults honestly.
| [in,out] | uc | Unicorn engine. |
| [in] | pc | Address of the faulting instruction. |
| true | The access happened and PC advanced by four bytes. |
| false | Not this family; no engine state changed. |
uc is stopped inside the UC_HOOK_INTR NoCP fault. pc is the faulting instruction address, not an EXC_RETURN magic. Definition at line 452 of file emu_seam_mve.c.
References emu_mem_read(), internal_mve_mem_try(), k_mve_insn_len, s_mve_emulated, s_mve_nocp_handled, s_mve_resume_armed, and s_mve_resume_pc.
Referenced by internal_on_intr().
| bool emu_mve_nocp_spurious | ( | uint32_t | pc | ) |
Report whether an invalid-instruction trap at pc is the bogus one Unicorn raises just after the MVE seam serviced a NoCP fault.
Servicing the NoCP fault means writing PC and calling uc_emu_stop from inside the interrupt hook. Unicorn then re-decodes at the advanced PC and reports UC_ERR_INSN_INVALID there even though the instruction is perfectly valid – in ereader_cover the address is a plain strd r3, r3, [r7, #8] four bytes past a vstrw.32. A relaunch from that same PC executes it correctly, so the report is noise, but it is indistinguishable from a real one by decode alone: this predicate distinguishes it by address instead.
Exactly one report is absorbed per serviced fault, and only at the address the seam advanced to. A genuinely invalid instruction sitting at that address is therefore delayed by one relaunch, never suppressed: the arming is cleared on the first call, so the second trap reports normally.
| [in] | pc | Address the invalid-instruction hook trapped at. |
| true | Absorb it silently and relaunch; nothing is wrong. |
| false | Report it; the arming (if any) is now cleared. |
Definition at line 470 of file emu_seam_mve.c.
References s_mve_nocp_handled, s_mve_resume_armed, and s_mve_resume_pc.
Referenced by on_invalid_insn().
| bool emu_mve_nocp_take | ( | void | ) |
Test and clear the "NoCP fault serviced by the MVE seam" latch.
uc_emu_start returns UC_ERR_EXCEPTION for a NoCP UsageFault even when the interrupt hook handled it completely, so the run loop cannot tell a serviced MVE access from a genuine unhandled exception by status alone. The seam sets this latch on every access it performs; the run loop consumes it at the chunk boundary and relaunches rather than ending the run as a fault.
| true | Relaunch from the advanced PC; the access already happened. |
| false | Nothing was serviced; treat the chunk status at face value. |
Test and clear the "NoCP fault serviced by the MVE seam" latch.
Definition at line 482 of file emu_seam_mve.c.
References s_mve_nocp_handled.
Referenced by internal_run_inner_take_exception().
| bool emulate_div0_patched | ( | uc_engine * | uc, |
| uint32_t | pc, | ||
| const uint8_t | code[4] ) |
Service an undefined-instruction trap that landed on an armed divide.
Called from the invalid-instruction dispatcher. When pc is a patched divide site this recovers the original encoding, reads the operands, and either (a) latches the pending div-0 fault when the divisor is zero and DIV_0_TRP is set – so the run loop synthesises the decoded UsageFault with pc stacked – or (b) computes the quotient in software, writes Rd and steps PC past the 4-byte instruction as a zero-time seam relaunch. A trap at any other address is not ours.
| [in,out] | uc | Unicorn engine. |
| [in] | pc | Address of the trapping instruction. |
| [in] | code | The 4 bytes at pc (the UDF, unused – the original encoding comes from the tracked sites). |
| true | pc was a patched divide; state (or the fault latch) was updated and the caller should stop + resume. |
| false | pc is not a patched divide; try the next handler. |
pc; else Rd and PC are advanced. Called from on_invalid_insn. Divide-by-zero trapping is modelled by overwriting each divide with UDF once the firmware sets CCR.DIV_0_TRP – unlike a per-site UC_HOOK_CODE this does NOT disable Unicorn's translation-block chaining, so a firmware that arms the trap runs its steady state at the baseline rate. When pc is one of those patched sites this recovers the original encoding, reads the operands, and either (a) latches s_div0_fault when the divisor is zero and DIV_0_TRP is set – so the run loop synthesises the decoded UsageFault with pc stacked – or (b) computes the quotient in software (internal_div0_quotient), writes Rd and steps PC past the 4-byte instruction. A trap at any other address is not ours.
| [in,out] | uc | Unicorn engine. |
| [in] | pc | Address of the trapping instruction. |
| [in] | code | The 4 bytes at pc (the UDF, unused – the original encoding comes from s_div0_site). |
| true | pc was a patched divide; register/PC state (or the fault latch) was updated and the caller should stop + resume. |
| false | pc is not a patched divide; try the next handler. |
pc; else Rd and PC are advanced. Definition at line 232 of file emu_seam_div0.c.
References emu_seam_request_relaunch(), div0_site_t::hw1, div0_site_t::hw2, internal_div0_quotient(), internal_udiv_sdiv_decode(), k_arm_reg_id, k_ccr_div_0_trp, k_div0_insn_len, k_scb_ccr, rd32(), s_div0_fault, s_div0_fault_pc, s_div0_site, and s_div0_site_n.
Referenced by internal_dispatch_insn_seam().
| bool emulate_long_shift_reg | ( | uc_engine * | uc, |
| uint32_t | pc, | ||
| const uint8_t | code[4] ) |
Emulate a register-form Armv8.1-M long shift (LSLL/ASRL) that trapped.
The register form (`lsll r0, r1, ip`) aliases to an ORR.W whose Rm field is SP, which the core refuses outright, so unlike the immediate form it arrives here as a genuine undefined-instruction trap rather than silently mis-executing. Decodes the site, applies the shift to the {RdaHi:RdaLo} pair with correct 64-bit host arithmetic – the amount is the SIGNED low byte of Rm, so a negative value shifts the other way – writes the pair back and advances PC past the 4-byte instruction. Flags are untouched because the aliased ORRS never executed.
| [in,out] | uc | Unicorn engine. |
| [in] | pc | Address of the trapping instruction. |
| [in] | code | The 4 instruction bytes at pc. |
code was a register-form long shift and was emulated. | true | Registers written and PC advanced; caller should stop+relaunch. |
| false | Not a register-form long shift; try the next handler. |
code holds the 4 bytes the core failed to decode at pc. uc is stopped inside the invalid-instruction hook. pc + 4 and the register pair holds the result. Definition at line 511 of file emu_seam_longshift.c.
References long_shift_insn_t::by_reg, internal_long_shift_amount(), internal_long_shift_apply(), internal_long_shift_decode(), k_arm_reg_id, k_byte_bits, k_lsh_insn_len, k_lsh_word_bits, long_shift_insn_t::op, long_shift_insn_t::rdahi, and long_shift_insn_t::rdalo.
Referenced by internal_dispatch_armv81_seam().
| bool emulate_mve | ( | uc_engine * | uc, |
| uint32_t | pc0, | ||
| const uint8_t | code0[4] ) |
Emulate a run of consecutive auto-vectoriser MVE instructions.
Helium ops come in tight back-to-back runs (e.g. one VMOV.I32 then several VSTRW.32 to zero a struct). Emulating only the first and relaunching would land the next launch on another invalid instruction, which Unicorn faults on – so this consumes every consecutive handled MVE op in one trap and sets PC to the first instruction it does NOT handle, exactly mirroring the cond-select seam's "stop, then relaunch on valid code" contract. Bounded.
| [in,out] | uc | Unicorn engine. |
| [in] | pc0 | Address of the trapped instruction. |
| [in] | code0 | The 4 instruction bytes already read at pc0. |
| false | code0 is not a handled MVE form (state untouched). |
code0 holds the 4 bytes at pc0. pc0. Helium ops come in tight back-to-back runs (e.g. one VMOV.I32 then several VSTRW.32 to zero a struct). Emulating only the first and relaunching would land the next launch on another invalid instruction, which Unicorn faults on – so this consumes every consecutive handled MVE op in one trap and sets PC to the first instruction it does NOT handle, exactly mirroring the cond-select seam's "stop, then relaunch on valid code" contract. Bounded by k_mve_max_run.
Definition at line 407 of file emu_seam_mve.c.
References emu_mem_read(), internal_mve_capstone(), internal_mve_exec_one(), internal_mve_mem_try(), k_mve_insn_len, k_mve_max_run, memcpy(), and s_mve_emulated.
Referenced by internal_dispatch_armv81_seam().
| void fast_sd_seam_install | ( | uc_engine * | uc, |
| const emu_elf_source_t * | elf ) |
Install the --fast-sd block-read hook if opted-in and the symbol exists.
| [in,out] | uc | Active Unicorn engine. |
| [in] | elf | Open ELF source used for symbol resolution. |
uc is initialised and elf remains open. Install the --fast-sd block-read hook if opted-in and the symbol exists; this step is contained within the emu seams model and uses bounded caller or module-owned storage.
| [in,out] | uc | Active Unicorn engine. |
| [in] | elf | Loaded ELF image (for symbol resolution). |
uc is initialised and elf is a validated loaded image. s_fast_sd and the symbol present, a UC_HOOK_CODE fires internal_on_sdmmc_read_block at the function entry; otherwise nothing is armed.Definition at line 124 of file emu_seam_sd.c.
References elf_sym_addr(), internal_on_sdmmc_read_block(), priv_emu_io_errf(), and s_fast_sd.
Referenced by internal_main_install_run_seams().
| void long_shift_seam_install | ( | uc_engine * | uc, |
| const emu_elf_source_t * | elf ) |
Scan the loaded image and install a hook at every immediate long-shift.
Walks the ELF32 PT_LOAD program headers, and for each executable segment scans its bytes on 2-byte boundaries for the LSLL/LSRL/ASRL encoding. A targeted UC_HOOK_CODE is installed at each site's VMA so the shift is applied on the host – where 64-bit arithmetic is correct – before the core silently mis-executes the overlapping ORR.W encoding. Matches use the segment's VMA (p_vaddr), so a .sram_text ramfunc region is hooked at its execution address even though it is not yet copied at install time. A scan false-positive is harmless: the core never starts execution there, so the hook never fires. Zero hooks – hence zero steady-state cost – for firmware that contains no long shifts.
| [in,out] | uc | Unicorn engine to install the hooks on. |
| [in] | elf | Open immutable ELF source. |
elf is a 32-bit ARM ELF (already validated by load_elf). Walks the ELF32 PT_LOAD program headers, and for each executable segment scans its bytes on 2-byte boundaries for the long-shift encoding (internal_long_shift_decode). A targeted UC_HOOK_CODE is installed at each site's VMA, and at the following instruction, so internal_on_long_shift can emulate it. Matches use the segment's VMA (p_vaddr), so a .sram_text ramfunc region is hooked at its execution address even though it is not yet copied at install time. A scan false-positive (a halfword pair inside data or mid-instruction that happens to match) is harmless: the core never starts execution there, so the hook never fires, and the seam never rewrites the image. Zero hooks – hence zero steady-state cost – for firmware that contains no long shifts.
| [in,out] | uc | Unicorn engine to install the hooks on. |
| [in] | elf | In-memory ELF image (still alive at call time). |
elf is a 32-bit ARM ELF (already validated by load_elf). Definition at line 675 of file emu_seam_longshift.c.
References elf_foreach_exec_segment(), internal_long_shift_segment(), memset(), priv_emu_io_errf(), s_lsh_pending, and s_lsh_site_count.
Referenced by internal_main_install_run_seams().
| bool on_invalid_insn | ( | uc_engine * | uc, |
| void * | user ) |
UC_HOOK_INSN_INVALID dispatcher: service or report a trapped opcode.
Tries each trap-path seam in a fixed order – the armed div-0 UDF service first (it matches only exact patched addresses), then the Armv8-M security scrubs, the conditional-select family, the barrier NOPs, the MVE run consumer and the low-overhead-branch loops. A handled seam edits PC and stops the engine (the run loop relaunches on valid code); anything else is disassembled and reported, then the engine stops with the invalid-opcode error.
| [in,out] | uc | Unicorn engine at the trapped instruction. |
| [in] | user | Hook user pointer (unused; Unicorn ABI). |
| true | PC advanced past the emulated instruction; engine stopped. |
| false | Genuinely invalid: report printed, emulation errors out. |
UC_HOOK_INSN_INVALID dispatcher: service or report a trapped opcode.
Definition at line 560 of file emu_insn_seams.c.
References emu_mem_read(), emu_mve_nocp_spurious(), internal_dispatch_insn_seam(), and internal_report_unhandled_insn().
Referenced by emu_insn_seams_install().