idalib/
xref.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use std::marker::PhantomData;
use std::mem;

use bitflags::bitflags;

use crate::ffi::xref::cref_t::*;
use crate::ffi::xref::dref_t::*;
use crate::ffi::xref::*;

use crate::idb::IDB;
use crate::Address;

pub struct XRef<'a> {
    inner: xrefblk_t,
    _marker: PhantomData<&'a IDB>,
}

impl<'a> Clone for XRef<'a> {
    fn clone(&self) -> Self {
        Self {
            inner: xrefblk_t {
                from: self.inner.from,
                to: self.inner.to,
                iscode: self.inner.iscode,
                type_: self.inner.type_,
                user: self.inner.user,
                _flags: self.inner._flags,
            },
            _marker: PhantomData,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum XRefType {
    Code(CodeRef),
    Data(DataRef),
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[repr(u8)]
pub enum CodeRef {
    Unknown = fl_U as _,
    FarCall = fl_CF as _,
    NearCall = fl_CN as _,
    FarJump = fl_JF as _,
    NearJump = fl_JN as _,
    Obsolete = fl_USobsolete as _,
    Flow = fl_F as _,
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[repr(u8)]
pub enum DataRef {
    Unknown = dr_U as _,
    Offset = dr_O as _,
    Write = dr_W as _,
    Read = dr_R as _,
    Text = dr_T as _,
    Informational = dr_I as _,
    EnumMember = dr_S as _,
}

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
    pub struct XRefFlags: u8 {
        const USER = XREF_USER as _;
        const TAIL = XREF_TAIL as _;
        const BASE = XREF_BASE as _;
    }
}

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
    pub struct XRefQuery: i32 {
        const ALL = XREF_ALL as _;
        const FAR = XREF_FAR as _;
        const DATA = XREF_DATA as _;
    }
}

impl<'a> XRef<'a> {
    pub(crate) fn from_repr(inner: xrefblk_t) -> Self {
        Self {
            inner,
            _marker: PhantomData,
        }
    }

    pub fn from(&self) -> Address {
        self.inner.from.into()
    }

    pub fn to(&self) -> Address {
        self.inner.to.into()
    }

    pub fn flags(&self) -> XRefFlags {
        let flags = self.inner.type_ & !(XREF_MASK as u8);
        XRefFlags::from_bits_retain(flags)
    }

    pub fn type_(&self) -> XRefType {
        let type_ = self.inner.type_ & (XREF_MASK as u8);

        if self.is_code() {
            XRefType::Code(unsafe { mem::transmute::<u8, CodeRef>(type_) })
        } else {
            XRefType::Data(unsafe { mem::transmute::<u8, DataRef>(type_) })
        }
    }

    pub fn is_code(&self) -> bool {
        self.inner.iscode
    }

    pub fn is_data(&self) -> bool {
        !self.is_code()
    }

    pub fn is_user_defined(&self) -> bool {
        self.inner.user
    }

    pub fn next_to(&self) -> Option<Self> {
        let mut curr = self.clone();

        let found = unsafe { xrefblk_t_next_to(&mut curr.inner as *mut _) };

        if found {
            Some(curr)
        } else {
            None
        }
    }

    pub fn next_from(&self) -> Option<Self> {
        let mut curr = self.clone();

        let found = unsafe { xrefblk_t_next_from(&mut curr.inner as *mut _) };

        if found {
            Some(curr)
        } else {
            None
        }
    }
}