binaryninja/architecture/
register.rs

1use crate::architecture::CoreArchitecture;
2use crate::rc::{CoreArrayProvider, CoreArrayProviderInner};
3use binaryninjacore_sys::*;
4use std::borrow::Cow;
5use std::ffi::CStr;
6use std::fmt::{Debug, Formatter};
7use std::hash::Hash;
8
9new_id_type!(RegisterId, u32);
10
11impl RegisterId {
12    pub fn is_temporary(&self) -> bool {
13        self.0 & 0x8000_0000 != 0
14    }
15}
16
17new_id_type!(RegisterStackId, u32);
18
19#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
20pub enum ImplicitRegisterExtend {
21    /// The upper bits of the parent register are preserved (untouched).
22    ///
23    /// # Example (x86-64)
24    ///
25    /// Executing `inc al` only modifies the lowest 8 bits of `rax`. The upper 56 bits of `rax` remain
26    /// completely unchanged.
27    NoExtend = 0,
28    /// The upper bits of the parent register are zeroed out.
29    ///
30    /// # Example (x86-64)
31    ///
32    /// Executing `mov eax, 1` writes `1` to the lower 32 bits of `rax`, but implicitly **clears** the
33    /// upper 32 bits of `rax` to zero.
34    ZeroExtendToFullWidth,
35    /// The upper bits of the parent register are filled with the sign bit (MSB) of the value written.
36    SignExtendToFullWidth,
37}
38
39impl From<BNImplicitRegisterExtend> for ImplicitRegisterExtend {
40    fn from(value: BNImplicitRegisterExtend) -> Self {
41        match value {
42            BNImplicitRegisterExtend::NoExtend => Self::NoExtend,
43            BNImplicitRegisterExtend::ZeroExtendToFullWidth => Self::ZeroExtendToFullWidth,
44            BNImplicitRegisterExtend::SignExtendToFullWidth => Self::SignExtendToFullWidth,
45        }
46    }
47}
48
49impl From<ImplicitRegisterExtend> for BNImplicitRegisterExtend {
50    fn from(value: ImplicitRegisterExtend) -> Self {
51        match value {
52            ImplicitRegisterExtend::NoExtend => Self::NoExtend,
53            ImplicitRegisterExtend::ZeroExtendToFullWidth => Self::ZeroExtendToFullWidth,
54            ImplicitRegisterExtend::SignExtendToFullWidth => Self::SignExtendToFullWidth,
55        }
56    }
57}
58
59/// Information about a register.
60pub trait RegisterInfo: Sized {
61    type RegType: Register<InfoType = Self>;
62
63    /// The register that this register is an alias of.
64    ///
65    /// # Example (x86-64)
66    ///
67    /// The register `rax` is a parent of the register `eax`.
68    fn parent(&self) -> Option<Self::RegType>;
69
70    /// Size of the register in bytes.
71    fn size(&self) -> usize;
72
73    /// Offset of the register in bytes from the start of the containing [`RegisterInfo::parent`].
74    fn offset(&self) -> usize;
75
76    /// Used when this register aliases a logical register to determine what happens to the upper bits.
77    fn implicit_extend(&self) -> ImplicitRegisterExtend;
78}
79
80pub trait Register: Debug + Sized + Clone + Copy + Hash + Eq {
81    type InfoType: RegisterInfo<RegType = Self>;
82
83    /// The displayed name of the register, such as "eax".
84    fn name(&self) -> Cow<'_, str>;
85
86    fn info(&self) -> Self::InfoType;
87
88    /// Unique identifier for this `Register`.
89    ///
90    /// NOTE: *MUST* be in the range [0, 0x7fff_ffff]
91    fn id(&self) -> RegisterId;
92}
93
94/// Information about a register stack.
95pub trait RegisterStackInfo: Sized {
96    type RegStackType: RegisterStack<InfoType = Self>;
97    type RegType: Register<InfoType = Self::RegInfoType>;
98    type RegInfoType: RegisterInfo<RegType = Self::RegType>;
99
100    // TODO: Return a list of the registers instead?
101    /// The sequence of physical registers that back this stack.
102    ///
103    /// This defines the absolute storage locations in the hardware, ignoring the current stack pointer.
104    ///
105    /// Return the start of the "fake" registers defined. The core requires that the id's be contiguous
106    /// as you only return the **first** storage register and the count.
107    ///
108    /// # Example (x87 FPU)
109    ///
110    /// [`RegisterStackInfo::top_relative_regs`] with (REG_ST0, 8) and then define here (REG_PHYSICAL_0, 8).
111    fn storage_regs(&self) -> (Self::RegType, usize);
112
113    // TODO: Return a list of the registers instead?
114    /// The sequence of registers used to access the stack relative to the current top.
115    ///
116    /// Return the start of the relative registers defined. The core requires that the id's be contiguous
117    /// as you only return the **first** relative register and the count.
118    ///
119    /// # Example (x87 FPU)
120    ///
121    /// Returns (REG_ST0, 8), where the id's of all the later relative registers are contiguous.
122    fn top_relative_regs(&self) -> Option<(Self::RegType, usize)>;
123
124    /// The specific register that holds the index of the current stack top.
125    ///
126    /// The value in this register determines which physical `storage_reg` corresponds
127    /// to the first `top_relative_reg`.
128    ///
129    /// # Example (x87 FPU)
130    ///
131    /// Returns the `TOP` as a fake register.
132    ///
133    /// * If `TOP` == 0: `top_relative_regs[0]` maps to `storage_regs[0]`.
134    /// * If `TOP` == 1: `top_relative_regs[0]` maps to `storage_regs[1]`.
135    fn stack_top_reg(&self) -> Self::RegType;
136}
137
138/// Register stacks are used in architectures where registers are accessed relative to a
139/// dynamic stack pointer rather than by fixed names.
140///
141/// For more information see [`RegisterStackInfo`].
142///
143/// # Example
144/// The **x87 FPU** on x86 uses a register stack (`ST(0)` through `ST(7)`).
145/// Pushing a value decrements the stack top pointer; popping increments it.
146pub trait RegisterStack: Debug + Sized + Clone + Copy {
147    type InfoType: RegisterStackInfo<
148        RegType = Self::RegType,
149        RegInfoType = Self::RegInfoType,
150        RegStackType = Self,
151    >;
152    type RegType: Register<InfoType = Self::RegInfoType>;
153    type RegInfoType: RegisterInfo<RegType = Self::RegType>;
154
155    fn name(&self) -> Cow<'_, str>;
156    fn info(&self) -> Self::InfoType;
157
158    /// Unique identifier for this `RegisterStack`.
159    ///
160    /// *MUST* be in the range [0, 0x7fff_ffff]
161    fn id(&self) -> RegisterStackId;
162}
163
164/// Type for architectures that do not use register stacks. Will panic if accessed as a register stack.
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166pub struct UnusedRegisterStack<R: Register> {
167    _reg: std::marker::PhantomData<R>,
168}
169
170impl<R: Register> RegisterStack for UnusedRegisterStack<R> {
171    type InfoType = Self;
172    type RegType = R;
173    type RegInfoType = R::InfoType;
174
175    fn name(&self) -> Cow<'_, str> {
176        unreachable!()
177    }
178    fn info(&self) -> Self::InfoType {
179        unreachable!()
180    }
181    fn id(&self) -> RegisterStackId {
182        unreachable!()
183    }
184}
185
186impl<R: Register> RegisterStackInfo for UnusedRegisterStack<R> {
187    type RegStackType = Self;
188    type RegType = R;
189    type RegInfoType = R::InfoType;
190
191    fn storage_regs(&self) -> (Self::RegType, usize) {
192        unreachable!()
193    }
194    fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> {
195        unreachable!()
196    }
197    fn stack_top_reg(&self) -> Self::RegType {
198        unreachable!()
199    }
200}
201
202#[derive(Debug, Copy, Clone)]
203pub struct CoreRegisterInfo {
204    arch: CoreArchitecture,
205    id: RegisterId,
206    info: BNRegisterInfo,
207}
208
209impl CoreRegisterInfo {
210    pub fn new(arch: CoreArchitecture, id: RegisterId, info: BNRegisterInfo) -> Self {
211        Self { arch, id, info }
212    }
213}
214
215impl RegisterInfo for CoreRegisterInfo {
216    type RegType = CoreRegister;
217
218    fn parent(&self) -> Option<CoreRegister> {
219        if self.id != RegisterId::from(self.info.fullWidthRegister) {
220            Some(CoreRegister::new(
221                self.arch,
222                RegisterId::from(self.info.fullWidthRegister),
223            )?)
224        } else {
225            None
226        }
227    }
228
229    fn size(&self) -> usize {
230        self.info.size
231    }
232
233    fn offset(&self) -> usize {
234        self.info.offset
235    }
236
237    fn implicit_extend(&self) -> ImplicitRegisterExtend {
238        self.info.extend.into()
239    }
240}
241
242#[derive(Copy, Clone, Eq, PartialEq, Hash)]
243pub struct CoreRegister {
244    arch: CoreArchitecture,
245    id: RegisterId,
246}
247
248impl CoreRegister {
249    pub fn new(arch: CoreArchitecture, id: RegisterId) -> Option<Self> {
250        let register = Self { arch, id };
251        register.is_valid().then_some(register)
252    }
253
254    fn is_valid(&self) -> bool {
255        // We check the name to see if the register is actually valid.
256        let name = unsafe { BNGetArchitectureRegisterName(self.arch.handle, self.id.into()) };
257        match name.is_null() {
258            true => false,
259            false => {
260                unsafe { BNFreeString(name) };
261                true
262            }
263        }
264    }
265}
266
267impl Register for CoreRegister {
268    type InfoType = CoreRegisterInfo;
269
270    fn name(&self) -> Cow<'_, str> {
271        unsafe {
272            let name = BNGetArchitectureRegisterName(self.arch.handle, self.id.into());
273
274            // We need to guarantee ownership, as if we're still
275            // a Borrowed variant we're about to free the underlying
276            // memory.
277            let res = CStr::from_ptr(name);
278            let res = res.to_string_lossy().into_owned().into();
279
280            BNFreeString(name);
281
282            res
283        }
284    }
285
286    fn info(&self) -> CoreRegisterInfo {
287        CoreRegisterInfo::new(self.arch, self.id, unsafe {
288            BNGetArchitectureRegisterInfo(self.arch.handle, self.id.into())
289        })
290    }
291
292    fn id(&self) -> RegisterId {
293        self.id
294    }
295}
296
297impl Debug for CoreRegister {
298    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
299        f.debug_struct("CoreRegister")
300            .field("id", &self.id)
301            .field("name", &self.name())
302            .finish()
303    }
304}
305
306impl CoreArrayProvider for CoreRegister {
307    type Raw = u32;
308    type Context = CoreArchitecture;
309    type Wrapped<'a> = Self;
310}
311
312unsafe impl CoreArrayProviderInner for CoreRegister {
313    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
314        BNFreeRegisterList(raw)
315    }
316
317    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
318        Self::new(*context, RegisterId::from(*raw)).expect("Register list contains valid registers")
319    }
320}
321
322#[derive(Debug, Copy, Clone)]
323pub struct CoreRegisterStackInfo {
324    arch: CoreArchitecture,
325    // TODO: Wrap BNRegisterStackInfo
326    info: BNRegisterStackInfo,
327}
328
329impl CoreRegisterStackInfo {
330    pub fn new(arch: CoreArchitecture, info: BNRegisterStackInfo) -> Self {
331        Self { arch, info }
332    }
333}
334
335impl RegisterStackInfo for CoreRegisterStackInfo {
336    type RegStackType = CoreRegisterStack;
337    type RegType = CoreRegister;
338    type RegInfoType = CoreRegisterInfo;
339
340    fn storage_regs(&self) -> (Self::RegType, usize) {
341        (
342            CoreRegister::new(self.arch, RegisterId::from(self.info.firstStorageReg))
343                .expect("Storage register is valid"),
344            self.info.storageCount as usize,
345        )
346    }
347
348    fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> {
349        if self.info.topRelativeCount == 0 {
350            None
351        } else {
352            Some((
353                CoreRegister::new(self.arch, RegisterId::from(self.info.firstTopRelativeReg))
354                    .expect("Top relative register is valid"),
355                self.info.topRelativeCount as usize,
356            ))
357        }
358    }
359
360    fn stack_top_reg(&self) -> Self::RegType {
361        CoreRegister::new(self.arch, RegisterId::from(self.info.stackTopReg))
362            .expect("Stack top register is valid")
363    }
364}
365
366#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
367pub struct CoreRegisterStack {
368    arch: CoreArchitecture,
369    id: RegisterStackId,
370}
371
372impl CoreRegisterStack {
373    pub fn new(arch: CoreArchitecture, id: RegisterStackId) -> Option<Self> {
374        let register_stack = Self { arch, id };
375        register_stack.is_valid().then_some(register_stack)
376    }
377
378    fn is_valid(&self) -> bool {
379        // We check the name to see if the stack register is actually valid.
380        let name = unsafe { BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into()) };
381        match name.is_null() {
382            true => false,
383            false => {
384                unsafe { BNFreeString(name) };
385                true
386            }
387        }
388    }
389}
390
391impl RegisterStack for CoreRegisterStack {
392    type InfoType = CoreRegisterStackInfo;
393    type RegType = CoreRegister;
394    type RegInfoType = CoreRegisterInfo;
395
396    fn name(&self) -> Cow<'_, str> {
397        unsafe {
398            let name = BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into());
399
400            // We need to guarantee ownership, as if we're still
401            // a Borrowed variant we're about to free the underlying
402            // memory.
403            let res = CStr::from_ptr(name);
404            let res = res.to_string_lossy().into_owned().into();
405
406            BNFreeString(name);
407
408            res
409        }
410    }
411
412    fn info(&self) -> CoreRegisterStackInfo {
413        CoreRegisterStackInfo::new(self.arch, unsafe {
414            BNGetArchitectureRegisterStackInfo(self.arch.handle, self.id.into())
415        })
416    }
417
418    fn id(&self) -> RegisterStackId {
419        self.id
420    }
421}