binaryninja/architecture/
flag.rs1use 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);
13new_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 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 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 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 fn id(&self) -> FlagGroupId;
66
67 fn flags_required(&self) -> Vec<Self::FlagType>;
73
74 fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>;
92}
93
94#[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 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 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 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 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 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 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 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 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}