lint: apply cargo fmt
This commit is contained in:
parent
e9858a3eb9
commit
3e7f0e61df
5 changed files with 417 additions and 96 deletions
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
pub mod arm;
|
||||
|
||||
use crate::{
|
||||
flow::FlowInfo,
|
||||
ir::Block,
|
||||
};
|
||||
use crate::{flow::FlowInfo, ir::Block};
|
||||
|
||||
/// Flat generic register metadata.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
|||
416
src/arch/arm.rs
416
src/arch/arm.rs
|
|
@ -47,7 +47,13 @@ pub struct ArmFeatures {
|
|||
|
||||
impl Default for ArmFeatures {
|
||||
fn default() -> Self {
|
||||
Self { version: ArmVersion::V7, thumb2: true, vfp: false, neon: false, dsp: false }
|
||||
Self {
|
||||
version: ArmVersion::V7,
|
||||
thumb2: true,
|
||||
vfp: false,
|
||||
neon: false,
|
||||
dsp: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +149,13 @@ impl<'ir, 'fb> ArmLiftCtx<'ir, 'fb> {
|
|||
for flag in [ArmFlag::N, ArmFlag::Z, ArmFlag::C, ArmFlag::V, ArmFlag::Q] {
|
||||
fb.declare_var(Self::flag_var(flag), Type::bool());
|
||||
}
|
||||
Self { arch, env, fb, pc, mode }
|
||||
Self {
|
||||
arch,
|
||||
env,
|
||||
fb,
|
||||
pc,
|
||||
mode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn word_ty(&self) -> Type {
|
||||
|
|
@ -184,22 +196,86 @@ impl<'ir, 'fb> ArmLiftCtx<'ir, 'fb> {
|
|||
}
|
||||
|
||||
pub const REGISTERS: [RegisterDesc<ArmReg>; 16] = [
|
||||
RegisterDesc { reg: ArmReg::R0, name: "r0", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R1, name: "r1", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R2, name: "r2", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R3, name: "r3", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R4, name: "r4", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R5, name: "r5", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R6, name: "r6", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R7, name: "r7", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R8, name: "r8", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R9, name: "r9", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R10, name: "r10", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R11, name: "r11", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::R12, name: "r12", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::Sp, name: "sp", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::Lr, name: "lr", bits: 32 },
|
||||
RegisterDesc { reg: ArmReg::Pc, name: "pc", bits: 32 },
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R0,
|
||||
name: "r0",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R1,
|
||||
name: "r1",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R2,
|
||||
name: "r2",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R3,
|
||||
name: "r3",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R4,
|
||||
name: "r4",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R5,
|
||||
name: "r5",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R6,
|
||||
name: "r6",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R7,
|
||||
name: "r7",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R8,
|
||||
name: "r8",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R9,
|
||||
name: "r9",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R10,
|
||||
name: "r10",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R11,
|
||||
name: "r11",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::R12,
|
||||
name: "r12",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::Sp,
|
||||
name: "sp",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::Lr,
|
||||
name: "lr",
|
||||
bits: 32,
|
||||
},
|
||||
RegisterDesc {
|
||||
reg: ArmReg::Pc,
|
||||
name: "pc",
|
||||
bits: 32,
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
@ -218,39 +294,52 @@ pub enum ArmLiftError {
|
|||
/// Map a 4-bit register index to `ArmReg`.
|
||||
const fn reg_of(r: u8) -> ArmReg {
|
||||
match r & 0xF {
|
||||
0 => ArmReg::R0, 1 => ArmReg::R1, 2 => ArmReg::R2, 3 => ArmReg::R3,
|
||||
4 => ArmReg::R4, 5 => ArmReg::R5, 6 => ArmReg::R6, 7 => ArmReg::R7,
|
||||
8 => ArmReg::R8, 9 => ArmReg::R9, 10 => ArmReg::R10, 11 => ArmReg::R11,
|
||||
12 => ArmReg::R12, 13 => ArmReg::Sp, 14 => ArmReg::Lr, _ => ArmReg::Pc,
|
||||
0 => ArmReg::R0,
|
||||
1 => ArmReg::R1,
|
||||
2 => ArmReg::R2,
|
||||
3 => ArmReg::R3,
|
||||
4 => ArmReg::R4,
|
||||
5 => ArmReg::R5,
|
||||
6 => ArmReg::R6,
|
||||
7 => ArmReg::R7,
|
||||
8 => ArmReg::R8,
|
||||
9 => ArmReg::R9,
|
||||
10 => ArmReg::R10,
|
||||
11 => ArmReg::R11,
|
||||
12 => ArmReg::R12,
|
||||
13 => ArmReg::Sp,
|
||||
14 => ArmReg::Lr,
|
||||
_ => ArmReg::Pc,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a boolean condition value from a 4-bit ARM condition code.
|
||||
/// Returns `Ok(None)` for AL (always / unconditional).
|
||||
fn cond_value(
|
||||
cx: &mut ArmLiftCtx<'_, '_>,
|
||||
cond: u8,
|
||||
) -> Result<Option<Value>, ArmLiftError> {
|
||||
fn cond_value(cx: &mut ArmLiftCtx<'_, '_>, cond: u8) -> Result<Option<Value>, ArmLiftError> {
|
||||
match cond & 0xF {
|
||||
0xE => Ok(None), // AL
|
||||
|
||||
0x0 => Ok(Some(cx.read_flag(ArmFlag::Z))), // EQ: Z=1
|
||||
|
||||
0x1 => { // NE: Z=0
|
||||
0x1 => {
|
||||
// NE: Z=0
|
||||
let z = cx.read_flag(ArmFlag::Z);
|
||||
Ok(Some(cx.fb.not(z)))
|
||||
}
|
||||
|
||||
0xB => { // LT: N != V — placeholder using N alone
|
||||
0xB => {
|
||||
// LT: N != V — placeholder using N alone
|
||||
Ok(Some(cx.read_flag(ArmFlag::N)))
|
||||
}
|
||||
|
||||
0xA => { // GE: N == V — placeholder using !N alone
|
||||
0xA => {
|
||||
// GE: N == V — placeholder using !N alone
|
||||
let n = cx.read_flag(ArmFlag::N);
|
||||
Ok(Some(cx.fb.not(n)))
|
||||
}
|
||||
|
||||
0xC => { // GT: Z=0 and N==V — placeholder using Z=0 and N=0
|
||||
0xC => {
|
||||
// GT: Z=0 and N==V — placeholder using Z=0 and N=0
|
||||
let z = cx.read_flag(ArmFlag::Z);
|
||||
let n = cx.read_flag(ArmFlag::N);
|
||||
let not_z = cx.fb.not(z);
|
||||
|
|
@ -258,7 +347,8 @@ fn cond_value(
|
|||
Ok(Some(cx.fb.and(not_z, not_n, Type::bool())))
|
||||
}
|
||||
|
||||
0xD => { // LE: Z=1 or N!=V — placeholder using Z=1 or N=1
|
||||
0xD => {
|
||||
// LE: Z=1 or N!=V — placeholder using Z=1 or N=1
|
||||
let z = cx.read_flag(ArmFlag::Z);
|
||||
let n = cx.read_flag(ArmFlag::N);
|
||||
Ok(Some(cx.fb.or(z, n, Type::bool())))
|
||||
|
|
@ -281,9 +371,9 @@ fn apply_shift_imm(
|
|||
}
|
||||
let amt = cx.fb.iconst(Type::i32(), imm5 as i64);
|
||||
Ok(match stype & 3 {
|
||||
0 => cx.fb.shl(base, amt, Type::i32()), // LSL
|
||||
1 => cx.fb.lshr(base, amt, Type::i32()), // LSR
|
||||
2 => cx.fb.ashr(base, amt, Type::i32()), // ASR
|
||||
0 => cx.fb.shl(base, amt, Type::i32()), // LSL
|
||||
1 => cx.fb.lshr(base, amt, Type::i32()), // LSR
|
||||
2 => cx.fb.ashr(base, amt, Type::i32()), // ASR
|
||||
_ => return Err(ArmLiftError::UnsupportedInstruction), // ROR
|
||||
})
|
||||
}
|
||||
|
|
@ -295,18 +385,30 @@ fn addr_imm_off(cx: &mut ArmLiftCtx<'_, '_>, rn: u8, u: bool, imm12: u16) -> Val
|
|||
return base;
|
||||
}
|
||||
let off = cx.fb.iconst(Type::i32(), imm12 as i64);
|
||||
if u { cx.fb.iadd(base, off, Type::i32()) } else { cx.fb.isub(base, off, Type::i32()) }
|
||||
if u {
|
||||
cx.fb.iadd(base, off, Type::i32())
|
||||
} else {
|
||||
cx.fb.isub(base, off, Type::i32())
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the effective address for an offset-form LDR/STR: base ± shifted rm.
|
||||
fn addr_reg_off(
|
||||
cx: &mut ArmLiftCtx<'_, '_>,
|
||||
rn: u8, u: bool, rm: u8, stype: u8, imm5: u8,
|
||||
rn: u8,
|
||||
u: bool,
|
||||
rm: u8,
|
||||
stype: u8,
|
||||
imm5: u8,
|
||||
) -> Result<Value, ArmLiftError> {
|
||||
let base = cx.read_reg(reg_of(rn));
|
||||
let idx_raw = cx.read_reg(reg_of(rm));
|
||||
let idx = apply_shift_imm(cx, idx_raw, stype, imm5)?;
|
||||
Ok(if u { cx.fb.iadd(base, idx, Type::i32()) } else { cx.fb.isub(base, idx, Type::i32()) })
|
||||
Ok(if u {
|
||||
cx.fb.iadd(base, idx, Type::i32())
|
||||
} else {
|
||||
cx.fb.isub(base, idx, Type::i32())
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -319,11 +421,21 @@ impl Arch for Arm {
|
|||
type Reg = ArmReg;
|
||||
type DecodeError = A32DecodeError;
|
||||
|
||||
fn name(&self) -> &'static str { "arm" }
|
||||
fn address_size(&self, _mode: Self::Mode) -> u8 { 4 }
|
||||
fn max_instruction_len(&self) -> u8 { 4 }
|
||||
fn registers(&self) -> &'static [RegisterDesc<Self::Reg>] { ®ISTERS }
|
||||
fn stack_pointer(&self) -> Option<Self::Reg> { Some(ArmReg::Sp) }
|
||||
fn name(&self) -> &'static str {
|
||||
"arm"
|
||||
}
|
||||
fn address_size(&self, _mode: Self::Mode) -> u8 {
|
||||
4
|
||||
}
|
||||
fn max_instruction_len(&self) -> u8 {
|
||||
4
|
||||
}
|
||||
fn registers(&self) -> &'static [RegisterDesc<Self::Reg>] {
|
||||
®ISTERS
|
||||
}
|
||||
fn stack_pointer(&self) -> Option<Self::Reg> {
|
||||
Some(ArmReg::Sp)
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
|
|
@ -339,7 +451,8 @@ impl Arch for Arm {
|
|||
fn flow_info(&self, inst: &Self::Inst, pc: u64, _mode: Self::Mode) -> FlowInfo {
|
||||
// PC-relative branch offset: target = PC + 8 + (imm24 sign-extended << 2)
|
||||
let branch_target = |imm24: u32| -> u64 {
|
||||
pc.wrapping_add(8).wrapping_add_signed(a32_branch_offset(imm24) as i64)
|
||||
pc.wrapping_add(8)
|
||||
.wrapping_add_signed(a32_branch_offset(imm24) as i64)
|
||||
};
|
||||
|
||||
match inst {
|
||||
|
|
@ -347,13 +460,22 @@ impl Arch for Arm {
|
|||
if *rm == 14 {
|
||||
FlowInfo::new(4, FlowKind::Return)
|
||||
} else {
|
||||
FlowInfo::new(4, FlowKind::Jump { target: FlowTarget::Indirect })
|
||||
FlowInfo::new(
|
||||
4,
|
||||
FlowKind::Jump {
|
||||
target: FlowTarget::Indirect,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
A32Inst::BlxRA1 { .. } => {
|
||||
FlowInfo::new(4, FlowKind::Call { target: FlowTarget::Indirect, returns: true })
|
||||
}
|
||||
A32Inst::BlxRA1 { .. } => FlowInfo::new(
|
||||
4,
|
||||
FlowKind::Call {
|
||||
target: FlowTarget::Indirect,
|
||||
returns: true,
|
||||
},
|
||||
),
|
||||
|
||||
A32Inst::BA1 { cond, imm24 } => {
|
||||
let target = FlowTarget::Direct(branch_target(*imm24));
|
||||
|
|
@ -366,7 +488,13 @@ impl Arch for Arm {
|
|||
|
||||
A32Inst::BlIA1 { imm24, .. } => {
|
||||
let target = FlowTarget::Direct(branch_target(*imm24));
|
||||
FlowInfo::new(4, FlowKind::Call { target, returns: true })
|
||||
FlowInfo::new(
|
||||
4,
|
||||
FlowKind::Call {
|
||||
target,
|
||||
returns: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
_ => FlowInfo::new(4, FlowKind::FallThrough),
|
||||
|
|
@ -384,7 +512,8 @@ impl Arch for Arm {
|
|||
|
||||
impl LiftArch for Arm {
|
||||
type LiftError = ArmLiftError;
|
||||
type LiftCtx<'ir, 'fb> = ArmLiftCtx<'ir, 'fb>
|
||||
type LiftCtx<'ir, 'fb>
|
||||
= ArmLiftCtx<'ir, 'fb>
|
||||
where
|
||||
Self: 'ir,
|
||||
'ir: 'fb;
|
||||
|
|
@ -415,7 +544,12 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// MOV wide immediate (MOVW)
|
||||
A32Inst::MovIA2 { cond, rd, imm12, imm4 } => {
|
||||
A32Inst::MovIA2 {
|
||||
cond,
|
||||
rd,
|
||||
imm12,
|
||||
imm4,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -426,8 +560,18 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- MOV register -------------------------------------------------------
|
||||
A32Inst::MovRA1 { cond, rd, stype, rm }
|
||||
| A32Inst::MovsRA1 { cond, rd, stype, rm } => {
|
||||
A32Inst::MovRA1 {
|
||||
cond,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
}
|
||||
| A32Inst::MovsRA1 {
|
||||
cond,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -439,8 +583,20 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- ADD register -------------------------------------------------------
|
||||
A32Inst::AddRA1 { cond, rn, rd, stype, rm }
|
||||
| A32Inst::AddsRA1 { cond, rn, rd, stype, rm } => {
|
||||
A32Inst::AddRA1 {
|
||||
cond,
|
||||
rn,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
}
|
||||
| A32Inst::AddsRA1 {
|
||||
cond,
|
||||
rn,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -453,8 +609,20 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- SUB register -------------------------------------------------------
|
||||
A32Inst::SubRA1 { cond, rn, rd, stype, rm }
|
||||
| A32Inst::SubsRA1 { cond, rn, rd, stype, rm } => {
|
||||
A32Inst::SubRA1 {
|
||||
cond,
|
||||
rn,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
}
|
||||
| A32Inst::SubsRA1 {
|
||||
cond,
|
||||
rn,
|
||||
rd,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -467,7 +635,12 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- CMP register -------------------------------------------------------
|
||||
A32Inst::CmpRA1 { cond, rn, stype, rm } => {
|
||||
A32Inst::CmpRA1 {
|
||||
cond,
|
||||
rn,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -501,7 +674,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- LDR immediate (offset / pre-index / post-index) --------------------
|
||||
A32Inst::LdrIA1Off { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::LdrIA1Off {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -511,7 +690,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::LdrIA1Pre { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::LdrIA1Pre {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -522,7 +707,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::LdrIA1Post { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::LdrIA1Post {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -535,7 +726,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- LDR register (offset / pre-index / post-index) ---------------------
|
||||
A32Inst::LdrRA1Off { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::LdrRA1Off {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -545,7 +744,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::LdrRA1Pre { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::LdrRA1Pre {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -556,7 +763,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::LdrRA1Post { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::LdrRA1Post {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -569,7 +784,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- STR immediate ------------------------------------------------------
|
||||
A32Inst::StrIA1Off { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::StrIA1Off {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -579,7 +800,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::StrIA1Pre { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::StrIA1Pre {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -590,7 +817,13 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::StrIA1Post { cond, u, rn, rt, imm12 } => {
|
||||
A32Inst::StrIA1Post {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm12,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -603,7 +836,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
}
|
||||
|
||||
// ---- STR register -------------------------------------------------------
|
||||
A32Inst::StrRA1Off { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::StrRA1Off {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -613,7 +854,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::StrRA1Pre { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::StrRA1Pre {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -624,7 +873,15 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
Ok(())
|
||||
}
|
||||
|
||||
A32Inst::StrRA1Post { cond, u, rn, rt, imm5, stype, rm } => {
|
||||
A32Inst::StrRA1Post {
|
||||
cond,
|
||||
u,
|
||||
rn,
|
||||
rt,
|
||||
imm5,
|
||||
stype,
|
||||
rm,
|
||||
} => {
|
||||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
|
|
@ -638,14 +895,19 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
|
||||
// ---- B ------------------------------------------------------------------
|
||||
A32Inst::BA1 { cond, imm24 } => {
|
||||
let target_addr = cx.pc.wrapping_add(8)
|
||||
let target_addr = cx
|
||||
.pc
|
||||
.wrapping_add(8)
|
||||
.wrapping_add_signed(a32_branch_offset(*imm24) as i64);
|
||||
let target_block = cx
|
||||
.direct_block(target_addr)
|
||||
.ok_or(ArmLiftError::MissingTargetBlock)?;
|
||||
|
||||
match cond_value(cx, *cond)? {
|
||||
None => { cx.fb.jump(target_block); Ok(()) }
|
||||
None => {
|
||||
cx.fb.jump(target_block);
|
||||
Ok(())
|
||||
}
|
||||
Some(c) => {
|
||||
let fallthrough = cx
|
||||
.fallthrough_block()
|
||||
|
|
@ -661,7 +923,9 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
if cond_value(cx, *cond)?.is_some() {
|
||||
return Err(ArmLiftError::UnsupportedCondition);
|
||||
}
|
||||
let target_addr = cx.pc.wrapping_add(8)
|
||||
let target_addr = cx
|
||||
.pc
|
||||
.wrapping_add(8)
|
||||
.wrapping_add_signed(a32_branch_offset(*imm24) as i64);
|
||||
let callee = cx.fb.iconst(Type::ptr(32), target_addr as i64);
|
||||
cx.fb.call(callee, &[]);
|
||||
|
|
@ -699,6 +963,10 @@ fn lift_inst(cx: &mut ArmLiftCtx<'_, '_>, inst: &A32Inst) -> Result<(), ArmLiftE
|
|||
pub struct DummyEnv;
|
||||
|
||||
impl LiftEnv for DummyEnv {
|
||||
fn block_for_target(&self, _addr: u64) -> Option<Block> { None }
|
||||
fn fallthrough_block(&self) -> Option<Block> { None }
|
||||
fn block_for_target(&self, _addr: u64) -> Option<Block> {
|
||||
None
|
||||
}
|
||||
fn fallthrough_block(&self) -> Option<Block> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ pub enum StmtData {
|
|||
// ------------------------------------------------------------------ //
|
||||
// Value-producing statements //
|
||||
// ------------------------------------------------------------------ //
|
||||
|
||||
/// Signed integer literal. Result type determines the width.
|
||||
IConst { imm: i64, result: Value },
|
||||
|
||||
|
|
@ -43,19 +42,42 @@ pub enum StmtData {
|
|||
BConst { value: bool, result: Value },
|
||||
|
||||
/// Unary operation.
|
||||
Unary { op: UnaryOp, arg: Value, result: Value },
|
||||
Unary {
|
||||
op: UnaryOp,
|
||||
arg: Value,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
/// Binary operation.
|
||||
Binary { op: BinaryOp, lhs: Value, rhs: Value, result: Value },
|
||||
Binary {
|
||||
op: BinaryOp,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
/// Cast or conversion.
|
||||
Cast { op: CastOp, arg: Value, result: Value },
|
||||
Cast {
|
||||
op: CastOp,
|
||||
arg: Value,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
/// Integer comparison. Result type is always `bool`.
|
||||
Icmp { cc: IntCC, lhs: Value, rhs: Value, result: Value },
|
||||
Icmp {
|
||||
cc: IntCC,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
/// Floating-point comparison. Result type is always `bool`.
|
||||
Fcmp { cc: FloatCC, lhs: Value, rhs: Value, result: Value },
|
||||
Fcmp {
|
||||
cc: FloatCC,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
/// Conditional select. `cond` must be `bool`.
|
||||
Select {
|
||||
|
|
@ -66,14 +88,21 @@ pub enum StmtData {
|
|||
},
|
||||
|
||||
/// Memory load. Anchored in the statement stream to preserve memory order.
|
||||
Load { addr: Value, size: MemSize, result: Value },
|
||||
Load {
|
||||
addr: Value,
|
||||
size: MemSize,
|
||||
result: Value,
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
// Side-effecting statements (no result value) //
|
||||
// ------------------------------------------------------------------ //
|
||||
|
||||
/// Memory store.
|
||||
Store { addr: Value, value: Value, size: MemSize },
|
||||
Store {
|
||||
addr: Value,
|
||||
value: Value,
|
||||
size: MemSize,
|
||||
},
|
||||
|
||||
/// Effectful call.
|
||||
Call { callee: Value, args: ValueList },
|
||||
|
|
@ -81,7 +110,6 @@ pub enum StmtData {
|
|||
// ------------------------------------------------------------------ //
|
||||
// Terminators //
|
||||
// ------------------------------------------------------------------ //
|
||||
|
||||
/// Unconditional jump.
|
||||
Jump { dst: BlockCall },
|
||||
|
||||
|
|
@ -122,7 +150,10 @@ impl StmtData {
|
|||
|
||||
/// Returns whether this statement is a block terminator.
|
||||
pub const fn is_terminator(self) -> bool {
|
||||
matches!(self, Self::Jump { .. } | Self::BrIf { .. } | Self::Return { .. })
|
||||
matches!(
|
||||
self,
|
||||
Self::Jump { .. } | Self::BrIf { .. } | Self::Return { .. }
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether this statement may read memory.
|
||||
|
|
|
|||
|
|
@ -143,7 +143,9 @@ impl Verifier<'_> {
|
|||
self.verify_result(stmt, result)?;
|
||||
}
|
||||
|
||||
StmtData::Binary { lhs, rhs, result, .. } => {
|
||||
StmtData::Binary {
|
||||
lhs, rhs, result, ..
|
||||
} => {
|
||||
self.ensure_valid_value(lhs, format!("statement {stmt} binary lhs"))?;
|
||||
self.ensure_valid_value(rhs, format!("statement {stmt} binary rhs"))?;
|
||||
self.verify_result(stmt, result)?;
|
||||
|
|
@ -154,8 +156,12 @@ impl Verifier<'_> {
|
|||
self.verify_result(stmt, result)?;
|
||||
}
|
||||
|
||||
StmtData::Icmp { lhs, rhs, result, .. }
|
||||
| StmtData::Fcmp { lhs, rhs, result, .. } => {
|
||||
StmtData::Icmp {
|
||||
lhs, rhs, result, ..
|
||||
}
|
||||
| StmtData::Fcmp {
|
||||
lhs, rhs, result, ..
|
||||
} => {
|
||||
self.ensure_valid_value(lhs, format!("statement {stmt} compare lhs"))?;
|
||||
self.ensure_valid_value(rhs, format!("statement {stmt} compare rhs"))?;
|
||||
self.verify_result(stmt, result)?;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,11 @@ impl Printer<'_> {
|
|||
|
||||
match *self.body.stmt_data(stmt) {
|
||||
StmtData::IConst { imm, result } => {
|
||||
writeln!(f, "%{result} = iconst {imm} : {}", self.body.value_type(result))
|
||||
writeln!(
|
||||
f,
|
||||
"%{result} = iconst {imm} : {}",
|
||||
self.body.value_type(result)
|
||||
)
|
||||
}
|
||||
|
||||
StmtData::F32Const { bits, result } => {
|
||||
|
|
@ -87,7 +91,12 @@ impl Printer<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
StmtData::Binary { op, lhs, rhs, result } => {
|
||||
StmtData::Binary {
|
||||
op,
|
||||
lhs,
|
||||
rhs,
|
||||
result,
|
||||
} => {
|
||||
writeln!(
|
||||
f,
|
||||
"%{result} = {op} %{lhs}, %{rhs} : {}",
|
||||
|
|
@ -104,7 +113,12 @@ impl Printer<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
StmtData::Icmp { cc, lhs, rhs, result } => {
|
||||
StmtData::Icmp {
|
||||
cc,
|
||||
lhs,
|
||||
rhs,
|
||||
result,
|
||||
} => {
|
||||
writeln!(
|
||||
f,
|
||||
"%{result} = icmp {cc} %{lhs}, %{rhs} : {}",
|
||||
|
|
@ -112,7 +126,12 @@ impl Printer<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
StmtData::Fcmp { cc, lhs, rhs, result } => {
|
||||
StmtData::Fcmp {
|
||||
cc,
|
||||
lhs,
|
||||
rhs,
|
||||
result,
|
||||
} => {
|
||||
writeln!(
|
||||
f,
|
||||
"%{result} = fcmp {cc} %{lhs}, %{rhs} : {}",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue