binaryninja/architecture/
flag.rs

1use crate::architecture::CoreArchitecture;
2use binaryninjacore_sys::*;
3use std::borrow::Cow;
4use std::collections::HashMap;
5use std::ffi::CStr;
6use std::fmt::Debug;
7use std::hash::Hash;
8
9pub use binaryninjacore_sys::BNFlagRole as FlagRole;
10pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition;
11
12new_id_type!(FlagId, u32);
13// TODO: Make this NonZero<u32>?
14new_id_type!(FlagWriteId, u32);
15new_id_type!(FlagClassId, u32);
16new_id_type!(FlagGroupId, u32);
17
18pub trait Flag: Debug + Sized + Clone + Copy + Hash + Eq {
19    type FlagClass: FlagClass;
20
21    fn name(&self) -> Cow<'_, str>;
22    fn role(&self, class: Option<Self::FlagClass>) -> FlagRole;
23
24    /// Unique identifier for this `Flag`.
25    ///
26    /// *MUST* be in the range [0, 0x7fff_ffff]
27    fn id(&self) -> FlagId;
28}
29
30pub trait FlagWrite: Sized + Clone + Copy {
31    type FlagType: Flag;
32    type FlagClass: FlagClass;
33
34    fn name(&self) -> Cow<'_, str>;
35    fn class(&self) -> Option<Self::FlagClass>;
36
37    /// Unique identifier for this `FlagWrite`.
38    ///
39    /// *MUST NOT* be 0.
40    /// *MUST* be in the range [1, 0x7fff_ffff]
41    fn id(&self) -> FlagWriteId;
42
43    fn flags_written(&self) -> Vec<Self::FlagType>;
44}
45
46pub trait FlagClass: Sized + Clone + Copy + Hash + Eq {
47    fn name(&self) -> Cow<'_, str>;
48
49    /// Unique identifier for this `FlagClass`.
50    ///
51    /// *MUST NOT* be 0.
52    /// *MUST* be in the range [1, 0x7fff_ffff]
53    fn id(&self) -> FlagClassId;
54}
55
56pub trait FlagGroup: Debug + Sized + Clone + Copy {
57    type FlagType: Flag;
58    type FlagClass: FlagClass;
59
60    fn name(&self) -> Cow<'_, str>;
61
62    /// Unique identifier for this `FlagGroup`.
63    ///
64    /// *MUST* be in the range [0, 0x7fff_ffff]
65    fn id(&self) -> FlagGroupId;
66
67    /// Returns the list of flags that need to be resolved in order
68    /// to take the clean flag resolution path -- at time of writing,
69    /// all required flags must have been set by the same instruction,
70    /// and the 'querying' instruction must be reachable from *one*
71    /// instruction that sets all of these flags.
72    fn flags_required(&self) -> Vec<Self::FlagType>;
73
74    /// Returns the mapping of Semantic Flag Classes to Flag Conditions,
75    /// in the context of this Flag Group.
76    ///
77    /// Example:
78    ///
79    /// If we have a group representing `cr1_lt` (as in PowerPC), we would
80    /// have multiple Semantic Flag Classes used by the different Flag Write
81    /// Types to represent the different comparisons, so for `cr1_lt` we
82    /// would return a mapping along the lines of:
83    ///
84    /// ```text
85    /// cr1_signed -> LLFC_SLT,
86    /// cr1_unsigned -> LLFC_ULT,
87    /// ```
88    ///
89    /// This allows the core to recover the semantics of the comparison and
90    /// inline it into conditional branches when appropriate.
91    fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>;
92}
93
94/// Type for architectures that do not use flags. Will panic if accessed as a flag.
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
96pub struct UnusedFlag;
97
98impl Flag for UnusedFlag {
99    type FlagClass = Self;
100    fn name(&self) -> Cow<'_, str> {
101        unreachable!()
102    }
103    fn role(&self, _class: Option<Self::FlagClass>) -> FlagRole {
104        unreachable!()
105    }
106    fn id(&self) -> FlagId {
107        unreachable!()
108    }
109}
110
111impl FlagWrite for UnusedFlag {
112    type FlagType = Self;
113    type FlagClass = Self;
114    fn name(&self) -> Cow<'_, str> {
115        unreachable!()
116    }
117    fn class(&self) -> Option<Self> {
118        unreachable!()
119    }
120    fn id(&self) -> FlagWriteId {
121        unreachable!()
122    }
123    fn flags_written(&self) -> Vec<Self::FlagType> {
124        unreachable!()
125    }
126}
127
128impl FlagClass for UnusedFlag {
129    fn name(&self) -> Cow<'_, str> {
130        unreachable!()
131    }
132    fn id(&self) -> FlagClassId {
133        unreachable!()
134    }
135}
136
137impl FlagGroup for UnusedFlag {
138    type FlagType = Self;
139    type FlagClass = Self;
140    fn name(&self) -> Cow<'_, str> {
141        unreachable!()
142    }
143    fn id(&self) -> FlagGroupId {
144        unreachable!()
145    }
146    fn flags_required(&self) -> Vec<Self::FlagType> {
147        unreachable!()
148    }
149    fn flag_conditions(&self) -> HashMap<Self, FlagCondition> {
150        unreachable!()
151    }
152}
153
154#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
155pub struct CoreFlag {
156    arch: CoreArchitecture,
157    id: FlagId,
158}
159
160impl CoreFlag {
161    pub fn new(arch: CoreArchitecture, id: FlagId) -> Option<Self> {
162        let flag = Self { arch, id };
163        flag.is_valid().then_some(flag)
164    }
165
166    fn is_valid(&self) -> bool {
167        // We check the name to see if the flag is actually valid.
168        let name = unsafe { BNGetArchitectureFlagName(self.arch.handle, self.id.into()) };
169        match name.is_null() {
170            true => false,
171            false => {
172                unsafe { BNFreeString(name) };
173                true
174            }
175        }
176    }
177}
178
179impl Flag for CoreFlag {
180    type FlagClass = CoreFlagClass;
181
182    fn name(&self) -> Cow<'_, str> {
183        unsafe {
184            let name = BNGetArchitectureFlagName(self.arch.handle, self.id.into());
185
186            // We need to guarantee ownership, as if we're still
187            // a Borrowed variant we're about to free the underlying
188            // memory.
189            let res = CStr::from_ptr(name);
190            let res = res.to_string_lossy().into_owned().into();
191
192            BNFreeString(name);
193
194            res
195        }
196    }
197
198    fn role(&self, class: Option<CoreFlagClass>) -> FlagRole {
199        unsafe {
200            BNGetArchitectureFlagRole(
201                self.arch.handle,
202                self.id.into(),
203                class.map(|c| c.id.0).unwrap_or(0),
204            )
205        }
206    }
207
208    fn id(&self) -> FlagId {
209        self.id
210    }
211}
212
213#[derive(Copy, Clone, Eq, PartialEq, Hash)]
214pub struct CoreFlagWrite {
215    arch: CoreArchitecture,
216    id: FlagWriteId,
217}
218
219impl CoreFlagWrite {
220    pub fn new(arch: CoreArchitecture, id: FlagWriteId) -> Option<Self> {
221        let flag_write = Self { arch, id };
222        flag_write.is_valid().then_some(flag_write)
223    }
224
225    fn is_valid(&self) -> bool {
226        // We check the name to see if the flag write is actually valid.
227        let name = unsafe { BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()) };
228        match name.is_null() {
229            true => false,
230            false => {
231                unsafe { BNFreeString(name) };
232                true
233            }
234        }
235    }
236}
237
238impl FlagWrite for CoreFlagWrite {
239    type FlagType = CoreFlag;
240    type FlagClass = CoreFlagClass;
241
242    fn name(&self) -> Cow<'_, str> {
243        unsafe {
244            let name = BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into());
245
246            // We need to guarantee ownership, as if we're still
247            // a Borrowed variant we're about to free the underlying
248            // memory.
249            let res = CStr::from_ptr(name);
250            let res = res.to_string_lossy().into_owned().into();
251
252            BNFreeString(name);
253
254            res
255        }
256    }
257
258    fn class(&self) -> Option<CoreFlagClass> {
259        let class = unsafe {
260            BNGetArchitectureSemanticClassForFlagWriteType(self.arch.handle, self.id.into())
261        };
262
263        match class {
264            0 => None,
265            class_id => Some(CoreFlagClass::new(self.arch, class_id.into())?),
266        }
267    }
268
269    fn id(&self) -> FlagWriteId {
270        self.id
271    }
272
273    fn flags_written(&self) -> Vec<CoreFlag> {
274        let mut count: usize = 0;
275        let regs: *mut u32 = unsafe {
276            BNGetArchitectureFlagsWrittenByFlagWriteType(
277                self.arch.handle,
278                self.id.into(),
279                &mut count,
280            )
281        };
282
283        let ret = unsafe {
284            std::slice::from_raw_parts(regs, count)
285                .iter()
286                .map(|id| FlagId::from(*id))
287                .filter_map(|reg| CoreFlag::new(self.arch, reg))
288                .collect()
289        };
290
291        unsafe {
292            BNFreeRegisterList(regs);
293        }
294
295        ret
296    }
297}
298
299#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
300pub struct CoreFlagClass {
301    arch: CoreArchitecture,
302    id: FlagClassId,
303}
304
305impl CoreFlagClass {
306    pub fn new(arch: CoreArchitecture, id: FlagClassId) -> Option<Self> {
307        let flag = Self { arch, id };
308        flag.is_valid().then_some(flag)
309    }
310
311    fn is_valid(&self) -> bool {
312        // We check the name to see if the flag is actually valid.
313        let name =
314            unsafe { BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into()) };
315        match name.is_null() {
316            true => false,
317            false => {
318                unsafe { BNFreeString(name) };
319                true
320            }
321        }
322    }
323}
324
325impl FlagClass for CoreFlagClass {
326    fn name(&self) -> Cow<'_, str> {
327        unsafe {
328            let name = BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into());
329
330            // We need to guarantee ownership, as if we're still
331            // a Borrowed variant we're about to free the underlying
332            // memory.
333            let res = CStr::from_ptr(name);
334            let res = res.to_string_lossy().into_owned().into();
335
336            BNFreeString(name);
337
338            res
339        }
340    }
341
342    fn id(&self) -> FlagClassId {
343        self.id
344    }
345}
346
347#[derive(Debug, Copy, Clone, Eq, PartialEq)]
348pub struct CoreFlagGroup {
349    arch: CoreArchitecture,
350    id: FlagGroupId,
351}
352
353impl CoreFlagGroup {
354    pub fn new(arch: CoreArchitecture, id: FlagGroupId) -> Option<Self> {
355        let flag_group = Self { arch, id };
356        flag_group.is_valid().then_some(flag_group)
357    }
358
359    fn is_valid(&self) -> bool {
360        // We check the name to see if the flag group is actually valid.
361        let name =
362            unsafe { BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into()) };
363        match name.is_null() {
364            true => false,
365            false => {
366                unsafe { BNFreeString(name) };
367                true
368            }
369        }
370    }
371}
372
373impl FlagGroup for CoreFlagGroup {
374    type FlagType = CoreFlag;
375    type FlagClass = CoreFlagClass;
376
377    fn name(&self) -> Cow<'_, str> {
378        unsafe {
379            let name = BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into());
380
381            // We need to guarantee ownership, as if we're still
382            // a Borrowed variant we're about to free the underlying
383            // memory.
384            let res = CStr::from_ptr(name);
385            let res = res.to_string_lossy().into_owned().into();
386
387            BNFreeString(name);
388
389            res
390        }
391    }
392
393    fn id(&self) -> FlagGroupId {
394        self.id
395    }
396
397    fn flags_required(&self) -> Vec<CoreFlag> {
398        let mut count: usize = 0;
399        let regs: *mut u32 = unsafe {
400            BNGetArchitectureFlagsRequiredForSemanticFlagGroup(
401                self.arch.handle,
402                self.id.into(),
403                &mut count,
404            )
405        };
406
407        let ret = unsafe {
408            std::slice::from_raw_parts(regs, count)
409                .iter()
410                .map(|id| FlagId::from(*id))
411                .filter_map(|reg| CoreFlag::new(self.arch, reg))
412                .collect()
413        };
414
415        unsafe {
416            BNFreeRegisterList(regs);
417        }
418
419        ret
420    }
421
422    fn flag_conditions(&self) -> HashMap<CoreFlagClass, FlagCondition> {
423        let mut count: usize = 0;
424
425        unsafe {
426            let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup(
427                self.arch.handle,
428                self.id.into(),
429                &mut count,
430            );
431
432            let ret = std::slice::from_raw_parts_mut(flag_conds, count)
433                .iter()
434                .filter_map(|class_cond| {
435                    Some((
436                        CoreFlagClass::new(self.arch, class_cond.semanticClass.into())?,
437                        class_cond.condition,
438                    ))
439                })
440                .collect();
441
442            BNFreeFlagConditionsForSemanticFlagGroup(flag_conds);
443
444            ret
445        }
446    }
447}