Skip to content

Commit 20b99b7

Browse files
committed
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.
1 parent a184a2a commit 20b99b7

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

arch/riscv/src/lib.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,20 @@ struct RiscVArch<D: RiscVDisassembler> {
637637
_dis: PhantomData<D>,
638638
}
639639

640+
impl<D: RiscVDisassembler> RiscVArch<D> {
641+
fn decode_zero(data: &[u8]) -> Option<usize> {
642+
if <D::CompressedExtension as riscv_dis::StandardExtension>::supported()
643+
&& data.len() >= 2
644+
&& data[0] == 0
645+
&& data[1] == 0
646+
{
647+
Some(2)
648+
} else {
649+
None
650+
}
651+
}
652+
}
653+
640654
impl<D: RiscVDisassembler> Architecture for RiscVArch<D> {
641655
type Handle = CustomArchitectureHandle<Self>;
642656

@@ -687,6 +701,14 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> {
687701
}
688702

689703
fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo> {
704+
// Special handling for 0000, which is often used by compilers
705+
// after jumps/calls in noreturn functions to trap execution
706+
if let Some(inst_len) = Self::decode_zero(data) {
707+
let mut res = InstructionInfo::new(inst_len, 0);
708+
res.add_branch(BranchKind::Unresolved);
709+
return Some(res);
710+
}
711+
690712
let (inst_len, op) = match D::decode(addr, data) {
691713
Ok(Instr::Rv16(op)) => (2, op),
692714
Ok(Instr::Rv32(op)) => (4, op),
@@ -752,6 +774,15 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> {
752774
use riscv_dis::Operand;
753775
use InstructionTextTokenKind::*;
754776

777+
// Special handling for 0000, which is often used by compilers
778+
// after jumps/calls in noreturn functions to trap execution
779+
if let Some(inst_len) = Self::decode_zero(data) {
780+
return Some((
781+
inst_len,
782+
vec![InstructionTextToken::new("trap", Instruction)],
783+
));
784+
}
785+
755786
let inst = match D::decode(addr, data) {
756787
Ok(i) => i,
757788
_ => return None,
@@ -1065,6 +1096,13 @@ impl<D: RiscVDisassembler> Architecture for RiscVArch<D> {
10651096
addr: u64,
10661097
il: &LowLevelILMutableFunction,
10671098
) -> Option<(usize, bool)> {
1099+
// Special handling for 0000, which is often used by compilers
1100+
// after jumps/calls in noreturn functions to trap execution
1101+
if let Some(inst_len) = Self::decode_zero(data) {
1102+
il.trap(0).append();
1103+
return Some((inst_len, true));
1104+
}
1105+
10681106
let max_width = self.default_integer_size();
10691107

10701108
let (inst_len, op) = match D::decode(addr, data) {

0 commit comments

Comments
 (0)