139 if ((out_rn ==
nullptr) || (out_rd ==
nullptr) || (out_rm ==
nullptr) ||
140 (out_signed ==
nullptr)) {
145 if (!is_udiv && !is_sdiv) {
165 *out_signed = is_sdiv;
198 return (uint32_t)((int32_t)vn / (int32_t)vm);
242 if (site ==
nullptr) {
265 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
310 (void)
priv_emu_io_errf(
" div-0 seam: CCR.DIV_0_TRP set -- patched %u UDIV/SDIV site(s)\n",
343 k_div0_scan_scratch = 4096U,
345 uint8_t bytes[k_div0_scan_scratch];
348 const uint32_t left = seg->
filesz - base;
349 const size_t length = (left <
sizeof(bytes)) ? (
size_t)left :
sizeof(bytes);
352 (uint64_t)seg->
offset + base,
360 for (
size_t local = 0U; (local +
k_div0_insn_len) <= length; local += 2U) {
361 const uint8_t* p = &bytes[local];
362 const uint16_t hw1 = (uint16_t)(p[0] | ((uint16_t)p[1] << 8));
363 const uint16_t hw2 = (uint16_t)(p[2] | ((uint16_t)p[3] << 8));
376 (
div0_site_t){.va = seg->
vaddr + base + (uint32_t)local, .hw1 = hw1, .hw2 = hw2};
379 if (length == left) {
382 base += (uint32_t)length - 2U;
417 (void)
priv_emu_io_errf(
" div-0 seam: %u UDIV/SDIV site(s) tracked; armed on CCR.DIV_0_TRP\n",
453 (void)uc_reg_write(uc, UC_ARM_REG_PC, &fault_pc);
ELF32 image services for the board emulator (load / symbols / vectors).
uint32_t elf_foreach_exec_segment(const emu_elf_source_t *elf, elf_exec_segment_fn fn, void *ctx)
Walk every executable PT_LOAD segment of an ELF32 image.
@ k_emu_elf_io_ok
The complete operation succeeded.
Private raw-descriptor ELF source operations.
emu_elf_io_result_t priv_emu_elf_read(const emu_elf_source_t *source, uint64_t offset, size_t required_bytes, void *scratch, size_t supplied_bytes, emu_elf_view_t *view)
Read one exact source range into caller-owned bounded scratch.
Shared Unicorn engine access utilities for the board emulator.
void emu_seam_request_relaunch(void)
Mark the pending engine stop as a zero-time seam relaunch.
static uint32_t rd32(uc_engine *uc, uint64_t addr)
Read a 32-bit little-endian word from emulated memory.
const int k_arm_reg_id[16]
ARM register index (0..15) -> Unicorn register id.
static void wr32(uc_engine *uc, uint64_t addr, uint32_t v)
Write a 32-bit little-endian word to emulated memory.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_scb_cfsr
Config Fault Status (MMFSR low byte).
@ k_scb_ccr
Configuration and Control (CCR).
@ k_ccr_div_0_trp
CCR.DIV_0_TRP bit4: divide-by-0 traps.
@ k_exc_usagefault
UsageFault exception / vector index.
uint32_t exc_vector(uc_engine *uc, uint32_t vtor_base, uint32_t exc_num)
Read the handler address for an exception from the vector table.
void exc_enter(uc_engine *uc, uint32_t exc_num, uint32_t handler)
Enter a Cortex-M exception: stack the basic frame and vector in.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
static RA8_INTERNAL bool internal_udiv_sdiv_decode(uint16_t hw1, uint16_t hw2, uint32_t *out_rn, uint32_t *out_rd, uint32_t *out_rm, bool *out_signed)
Decode a Thumb-2 halfword pair as UDIV/SDIV, recovering all operands.
static bool s_div0_armed
Armed sites overwritten UDF.
bool emu_div0_fault_pending(void)
Implementation of emu_div0_fault_pending() – plain flag read.
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 emu_div0_count_trap(void)
Implementation of emu_div0_count_trap() – run-end telemetry bump.
void div0_synth_usagefault(uc_engine *uc, uint32_t vtor_base)
Synthesise a UsageFault (#6) for a trapped divide-by-zero.
void emu_div0_clear_fault(void)
Implementation of emu_div0_clear_fault() – plain flag clear.
void emu_div0_disarm(void)
Implementation of emu_div0_disarm() – warm reboot un-patches sites.
@ k_div0_sites_max
Div0 sites maximum.
uint32_t emu_div0_fault_pc(void)
Implementation of emu_div0_fault_pc() – plain state read.
static bool s_div0_fault
Trapping div-0 latched (the run loop synthesises the UsageFault).
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.
static RA8_INTERNAL bool internal_div0_scan_segment(const elf_exec_segment_t *seg, void *ctx)
Record every UDIV/SDIV site in one executable segment.
static uint32_t s_div0_site_n
Count of tracked sites.
void div0_patch_sites(uc_engine *uc)
Overwrite every tracked divide with UDF so divide-by-zero can trap.
static uint32_t s_div0_fault_pc
PC of the divide that trapped (stacked by the synthesised fault).
static uint64_t s_div0_traps
Count of divide-by-zero UsageFaults synthesised this run.
static div0_site_t s_div0_site[k_div0_sites_max]
Tracked divide sites.
static const uint8_t s_k_div0_udf[k_div0_insn_len]
UDF.W #0 – a permanently-undefined 32-bit Thumb-2 instruction (LE bytes).
static RA8_INTERNAL uint32_t internal_div0_quotient(uint32_t vn, uint32_t vm, bool is_signed)
Compute a UDIV/SDIV quotient with the Arm div-by-zero + overflow rules.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
@ k_div0_hw2_mask
hw2[15:12] and hw2[7:4] must be 1111.
@ k_div0_cfsr_divzero
CFSR.UFSR.DIVBYZERO (0x02000000).
@ k_div0_insn_len
UDIV/SDIV are 32-bit Thumb-2.
@ k_div0_udf_b0
UDF.W #0 little-endian byte 0.
@ k_div0_udf_b1
UDF.W #0 little-endian byte 1.
@ k_div0_hw1_udiv
UDIV T1: hw1[15:4] == 0xFBB.
@ k_div0_rd_shift
hw2[11:8] = Rd (destination register).
@ k_div0_hw1_sdiv
SDIV T1: hw1[15:4] == 0xFB9.
@ k_div0_reg_sp
r13 (SP): UNPREDICTABLE as UDIV d/n/m.
@ k_div0_int32_min
INT32_MIN: the SDIV / -1 overflow edge.
@ k_div0_hw1_mask
hw1[15:4] selects the divide opcode.
@ k_div0_reg_pc
r15 (PC): UNPREDICTABLE as UDIV d/n/m.
@ k_div0_reg_mask
4-bit register field (Rn / Rm / Rd).
@ k_div0_udf_b3
UDF.W #0 little-endian byte 3.
@ k_div0_hw2_fixed
Their required value for a real divide.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One tracked UDIV/SDIV site: its address and original encoding halfwords.
uint32_t va
Divide-instruction virtual address.
uint16_t hw2
Original second halfword.
uint16_t hw1
Original first halfword.
One executable PT_LOAD segment, already bounds-checked against the image.
uint32_t offset
Segment file offset.
uint32_t filesz
Segment file byte count.
const emu_elf_source_t * source
Open source owning segment bytes.
uint32_t vaddr
Segment virtual address.
emu_elf_io_status_t status
Semantic completion status.
One independently owned immutable raw-descriptor ELF source.
Transient view into caller-owned bounded scratch.