summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlexander Taylor <alex@vector35.com>2026-03-07 13:12:06 -0500
committerAlexander Taylor <alex@vector35.com>2026-04-15 14:56:32 -0400
commit20b99b72d2bda9504d12f11d24bc07f95b41d048 (patch)
treea6980da58d549d73c338cfca09a9dfd09ce3200f /arch
parenta184a2a04f0203dd1f597cdb248afa67dcf951b3 (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.rs38
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) {