Skip to content

Commit fe7b9b5

Browse files
committed
Support SSA form properly in low level IL Rust API
1 parent 0722b74 commit fe7b9b5

File tree

6 files changed

+440
-37
lines changed

6 files changed

+440
-37
lines changed

rust/src/low_level_il.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::borrow::Cow;
1516
use std::fmt;
1617

1718
// TODO : provide some way to forbid emitting register reads for certain registers
@@ -125,12 +126,19 @@ impl<R: ArchReg> LowLevelILRegisterKind<R> {
125126
LowLevelILRegisterKind::Temp(temp.into())
126127
}
127128

128-
fn id(&self) -> RegisterId {
129+
pub fn id(&self) -> RegisterId {
129130
match *self {
130131
LowLevelILRegisterKind::Arch(ref r) => r.id(),
131132
LowLevelILRegisterKind::Temp(temp) => temp.id(),
132133
}
133134
}
135+
136+
pub fn name(&self) -> Cow<str> {
137+
match *self {
138+
LowLevelILRegisterKind::Arch(ref r) => r.name(),
139+
LowLevelILRegisterKind::Temp(temp) => Cow::Owned(format!("temp{}", temp.temp_id)),
140+
}
141+
}
134142
}
135143

136144
impl<R: ArchReg> fmt::Debug for LowLevelILRegisterKind<R> {
@@ -149,15 +157,16 @@ impl From<LowLevelILTempRegister> for LowLevelILRegisterKind<CoreRegister> {
149157
}
150158

151159
#[derive(Copy, Clone, Debug)]
152-
pub enum LowLevelILSSARegister<R: ArchReg> {
160+
pub enum LowLevelILSSARegisterKind<R: ArchReg> {
153161
Full(LowLevelILRegisterKind<R>, u32), // no such thing as partial access to a temp register, I think
154162
Partial(R, u32, R), // partial accesses only possible for arch registers, I think
155163
}
156164

157-
impl<R: ArchReg> LowLevelILSSARegister<R> {
165+
impl<R: ArchReg> LowLevelILSSARegisterKind<R> {
158166
pub fn version(&self) -> u32 {
159167
match *self {
160-
LowLevelILSSARegister::Full(_, ver) | LowLevelILSSARegister::Partial(_, ver, _) => ver,
168+
LowLevelILSSARegisterKind::Full(_, ver)
169+
| LowLevelILSSARegisterKind::Partial(_, ver, _) => ver,
161170
}
162171
}
163172
}

rust/src/low_level_il/expression.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,13 @@ where
216216
F: FunctionForm,
217217
{
218218
Load(Operation<'func, M, F, operation::Load>),
219+
LoadSsa(Operation<'func, M, F, operation::LoadSsa>),
219220
Pop(Operation<'func, M, F, operation::Pop>),
220221
Reg(Operation<'func, M, F, operation::Reg>),
222+
RegSsa(Operation<'func, M, F, operation::RegSsa>),
223+
RegPartialSsa(Operation<'func, M, F, operation::RegPartialSsa>),
221224
RegSplit(Operation<'func, M, F, operation::RegSplit>),
225+
RegSplitSsa(Operation<'func, M, F, operation::RegSplitSsa>),
222226
Const(Operation<'func, M, F, operation::Const>),
223227
ConstPtr(Operation<'func, M, F, operation::Const>),
224228
Flag(Operation<'func, M, F, operation::Flag>),
@@ -327,15 +331,17 @@ where
327331
use binaryninjacore_sys::BNLowLevelILOperation::*;
328332

329333
match op.operation {
330-
LLIL_LOAD | LLIL_LOAD_SSA => {
331-
LowLevelILExpressionKind::Load(Operation::new(function, op))
332-
}
334+
LLIL_LOAD => LowLevelILExpressionKind::Load(Operation::new(function, op)),
335+
LLIL_LOAD_SSA => LowLevelILExpressionKind::LoadSsa(Operation::new(function, op)),
333336
LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op)),
334-
LLIL_REG | LLIL_REG_SSA | LLIL_REG_SSA_PARTIAL => {
335-
LowLevelILExpressionKind::Reg(Operation::new(function, op))
337+
LLIL_REG => LowLevelILExpressionKind::Reg(Operation::new(function, op)),
338+
LLIL_REG_SSA => LowLevelILExpressionKind::RegSsa(Operation::new(function, op)),
339+
LLIL_REG_SSA_PARTIAL => {
340+
LowLevelILExpressionKind::RegPartialSsa(Operation::new(function, op))
336341
}
337-
LLIL_REG_SPLIT | LLIL_REG_SPLIT_SSA => {
338-
LowLevelILExpressionKind::RegSplit(Operation::new(function, op))
342+
LLIL_REG_SPLIT => LowLevelILExpressionKind::RegSplit(Operation::new(function, op)),
343+
LLIL_REG_SPLIT_SSA => {
344+
LowLevelILExpressionKind::RegSplitSsa(Operation::new(function, op))
339345
}
340346
LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op)),
341347
LLIL_CONST_PTR => LowLevelILExpressionKind::ConstPtr(Operation::new(function, op)),
@@ -587,10 +593,13 @@ where
587593
Load(ref op) => {
588594
visit!(op.source_mem_expr());
589595
}
590-
// Do not have any sub expressions.
591-
Pop(_) | Reg(_) | RegSplit(_) | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_)
592-
| ExternPtr(_) | FlagCond(_) | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) => {
596+
LoadSsa(ref op) => {
597+
visit!(op.source_mem_expr().0);
593598
}
599+
// Do not have any sub expressions.
600+
Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_)
601+
| Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_)
602+
| FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) => {}
594603
}
595604

596605
VisitorAction::Sibling
@@ -614,12 +623,20 @@ where
614623

615624
Load(ref op) => &op.op,
616625

626+
LoadSsa(ref op) => &op.op,
627+
617628
Pop(ref op) => &op.op,
618629

619630
Reg(ref op) => &op.op,
620631

632+
RegSsa(ref op) => &op.op,
633+
634+
RegPartialSsa(ref op) => &op.op,
635+
621636
RegSplit(ref op) => &op.op,
622637

638+
RegSplitSsa(ref op) => &op.op,
639+
623640
Flag(ref op) => &op.op,
624641

625642
FlagBit(ref op) => &op.op,
@@ -670,12 +687,20 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA<LiftedNonSSA>> {
670687

671688
Load(ref op) => op.flag_write(),
672689

690+
LoadSsa(ref op) => op.flag_write(),
691+
673692
Pop(ref op) => op.flag_write(),
674693

675694
Reg(ref op) => op.flag_write(),
676695

696+
RegSsa(ref op) => op.flag_write(),
697+
698+
RegPartialSsa(ref op) => op.flag_write(),
699+
677700
RegSplit(ref op) => op.flag_write(),
678701

702+
RegSplitSsa(ref op) => op.flag_write(),
703+
679704
Flag(ref op) => op.flag_write(),
680705

681706
FlagBit(ref op) => op.flag_write(),

rust/src/low_level_il/function.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use binaryninjacore_sys::BNFreeLowLevelILFunction;
16-
use binaryninjacore_sys::BNGetLowLevelILOwnerFunction;
17-
use binaryninjacore_sys::BNLowLevelILFunction;
18-
use binaryninjacore_sys::BNNewLowLevelILFunctionReference;
19-
2015
use std::fmt::Debug;
2116
use std::hash::{Hash, Hasher};
2217
use std::marker::PhantomData;
2318

19+
use binaryninjacore_sys::*;
20+
2421
use crate::architecture::CoreArchitecture;
2522
use crate::basic_block::BasicBlock;
2623
use crate::function::Function;
@@ -160,13 +157,8 @@ where
160157
Function::ref_from_raw(func)
161158
}
162159
}
163-
}
164160

165-
// LLIL basic blocks are not available until the function object
166-
// is finalized, so ensure we can't try requesting basic blocks
167-
// during lifting
168-
impl<F: FunctionForm> LowLevelILFunction<Finalized, F> {
169-
pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<Finalized, F>>> {
161+
pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<M, F>>> {
170162
use binaryninjacore_sys::BNGetLowLevelILBasicBlockList;
171163

172164
unsafe {
@@ -178,6 +170,17 @@ impl<F: FunctionForm> LowLevelILFunction<Finalized, F> {
178170
}
179171
}
180172

173+
impl<M: FunctionMutability, V: NonSSAVariant> LowLevelILFunction<M, NonSSA<V>> {
174+
/// Retrieve the SSA form of the function.
175+
pub fn ssa_form(&self) -> Option<Ref<LowLevelILFunction<M, SSA>>> {
176+
let handle = unsafe { BNGetLowLevelILSSAForm(self.handle) };
177+
if handle.is_null() {
178+
return None;
179+
}
180+
Some(unsafe { LowLevelILFunction::ref_from_raw(handle) })
181+
}
182+
}
183+
181184
// Allow instantiating Lifted IL functions for querying Lifted IL from Architectures
182185
impl LowLevelILFunction<Mutable, NonSSA<LiftedNonSSA>> {
183186
// TODO: Document what happens when you pass None for `source_func`.
@@ -201,7 +204,6 @@ impl LowLevelILFunction<Mutable, NonSSA<LiftedNonSSA>> {
201204

202205
pub fn generate_ssa_form(&self) {
203206
use binaryninjacore_sys::BNGenerateLowLevelILSSAForm;
204-
205207
unsafe { BNGenerateLowLevelILSSAForm(self.handle) };
206208
}
207209
}

rust/src/low_level_il/instruction.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,12 @@ where
207207
{
208208
Nop(Operation<'func, M, F, operation::NoArgs>),
209209
SetReg(Operation<'func, M, F, operation::SetReg>),
210+
SetRegSsa(Operation<'func, M, F, operation::SetRegSsa>),
211+
SetRegPartialSsa(Operation<'func, M, F, operation::SetRegPartialSsa>),
210212
SetRegSplit(Operation<'func, M, F, operation::SetRegSplit>),
211213
SetFlag(Operation<'func, M, F, operation::SetFlag>),
212214
Store(Operation<'func, M, F, operation::Store>),
215+
StoreSsa(Operation<'func, M, F, operation::StoreSsa>),
213216
// TODO needs a real op
214217
Push(Operation<'func, M, F, operation::UnaryOp>),
215218

@@ -251,18 +254,19 @@ where
251254

252255
match op.operation {
253256
LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op)),
254-
LLIL_SET_REG | LLIL_SET_REG_SSA => {
255-
LowLevelILInstructionKind::SetReg(Operation::new(function, op))
257+
LLIL_SET_REG => LowLevelILInstructionKind::SetReg(Operation::new(function, op)),
258+
LLIL_SET_REG_SSA => LowLevelILInstructionKind::SetRegSsa(Operation::new(function, op)),
259+
LLIL_SET_REG_SSA_PARTIAL => {
260+
LowLevelILInstructionKind::SetRegPartialSsa(Operation::new(function, op))
256261
}
257262
LLIL_SET_REG_SPLIT | LLIL_SET_REG_SPLIT_SSA => {
258263
LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op))
259264
}
260265
LLIL_SET_FLAG | LLIL_SET_FLAG_SSA => {
261266
LowLevelILInstructionKind::SetFlag(Operation::new(function, op))
262267
}
263-
LLIL_STORE | LLIL_STORE_SSA => {
264-
LowLevelILInstructionKind::Store(Operation::new(function, op))
265-
}
268+
LLIL_STORE => LowLevelILInstructionKind::Store(Operation::new(function, op)),
269+
LLIL_STORE_SSA => LowLevelILInstructionKind::StoreSsa(Operation::new(function, op)),
266270
LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op)),
267271

268272
LLIL_REG_STACK_PUSH => {
@@ -314,12 +318,18 @@ where
314318

315319
match self {
316320
SetReg(ref op) => visit!(&op.source_expr()),
321+
SetRegSsa(ref op) => visit!(&op.source_expr()),
322+
SetRegPartialSsa(ref op) => visit!(&op.source_expr()),
317323
SetRegSplit(ref op) => visit!(&op.source_expr()),
318324
SetFlag(ref op) => visit!(&op.source_expr()),
319325
Store(ref op) => {
320326
visit!(&op.dest_mem_expr());
321327
visit!(&op.source_expr());
322328
}
329+
StoreSsa(ref op) => {
330+
visit!(&op.dest_mem_expr().0);
331+
visit!(&op.source_expr().0);
332+
}
323333
Push(ref op) => visit!(&op.operand()),
324334
RegStackPush(ref op) => visit!(&op.source_expr()),
325335
Jump(ref op) => visit!(&op.target()),

0 commit comments

Comments
 (0)