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}