87typedef enum : uint32_t {
233 return (int32_t)insn->
imm;
241 return (int32_t)byte;
271 left = (left != 0U) ? 0U : 1U;
278 return arith ? (uint64_t)((int64_t)val >> ((int32_t)
k_lsh_pair_bits - 1)) : 0U;
281 return val << (uint32_t)n;
283 return arith ? (uint64_t)((int64_t)val >> (uint32_t)n) : (val >> (uint32_t)n);
421 if (
emu_mem_read(uc, address, code,
sizeof(code)) != UC_ERR_OK) {
424 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << (uint16_t)
k_byte_bits));
425 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << (uint16_t)
k_byte_bits));
434 const uint64_t val = ((uint64_t)hi << (uint64_t)
k_lsh_word_bits) | (uint64_t)lo;
438 (void)uc_reg_read(uc, UC_ARM_REG_APSR_NZCV, &nzcv);
441 if (slot ==
nullptr) {
480 (void)uc_reg_write(uc, UC_ARM_REG_APSR_NZCV, &slot->
nzcv);
501 const uint32_t pc = (uint32_t)address;
503 if (slot !=
nullptr) {
513 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << (uint16_t)
k_byte_bits));
514 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << (uint16_t)
k_byte_bits));
523 const uint64_t val = ((uint64_t)hi << (uint64_t)
k_lsh_word_bits) | (uint64_t)lo;
531 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
559 const uint8_t* bytes,
563 for (
size_t off = 0U; (off +
k_lsh_insn_len) <= length; off += 2U) {
564 const uint8_t* p = &bytes[off];
565 const uint16_t hw1 = (uint16_t)(p[0] | ((uint16_t)p[1] << (uint16_t)
k_byte_bits));
566 const uint16_t hw2 = (uint16_t)(p[2] | ((uint16_t)p[3] << (uint16_t)
k_byte_bits));
583 const uint64_t va = (uint64_t)vaddr + off;
587 (void)uc_hook_add(scan->uc,
594 (void)uc_hook_add(scan->uc,
625 k_lsh_scan_scratch = 4096U,
628 uint8_t bytes[k_lsh_scan_scratch];
631 const uint32_t left = segment->
filesz - base;
632 const size_t length = (left <
sizeof(bytes)) ? (
size_t)left :
sizeof(bytes);
635 (uint64_t)segment->
offset + base,
644 if (length == left) {
647 base += (uint32_t)length - 2U;
677 if (elf ==
nullptr) {
684 if (scan.n_hooks > 0U) {
685 (void)
priv_emu_io_errf(
" long-shift seam: emulating %u Armv8.1-M LSLL/LSRL/ASRL site(s)\n",
686 (
unsigned)scan.n_hooks);
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.
const int k_arm_reg_id[16]
ARM register index (0..15) -> Unicorn register id.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_lo4_mask
Low nibble (register / cond field).
@ k_byte_bits
Bits per byte (SHPR field width).
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_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
@ k_lsh_hw1_sat_bit
hw1[0]: 1 = saturating/rounding subfamily.
@ k_lsh_tail_reg
hw2[3:0] == 0b1101 -> register form.
@ k_lsh_rdahi_wide
RdaHi == 0b1111 -> 32-bit form, rejected.
@ k_lsh_imm3_to_imm5
imm5 = (imm3 << 2) | imm2.
@ k_lsh_tail_imm
hw2[3:0] == 0b1111 -> immediate form.
@ k_lsh_imm2_mask
imm2 width.
@ k_lsh_hw1_mask
hw1[15:4] selects the group.
@ k_lsh_insn_len
Thumb-2 instruction length, bytes.
@ k_lsh_amount_mask
Register form uses Rm[7:0] as the amount.
@ k_lsh_imm3_shift
imm3 at hw2[14:12].
@ k_lsh_hw1_match
hw1[15:4] == 0xEA5 for this family.
@ k_lsh_hw2_lo_mask
hw2[3:0] selects immediate vs register form.
@ k_lsh_reg_zero_msk
hw2[7:6] must be zero in the register form.
@ k_lsh_op_lsll
00: 64-bit logical shift left.
@ k_lsh_imm2_shift
imm2 at hw2[7:6].
@ k_lsh_word_bits
Word width; also the imm5==0 shift amount.
@ k_lsh_op_asrl
10: 64-bit arithmetic shift right.
@ k_lsh_rm_shift
Rm at hw2[15:12] in the register form.
@ k_lsh_op_lsrl
01: 64-bit logical shift right.
@ k_lsh_pair_bits
Width of the {RdaHi:RdaLo} pair, bits.
@ k_lsh_amount_sign
Sign bit of the 8-bit shift amount.
@ k_lsh_op_shift
op field at hw2[5:4].
@ k_lsh_imm3_mask
imm3 width.
@ k_lsh_amount_wrap
Rm[7:0] is signed: subtract to go negative.
@ k_lsh_op_mask
op width (value 3 is reserved -> rejected).
@ k_lsh_rdalo_mask
RdaLo at hw1[3:1] (an even register).
@ k_lsh_rdahi_shift
RdaHi at hw2[11:8].
static uint32_t s_lsh_site_count
Number of valid entries in s_lsh_sites.
static RA8_INTERNAL void internal_on_long_shift(uc_engine *uc, uint64_t address, uint32_t size, void *user)
Perform on long shift for the emu seam longshift model.
static uc_hook s_lsh_hooks[k_lsh_hooks_max]
Hook handles for the installed sites (kept alive for the whole run).
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.
static RA8_INTERNAL bool internal_long_shift_segment(const elf_exec_segment_t *segment, void *opaque)
Stream and scan one executable segment through bounded scratch.
static RA8_INTERNAL int32_t internal_long_shift_amount(uc_engine *uc, const long_shift_insn_t *insn)
Resolve the shift amount of a decoded long shift, in bits.
static RA8_INTERNAL uint64_t internal_long_shift_apply(uint64_t val, uint32_t op, int32_t shift)
Apply one long shift to a 64-bit value with correct host arithmetic.
static long_shift_pending_t s_lsh_pending[k_lsh_pending_max]
Outstanding long-shift write-backs (see long_shift_pending_t).
static RA8_INTERNAL bool internal_install_seg_hooks(long_shift_scan_t *scan, const uint8_t *bytes, size_t length, uint32_t vaddr)
Scan one transient segment chunk and arm long-shift hooks.
@ k_lsh_sites_max
Lsh sites maximum.
@ k_lsh_hooks_max
Two hooks per site: the site and its tail.
static uint32_t s_lsh_sites[k_lsh_sites_max]
Execution addresses of every immediate long shift found in the image.
static RA8_INTERNAL long_shift_pending_t * internal_long_shift_slot(uint32_t at, bool want_active)
Find the pending write-back slot for at, or a free slot.
static RA8_INTERNAL bool internal_long_shift_is_site(uint32_t addr)
Report whether addr is a long-shift site found by the image scan.
@ k_lsh_pending_max
Lsh pending maximum.
static RA8_INTERNAL void internal_long_shift_commit(uc_engine *uc, long_shift_pending_t *slot)
Write back the staged long-shift result over the ORRS's damage.
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.
static RA8_INTERNAL bool internal_long_shift_decode(uint16_t hw1, uint16_t hw2, long_shift_insn_t *out)
Decode an Armv8.1-M long shift (LSLL/LSRL/ASRL), immediate or register.
static RA8_INTERNAL void internal_long_shift_begin(uc_engine *uc, uint32_t address)
Compute one long shift on the host and stage it for write-back.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
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.
One decoded immediate-or-register Armv8.1-M long shift.
uint32_t imm
Shift amount 1..32 (immediate form only).
uint32_t rdahi
High destination register index.
uint32_t rdalo
Low destination register index (even).
uint32_t op
k_lsh_op_lsll / _lsrl / _asrl.
bool by_reg
true when the amount comes from rm.
uint32_t rm
Register holding the amount (register form only).
The correct result of one long shift, awaiting write-back.
uint32_t at
Address of the instruction after the long shift.
uint32_t rdalo
Low destination register index.
uint32_t lo
Correct low word of the shifted 64-bit value.
uint32_t rdahi
High destination register index.
uint32_t nzcv
NZCV as it stood before the ORRS overwrote it.
uint32_t hi
Correct high word of the shifted 64-bit value.
bool active
A captured result is waiting to be written back.
Engine and bounded installed-hook count for a streamed scan.
uc_engine * uc
Engine receiving targeted hooks.
uint32_t n_hooks
Running installed-site count.