idalib/
xref.rs

1use std::marker::PhantomData;
2use std::mem;
3
4use bitflags::bitflags;
5
6use crate::ffi::xref::cref_t::*;
7use crate::ffi::xref::dref_t::*;
8use crate::ffi::xref::*;
9
10use crate::idb::IDB;
11use crate::Address;
12
13pub struct XRef<'a> {
14    inner: xrefblk_t,
15    _marker: PhantomData<&'a IDB>,
16}
17
18impl<'a> Clone for XRef<'a> {
19    fn clone(&self) -> Self {
20        Self {
21            inner: xrefblk_t {
22                from: self.inner.from,
23                to: self.inner.to,
24                iscode: self.inner.iscode,
25                type_: self.inner.type_,
26                user: self.inner.user,
27                _flags: self.inner._flags,
28            },
29            _marker: PhantomData,
30        }
31    }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
35pub enum XRefType {
36    Code(CodeRef),
37    Data(DataRef),
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
41#[repr(u8)]
42pub enum CodeRef {
43    Unknown = fl_U as _,
44    FarCall = fl_CF as _,
45    NearCall = fl_CN as _,
46    FarJump = fl_JF as _,
47    NearJump = fl_JN as _,
48    Obsolete = fl_USobsolete as _,
49    Flow = fl_F as _,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
53#[repr(u8)]
54pub enum DataRef {
55    Unknown = dr_U as _,
56    Offset = dr_O as _,
57    Write = dr_W as _,
58    Read = dr_R as _,
59    Text = dr_T as _,
60    Informational = dr_I as _,
61    EnumMember = dr_S as _,
62}
63
64bitflags! {
65    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
66    pub struct XRefFlags: u8 {
67        const USER = XREF_USER as _;
68        const TAIL = XREF_TAIL as _;
69        const BASE = XREF_BASE as _;
70    }
71}
72
73bitflags! {
74    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
75    pub struct XRefQuery: i32 {
76        const ALL = XREF_ALL as _;
77        const FAR = XREF_FAR as _;
78        const DATA = XREF_DATA as _;
79    }
80}
81
82impl<'a> XRef<'a> {
83    pub(crate) fn from_repr(inner: xrefblk_t) -> Self {
84        Self {
85            inner,
86            _marker: PhantomData,
87        }
88    }
89
90    pub fn from(&self) -> Address {
91        self.inner.from.into()
92    }
93
94    pub fn to(&self) -> Address {
95        self.inner.to.into()
96    }
97
98    pub fn flags(&self) -> XRefFlags {
99        let flags = self.inner.type_ & !(XREF_MASK as u8);
100        XRefFlags::from_bits_retain(flags)
101    }
102
103    pub fn type_(&self) -> XRefType {
104        let type_ = self.inner.type_ & (XREF_MASK as u8);
105
106        if self.is_code() {
107            XRefType::Code(unsafe { mem::transmute::<u8, CodeRef>(type_) })
108        } else {
109            XRefType::Data(unsafe { mem::transmute::<u8, DataRef>(type_) })
110        }
111    }
112
113    pub fn is_code(&self) -> bool {
114        self.inner.iscode
115    }
116
117    pub fn is_data(&self) -> bool {
118        !self.is_code()
119    }
120
121    pub fn is_user_defined(&self) -> bool {
122        self.inner.user
123    }
124
125    pub fn next_to(&self) -> Option<Self> {
126        let mut curr = self.clone();
127
128        let found = unsafe { xrefblk_t_next_to(&mut curr.inner as *mut _) };
129
130        if found {
131            Some(curr)
132        } else {
133            None
134        }
135    }
136
137    pub fn next_from(&self) -> Option<Self> {
138        let mut curr = self.clone();
139
140        let found = unsafe { xrefblk_t_next_from(&mut curr.inner as *mut _) };
141
142        if found {
143            Some(curr)
144        } else {
145            None
146        }
147    }
148}