From 89f3b0a363ebf663a612db54af14bf68563eb545 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 7 Mar 2026 13:12:06 -0500 Subject: [PATCH] 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. --- arch/riscv/src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 1f822524d..2bc0427c3 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -637,6 +637,20 @@ struct RiscVArch { _dis: PhantomData, } +impl RiscVArch { + fn decode_zero(data: &[u8]) -> Option { + if ::supported() + && data.len() >= 2 + && data[0] == 0 + && data[1] == 0 + { + Some(2) + } else { + None + } + } +} + impl Architecture for RiscVArch { type Handle = CustomArchitectureHandle; @@ -687,6 +701,14 @@ impl Architecture for RiscVArch { } fn instruction_info(&self, data: &[u8], addr: u64) -> Option { + // 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 Architecture for RiscVArch { 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 Architecture for RiscVArch { 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) {