diff options
| author | Alexander Taylor <alex@vector35.com> | 2026-03-07 13:12:06 -0500 |
|---|---|---|
| committer | Alexander Taylor <alex@vector35.com> | 2026-04-15 14:56:32 -0400 |
| commit | 20b99b72d2bda9504d12f11d24bc07f95b41d048 (patch) | |
| tree | a6980da58d549d73c338cfca09a9dfd09ce3200f /arch | |
| parent | a184a2a04f0203dd1f597cdb248afa67dcf951b3 (diff) | |
RISC-V: Special handling for 0000 (trap).
Some compilers will stick 0000 (an invalid instruction) after jumps or
calls in a noreturn function, which we lifted as an invalid instruction.
If our analysis didn't catch that the function is noreturn, it would
trigger guided analysis mode for these functions due to the invalid
instruction. This is a workaround that we've applied to x86 and aarch64
as well.
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/riscv/src/lib.rs | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 1f822524..2bc0427c 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -637,6 +637,20 @@ struct RiscVArch<D: RiscVDisassembler> { _dis: PhantomData<D>, } +impl<D: RiscVDisassembler> RiscVArch<D> { + fn decode_zero(data: &[u8]) -> Option<usize> { + if <D::CompressedExtension as riscv_dis::StandardExtension>::supported() + && data.len() >= 2 + && data[0] == 0 + && data[1] == 0 + { + Some(2) + } else { + None + } + } +} + impl<D: RiscVDisassembler> Architecture for RiscVArch<D> { type Handle = CustomArchitectureHandle<Self>; @@ -687,6 +701,14 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> { } fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo> { + // Special handling for 0000, which is often used by compilers + // after jumps/calls in noreturn functions to trap execution + if let Some(inst_len) = Self::decode_zero(data) { + let mut res = InstructionInfo::new(inst_len, 0); + res.add_branch(BranchKind::Unresolved); + return Some(res); + } + let (inst_len, op) = match D::decode(addr, data) { Ok(Instr::Rv16(op)) => (2, op), Ok(Instr::Rv32(op)) => (4, op), @@ -752,6 +774,15 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> { use riscv_dis::Operand; use InstructionTextTokenKind::*; + // Special handling for 0000, which is often used by compilers + // after jumps/calls in noreturn functions to trap execution + if let Some(inst_len) = Self::decode_zero(data) { + return Some(( + inst_len, + vec![InstructionTextToken::new("trap", Instruction)], + )); + } + let inst = match D::decode(addr, data) { Ok(i) => i, _ => return None, @@ -1065,6 +1096,13 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> { addr: u64, il: &LowLevelILMutableFunction, ) -> Option<(usize, bool)> { + // Special handling for 0000, which is often used by compilers + // after jumps/calls in noreturn functions to trap execution + if let Some(inst_len) = Self::decode_zero(data) { + il.trap(0).append(); + return Some((inst_len, true)); + } + let max_width = self.default_integer_size(); let (inst_len, op) = match D::decode(addr, data) { |
