binaryninja/
low_level_il.rs

1// Copyright 2021-2026 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::borrow::Cow;
16use std::fmt;
17use std::fmt::{Debug, Display};
18// TODO : provide some way to forbid emitting register reads for certain registers
19// also writing for certain registers (e.g. zero register must prohibit il.set_reg and il.reg
20// (replace with nop or const(0) respectively)
21// requirements on load/store memory address sizes?
22// can reg/set_reg be used with sizes that differ from what is in BNRegisterInfo?
23
24use crate::architecture::{Architecture, Flag, RegisterId};
25use crate::architecture::{CoreRegister, Register as ArchReg};
26use crate::function::Location;
27
28pub mod block;
29pub mod expression;
30pub mod function;
31pub mod instruction;
32pub mod lifting;
33pub mod operation;
34
35use self::expression::*;
36use self::function::*;
37use self::instruction::*;
38
39/// Regular low-level IL, if you are not modifying the functions IL or needing SSA, use this.
40pub type LowLevelILRegularFunction = LowLevelILFunction<Finalized, NonSSA>;
41pub type LowLevelILRegularInstruction<'a> = LowLevelILInstruction<'a, Finalized, NonSSA>;
42pub type LowLevelILRegularInstructionKind<'a> = LowLevelILInstructionKind<'a, Finalized, NonSSA>;
43pub type LowLevelILRegularExpression<'a, ReturnType> =
44    LowLevelILExpression<'a, Finalized, NonSSA, ReturnType>;
45pub type LowLevelILRegularExpressionKind<'a> = LowLevelILExpressionKind<'a, Finalized, NonSSA>;
46
47/// Mutable low-level IL, used when lifting in architectures and modifying IL in workflow activities.
48pub type LowLevelILMutableFunction = LowLevelILFunction<Mutable, NonSSA>;
49pub type LowLevelILMutableExpression<'a, ReturnType> =
50    LowLevelILExpression<'a, Mutable, NonSSA, ReturnType>;
51
52/// SSA Variant of low-level IL, this can never be mutated directly.
53pub type LowLevelILSSAFunction = LowLevelILFunction<Finalized, SSA>;
54
55#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
56pub struct LowLevelILTempRegister {
57    /// The temporary id for the register, this will **NOT** be the referenced id in the core.
58    ///
59    /// Do not attempt to pass this to the core. Use [`LowLevelILTempRegister::id`] instead.
60    temp_id: RegisterId,
61}
62
63impl LowLevelILTempRegister {
64    pub fn new(temp_id: u32) -> Self {
65        Self {
66            temp_id: RegisterId(temp_id),
67        }
68    }
69
70    pub fn from_id(id: RegisterId) -> Option<Self> {
71        match id.is_temporary() {
72            true => {
73                let temp_id = RegisterId(id.0 & 0x7fff_ffff);
74                Some(Self { temp_id })
75            }
76            false => None,
77        }
78    }
79
80    /// The temporary registers core id, with the temporary bit set.
81    pub fn id(&self) -> RegisterId {
82        RegisterId(self.temp_id.0 | 0x8000_0000)
83    }
84}
85
86impl Debug for LowLevelILTempRegister {
87    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88        write!(f, "temp{}", self.temp_id)
89    }
90}
91
92impl Display for LowLevelILTempRegister {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        Debug::fmt(self, f)
95    }
96}
97
98impl TryFrom<RegisterId> for LowLevelILTempRegister {
99    type Error = ();
100
101    fn try_from(value: RegisterId) -> Result<Self, Self::Error> {
102        Self::from_id(value).ok_or(())
103    }
104}
105
106impl From<u32> for LowLevelILTempRegister {
107    fn from(value: u32) -> Self {
108        Self::new(value)
109    }
110}
111
112#[derive(Copy, Clone, PartialEq, Eq)]
113pub enum LowLevelILRegisterKind<R: ArchReg> {
114    Arch(R),
115    Temp(LowLevelILTempRegister),
116}
117
118impl<R: ArchReg> LowLevelILRegisterKind<R> {
119    pub fn from_raw(arch: &impl Architecture<Register = R>, val: RegisterId) -> Option<Self> {
120        match val.is_temporary() {
121            true => {
122                let temp_reg = LowLevelILTempRegister::from_id(val)?;
123                Some(LowLevelILRegisterKind::Temp(temp_reg))
124            }
125            false => {
126                let arch_reg = arch.register_from_id(val)?;
127                Some(LowLevelILRegisterKind::Arch(arch_reg))
128            }
129        }
130    }
131
132    pub fn from_temp(temp: impl Into<LowLevelILTempRegister>) -> Self {
133        LowLevelILRegisterKind::Temp(temp.into())
134    }
135
136    pub fn id(&self) -> RegisterId {
137        match *self {
138            LowLevelILRegisterKind::Arch(ref r) => r.id(),
139            LowLevelILRegisterKind::Temp(temp) => temp.id(),
140        }
141    }
142
143    pub fn name(&self) -> Cow<'_, str> {
144        match *self {
145            LowLevelILRegisterKind::Arch(ref r) => r.name(),
146            LowLevelILRegisterKind::Temp(temp) => Cow::Owned(format!("temp{}", temp.temp_id)),
147        }
148    }
149}
150
151impl<R: ArchReg> Debug for LowLevelILRegisterKind<R> {
152    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153        match *self {
154            LowLevelILRegisterKind::Arch(ref r) => r.fmt(f),
155            LowLevelILRegisterKind::Temp(ref id) => Debug::fmt(id, f),
156        }
157    }
158}
159
160impl<R: ArchReg> Display for LowLevelILRegisterKind<R> {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        match *self {
163            LowLevelILRegisterKind::Arch(ref r) => write!(f, "{}", r.name()),
164            LowLevelILRegisterKind::Temp(ref id) => Display::fmt(id, f),
165        }
166    }
167}
168
169impl From<LowLevelILTempRegister> for LowLevelILRegisterKind<CoreRegister> {
170    fn from(reg: LowLevelILTempRegister) -> Self {
171        LowLevelILRegisterKind::Temp(reg)
172    }
173}
174
175#[derive(Copy, Clone, Debug)]
176pub struct LowLevelILSSARegister<R: ArchReg> {
177    pub reg: LowLevelILRegisterKind<R>,
178    /// The SSA version of the register.
179    pub version: u32,
180}
181
182impl<R: ArchReg> LowLevelILSSARegister<R> {
183    pub fn new(reg: LowLevelILRegisterKind<R>, version: u32) -> Self {
184        Self { reg, version }
185    }
186
187    pub fn name(&self) -> Cow<'_, str> {
188        self.reg.name()
189    }
190
191    pub fn id(&self) -> RegisterId {
192        self.reg.id()
193    }
194}
195
196impl<R: ArchReg> Display for LowLevelILSSARegister<R> {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        write!(f, "{}#{}", self.reg, self.version)
199    }
200}
201
202/// The kind of SSA register.
203///
204/// An SSA register can exist in two states:
205///
206/// - Full, e.g. `eax` on x86
207/// - Partial, e.g. `al` on x86
208///
209/// If you intend to query for the ssa uses or definitions you must retrieve the physical register
210/// using the function [`LowLevelILSSARegisterKind::physical_reg`] which will give you the actual
211/// [`LowLevelILSSARegister`].
212#[derive(Copy, Clone, Debug)]
213pub enum LowLevelILSSARegisterKind<R: ArchReg> {
214    /// A full register is one that is not aliasing another, such as `eax` on x86 or `rax` on x86_64.
215    Full(LowLevelILSSARegister<R>),
216    Partial {
217        /// This is the non-aliased register.
218        ///
219        /// This register is what is used for dataflow, otherwise the backing storage of aliased registers
220        /// like `al` on x86 would contain separate value information from the physical register `eax`.
221        ///
222        /// NOTE: While this is a [`LowLevelILSSARegister`] temporary registers are not allowed in partial
223        /// assignments, so this will always be an actual architecture register.
224        full_reg: LowLevelILSSARegister<R>,
225        /// This is the aliased register.
226        ///
227        /// On x86 if the register `al` is used that would be considered a partial register, with the
228        /// full register `eax` being used as the backing storage.
229        partial_reg: CoreRegister,
230    },
231}
232
233impl<R: ArchReg> LowLevelILSSARegisterKind<R> {
234    pub fn new_full(kind: LowLevelILRegisterKind<R>, version: u32) -> Self {
235        Self::Full(LowLevelILSSARegister::new(kind, version))
236    }
237
238    pub fn new_partial(
239        full_reg: LowLevelILRegisterKind<R>,
240        version: u32,
241        partial_reg: CoreRegister,
242    ) -> Self {
243        Self::Partial {
244            full_reg: LowLevelILSSARegister::new(full_reg, version),
245            partial_reg,
246        }
247    }
248
249    /// This is the non-aliased register used. This should be called when you intend to actually
250    /// query for SSA dataflow information, as a partial register is prohibited from being used.
251    ///
252    /// # Example
253    ///
254    /// On x86 `al` in the LLIL SSA will have a physical register of `eax`.
255    pub fn physical_reg(&self) -> LowLevelILSSARegister<R> {
256        match *self {
257            LowLevelILSSARegisterKind::Full(reg) => reg,
258            LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg,
259        }
260    }
261
262    /// Gets the displayable register, for partial this will be the partial register name.
263    ///
264    /// # Example
265    ///
266    /// On x86 this will display "al" not "eax".
267    pub fn name(&self) -> Cow<'_, str> {
268        match *self {
269            LowLevelILSSARegisterKind::Full(ref reg) => reg.reg.name(),
270            LowLevelILSSARegisterKind::Partial {
271                ref partial_reg, ..
272            } => partial_reg.name(),
273        }
274    }
275}
276
277impl<R: ArchReg> AsRef<LowLevelILSSARegister<R>> for LowLevelILSSARegisterKind<R> {
278    fn as_ref(&self) -> &LowLevelILSSARegister<R> {
279        match self {
280            LowLevelILSSARegisterKind::Full(reg) => reg,
281            LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg,
282        }
283    }
284}
285
286impl<R: ArchReg> From<LowLevelILSSARegister<R>> for LowLevelILSSARegisterKind<R> {
287    fn from(value: LowLevelILSSARegister<R>) -> Self {
288        LowLevelILSSARegisterKind::Full(value)
289    }
290}
291
292impl<R: ArchReg> From<LowLevelILSSARegisterKind<R>> for LowLevelILSSARegister<R> {
293    fn from(value: LowLevelILSSARegisterKind<R>) -> Self {
294        match value {
295            LowLevelILSSARegisterKind::Full(reg) => reg,
296            LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg,
297        }
298    }
299}
300
301#[derive(Copy, Clone, Debug)]
302pub struct LowLevelILSSAFlag<F: Flag> {
303    pub flag: F,
304    pub version: u32,
305}
306
307impl<F: Flag> LowLevelILSSAFlag<F> {
308    pub fn new(flag: F, version: u32) -> Self {
309        Self { flag, version }
310    }
311}
312
313#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
314pub enum VisitorAction {
315    Descend,
316    Sibling,
317    Halt,
318}