idalib/
segment.rs

1use std::marker::PhantomData;
2use std::mem;
3use std::pin::Pin;
4
5use autocxx::moveit::Emplace;
6use bitflags::bitflags;
7
8use crate::ffi::range_t;
9use crate::ffi::segment::*;
10use crate::idb::IDB;
11use crate::Address;
12
13pub struct Segment<'a> {
14    ptr: *mut segment_t,
15    _lock: Pin<Box<lock_segment>>,
16    _marker: PhantomData<&'a IDB>,
17}
18
19pub type SegmentId = usize;
20
21bitflags! {
22    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
23    pub struct SegmentPermissions: u8 {
24        const EXEC = SEGPERM_EXEC as _;
25        const WRITE = SEGPERM_WRITE as _;
26        const READ = SEGPERM_READ as _;
27    }
28}
29
30impl SegmentPermissions {
31    pub fn is_executable(&self) -> bool {
32        self.contains(SegmentPermissions::EXEC)
33    }
34
35    pub fn is_writable(&self) -> bool {
36        self.contains(SegmentPermissions::WRITE)
37    }
38
39    pub fn is_readable(&self) -> bool {
40        self.contains(SegmentPermissions::READ)
41    }
42}
43
44#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[repr(u8)]
46pub enum SegmentAlignment {
47    Abs = saAbs as _,
48    RelByte = saRelByte as _,
49    RelWord = saRelWord as _,
50    RelPara = saRelPara as _,
51    RelPage = saRelPage as _,
52    RelDble = saRelDble as _,
53    Rel4K = saRel4K as _,
54    Group = saGroup as _,
55    Rel32Bytes = saRel32Bytes as _,
56    Rel64Bytes = saRel64Bytes as _,
57    RelQword = saRelQword as _,
58    Rel128Bytes = saRel128Bytes as _,
59    Rel512Bytes = saRel512Bytes as _,
60    Rel1024Bytes = saRel1024Bytes as _,
61    Rel2048Bytes = saRel2048Bytes as _,
62}
63
64impl SegmentAlignment {
65    pub fn is_abs(&self) -> bool {
66        matches!(self, Self::Abs)
67    }
68
69    pub fn is_rel_byte(&self) -> bool {
70        matches!(self, Self::RelByte)
71    }
72
73    pub fn is_rel_word(&self) -> bool {
74        matches!(self, Self::RelWord)
75    }
76
77    pub fn is_rel_para(&self) -> bool {
78        matches!(self, Self::RelPara)
79    }
80
81    pub fn is_rel_page(&self) -> bool {
82        matches!(self, Self::RelPage)
83    }
84
85    pub fn is_rel_dble(&self) -> bool {
86        matches!(self, Self::RelDble)
87    }
88
89    pub fn is_rel_4k(&self) -> bool {
90        matches!(self, Self::Rel4K)
91    }
92
93    pub fn is_group(&self) -> bool {
94        matches!(self, Self::Group)
95    }
96
97    pub fn is_rel_32_bytes(&self) -> bool {
98        matches!(self, Self::Rel32Bytes)
99    }
100
101    pub fn is_rel_64_bytes(&self) -> bool {
102        matches!(self, Self::Rel64Bytes)
103    }
104
105    pub fn is_rel_qword(&self) -> bool {
106        matches!(self, Self::RelQword)
107    }
108
109    pub fn is_rel_128_bytes(&self) -> bool {
110        matches!(self, Self::Rel128Bytes)
111    }
112
113    pub fn is_rel_512_bytes(&self) -> bool {
114        matches!(self, Self::Rel512Bytes)
115    }
116
117    pub fn is_rel_1024_bytes(&self) -> bool {
118        matches!(self, Self::Rel1024Bytes)
119    }
120
121    pub fn is_rel_2048_bytes(&self) -> bool {
122        matches!(self, Self::Rel2048Bytes)
123    }
124}
125
126#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
127#[repr(u8)]
128pub enum SegmentType {
129    NORM = SEG_NORM as _,
130    XTRN = SEG_XTRN as _,
131    CODE = SEG_CODE as _,
132    DATA = SEG_DATA as _,
133    IMP = SEG_IMP as _,
134    GRP = SEG_GRP as _,
135    NULL = SEG_NULL as _,
136    UNDF = SEG_UNDF as _,
137    BSS = SEG_BSS as _,
138    ABSSYM = SEG_ABSSYM as _,
139    COMM = SEG_COMM as _,
140    IMEM = SEG_IMEM as _,
141}
142
143impl SegmentType {
144    pub fn is_normal(&self) -> bool {
145        matches!(self, Self::NORM)
146    }
147
148    pub fn is_norm(&self) -> bool {
149        self.is_normal()
150    }
151
152    pub fn is_extern(&self) -> bool {
153        matches!(self, Self::XTRN)
154    }
155
156    pub fn is_xtrn(&self) -> bool {
157        self.is_extern()
158    }
159
160    pub fn is_code(&self) -> bool {
161        matches!(self, Self::CODE)
162    }
163
164    pub fn is_data(&self) -> bool {
165        matches!(self, Self::DATA)
166    }
167
168    pub fn is_import(&self) -> bool {
169        matches!(self, Self::IMP)
170    }
171
172    pub fn is_imp(&self) -> bool {
173        self.is_import()
174    }
175
176    pub fn is_group(&self) -> bool {
177        matches!(self, Self::GRP)
178    }
179
180    pub fn is_grp(&self) -> bool {
181        self.is_group()
182    }
183
184    pub fn is_bss(&self) -> bool {
185        matches!(self, Self::BSS)
186    }
187
188    pub fn is_null(&self) -> bool {
189        matches!(self, Self::NULL)
190    }
191
192    pub fn is_absym(&self) -> bool {
193        matches!(self, Self::ABSSYM)
194    }
195
196    pub fn is_comm(&self) -> bool {
197        matches!(self, Self::COMM)
198    }
199
200    pub fn is_imem(&self) -> bool {
201        matches!(self, Self::IMEM)
202    }
203
204    pub fn is_undefined(&self) -> bool {
205        matches!(self, Self::UNDF)
206    }
207
208    pub fn is_undf(&self) -> bool {
209        self.is_undefined()
210    }
211}
212
213impl<'a> Segment<'a> {
214    pub(crate) fn from_ptr(ptr: *mut segment_t) -> Self {
215        let lock = unsafe { Box::emplace(lock_segment::new(ptr)) };
216        Self {
217            ptr,
218            _lock: lock,
219            _marker: PhantomData,
220        }
221    }
222
223    fn as_range_t(&self) -> *const range_t {
224        self.ptr.cast()
225    }
226
227    pub fn start_address(&self) -> Address {
228        unsafe { (*self.as_range_t()).start_ea.into() }
229    }
230
231    pub fn end_address(&self) -> Address {
232        unsafe { (*self.as_range_t()).end_ea.into() }
233    }
234
235    pub fn len(&self) -> usize {
236        unsafe { (*self.as_range_t()).size().0 as _ }
237    }
238
239    pub fn is_empty(&self) -> bool {
240        self.len() == 0
241    }
242
243    pub fn contains_address(&self, addr: Address) -> bool {
244        unsafe { (*self.as_range_t()).contains(addr.into()) }
245    }
246
247    pub fn name(&self) -> Option<String> {
248        let name = unsafe { idalib_segm_name(self.ptr) }.ok()?;
249
250        if name.is_empty() {
251            None
252        } else {
253            Some(name)
254        }
255    }
256
257    pub fn alignment(&self) -> SegmentAlignment {
258        unsafe { mem::transmute(idalib_segm_align(self.ptr)) }
259    }
260
261    pub fn permissions(&self) -> SegmentPermissions {
262        let bits = unsafe { idalib_segm_perm(self.ptr) };
263        SegmentPermissions::from_bits_retain(bits)
264    }
265
266    pub fn bitness(&self) -> usize {
267        (unsafe { idalib_segm_bitness(self.ptr) }) as usize
268    }
269
270    pub fn r#type(&self) -> SegmentType {
271        unsafe { mem::transmute(idalib_segm_type(self.ptr)) }
272    }
273
274    pub fn bytes(&self) -> Vec<u8> {
275        let size = self.len();
276        let mut buf = Vec::with_capacity(size);
277
278        let Ok(new_len) = (unsafe { idalib_segm_bytes(self.ptr, &mut buf) }) else {
279            return Vec::with_capacity(0);
280        };
281
282        unsafe {
283            buf.set_len(new_len);
284        }
285
286        buf
287    }
288
289    pub fn address_bits(&self) -> u32 {
290        unsafe { (*self.ptr).abits().0 as _ }
291    }
292
293    pub fn address_bytes(&self) -> usize {
294        unsafe { (*self.ptr).abytes().0 as _ }
295    }
296
297    pub fn is_16bit(&self) -> bool {
298        unsafe { (*self.ptr).is_16bit() }
299    }
300
301    pub fn is_32bit(&self) -> bool {
302        unsafe { (*self.ptr).is_32bit() }
303    }
304
305    pub fn is_64bit(&self) -> bool {
306        unsafe { (*self.ptr).is_64bit() }
307    }
308
309    pub fn is_hidden(&self) -> bool {
310        unsafe { (*self.ptr).is_hidden_segtype() }
311    }
312
313    pub fn is_loader(&self) -> bool {
314        unsafe { (*self.ptr).is_loader_segm() }
315    }
316
317    pub fn is_header(&self) -> bool {
318        unsafe { (*self.ptr).is_header_segm() }
319    }
320
321    pub fn is_ephemeral(&self) -> bool {
322        unsafe { (*self.ptr).is_ephemeral_segm() }
323    }
324
325    pub fn is_debugger(&self) -> bool {
326        unsafe { (*self.ptr).is_debugger_segm() }
327    }
328
329    pub fn is_visible(&self) -> bool {
330        unsafe { (*self.ptr).is_visible_segm() }
331    }
332}