1use core::fmt::Debug;
2use core::{result, slice, str};
3
4use crate::endian::{self, Endianness};
5use crate::macho;
6use crate::pod::Pod;
7use crate::read::{self, ObjectSegment, Permissions, ReadError, ReadRef, Result, SegmentFlags};
8
9use super::{LoadCommandData, MachHeader, MachOFile, Section};
10
11pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
13 MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
14pub type MachOSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
16 MachOSegmentIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
17
18#[derive(Debug)]
20pub struct MachOSegmentIterator<'data, 'file, Mach, R = &'data [u8]>
21where
22 Mach: MachHeader,
23 R: ReadRef<'data>,
24{
25 pub(super) file: &'file MachOFile<'data, Mach, R>,
26 pub(super) iter: slice::Iter<'file, MachOSegmentInternal<'data, Mach, R>>,
27}
28
29impl<'data, 'file, Mach, R> Iterator for MachOSegmentIterator<'data, 'file, Mach, R>
30where
31 Mach: MachHeader,
32 R: ReadRef<'data>,
33{
34 type Item = MachOSegment<'data, 'file, Mach, R>;
35
36 fn next(&mut self) -> Option<Self::Item> {
37 self.iter.next().map(|internal| MachOSegment {
38 file: self.file,
39 internal,
40 })
41 }
42}
43
44pub type MachOSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
46 MachOSegment<'data, 'file, macho::MachHeader32<Endian>, R>;
47pub type MachOSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
49 MachOSegment<'data, 'file, macho::MachHeader64<Endian>, R>;
50
51#[derive(Debug)]
55pub struct MachOSegment<'data, 'file, Mach, R = &'data [u8]>
56where
57 Mach: MachHeader,
58 R: ReadRef<'data>,
59{
60 file: &'file MachOFile<'data, Mach, R>,
61 internal: &'file MachOSegmentInternal<'data, Mach, R>,
62}
63
64impl<'data, 'file, Mach, R> MachOSegment<'data, 'file, Mach, R>
65where
66 Mach: MachHeader,
67 R: ReadRef<'data>,
68{
69 pub fn macho_file(&self) -> &'file MachOFile<'data, Mach, R> {
71 self.file
72 }
73
74 pub fn macho_segment(&self) -> &'data Mach::Segment {
76 self.internal.segment
77 }
78
79 fn bytes(&self) -> Result<&'data [u8]> {
80 self.internal
81 .segment
82 .data(self.file.endian, self.internal.data)
83 .read_error("Invalid Mach-O segment size or offset")
84 }
85}
86
87impl<'data, 'file, Mach, R> read::private::Sealed for MachOSegment<'data, 'file, Mach, R>
88where
89 Mach: MachHeader,
90 R: ReadRef<'data>,
91{
92}
93
94impl<'data, 'file, Mach, R> ObjectSegment<'data> for MachOSegment<'data, 'file, Mach, R>
95where
96 Mach: MachHeader,
97 R: ReadRef<'data>,
98{
99 #[inline]
100 fn address(&self) -> u64 {
101 self.internal.segment.vmaddr(self.file.endian).into()
102 }
103
104 #[inline]
105 fn size(&self) -> u64 {
106 self.internal.segment.vmsize(self.file.endian).into()
107 }
108
109 #[inline]
110 fn align(&self) -> u64 {
111 0x1000
113 }
114
115 #[inline]
116 fn file_range(&self) -> (u64, u64) {
117 self.internal.segment.file_range(self.file.endian)
118 }
119
120 fn data(&self) -> Result<&'data [u8]> {
121 self.bytes()
122 }
123
124 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
125 Ok(read::util::data_range(
126 self.bytes()?,
127 self.address(),
128 address,
129 size,
130 ))
131 }
132
133 #[inline]
134 fn name_bytes(&self) -> Result<Option<&[u8]>> {
135 Ok(Some(self.internal.segment.name()))
136 }
137
138 #[inline]
139 fn name(&self) -> Result<Option<&str>> {
140 Ok(Some(
141 str::from_utf8(self.internal.segment.name())
142 .ok()
143 .read_error("Non UTF-8 Mach-O segment name")?,
144 ))
145 }
146
147 #[inline]
148 fn flags(&self) -> SegmentFlags {
149 let flags = self.internal.segment.flags(self.file.endian);
150 let maxprot = self.internal.segment.maxprot(self.file.endian);
151 let initprot = self.internal.segment.initprot(self.file.endian);
152 SegmentFlags::MachO {
153 flags,
154 maxprot,
155 initprot,
156 }
157 }
158
159 #[inline]
160 fn permissions(&self) -> Permissions {
161 let maxprot = self.internal.segment.maxprot(self.file.endian);
162 Permissions::new(
163 maxprot & macho::VM_PROT_READ != 0,
164 maxprot & macho::VM_PROT_WRITE != 0,
165 maxprot & macho::VM_PROT_EXECUTE != 0,
166 )
167 }
168}
169
170#[derive(Debug, Clone, Copy)]
171pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> {
172 pub segment: &'data Mach::Segment,
173 pub data: R,
178}
179
180#[allow(missing_docs)]
182pub trait Segment: Debug + Pod {
183 type Word: Into<u64>;
184 type Endian: endian::Endian;
185 type Section: Section<Endian = Self::Endian>;
186
187 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>>;
188
189 fn cmd(&self, endian: Self::Endian) -> u32;
190 fn cmdsize(&self, endian: Self::Endian) -> u32;
191 fn segname(&self) -> &[u8; 16];
192 fn vmaddr(&self, endian: Self::Endian) -> Self::Word;
193 fn vmsize(&self, endian: Self::Endian) -> Self::Word;
194 fn fileoff(&self, endian: Self::Endian) -> Self::Word;
195 fn filesize(&self, endian: Self::Endian) -> Self::Word;
196 fn maxprot(&self, endian: Self::Endian) -> u32;
197 fn initprot(&self, endian: Self::Endian) -> u32;
198 fn nsects(&self, endian: Self::Endian) -> u32;
199 fn flags(&self, endian: Self::Endian) -> u32;
200
201 fn name(&self) -> &[u8] {
203 let segname = &self.segname()[..];
204 match memchr::memchr(b'\0', segname) {
205 Some(end) => &segname[..end],
206 None => segname,
207 }
208 }
209
210 fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
212 (self.fileoff(endian).into(), self.filesize(endian).into())
213 }
214
215 fn data<'data, R: ReadRef<'data>>(
219 &self,
220 endian: Self::Endian,
221 data: R,
222 ) -> result::Result<&'data [u8], ()> {
223 let (offset, size) = self.file_range(endian);
224 data.read_bytes_at(offset, size)
225 }
226
227 fn sections<'data, R: ReadRef<'data>>(
231 &self,
232 endian: Self::Endian,
233 section_data: R,
234 ) -> Result<&'data [Self::Section]> {
235 section_data
236 .read_slice_at(0, self.nsects(endian) as usize)
237 .read_error("Invalid Mach-O number of sections")
238 }
239}
240
241impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> {
242 type Word = u32;
243 type Endian = Endian;
244 type Section = macho::Section32<Self::Endian>;
245
246 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
247 command.segment_32()
248 }
249
250 fn cmd(&self, endian: Self::Endian) -> u32 {
251 self.cmd.get(endian)
252 }
253 fn cmdsize(&self, endian: Self::Endian) -> u32 {
254 self.cmdsize.get(endian)
255 }
256 fn segname(&self) -> &[u8; 16] {
257 &self.segname
258 }
259 fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
260 self.vmaddr.get(endian)
261 }
262 fn vmsize(&self, endian: Self::Endian) -> Self::Word {
263 self.vmsize.get(endian)
264 }
265 fn fileoff(&self, endian: Self::Endian) -> Self::Word {
266 self.fileoff.get(endian)
267 }
268 fn filesize(&self, endian: Self::Endian) -> Self::Word {
269 self.filesize.get(endian)
270 }
271 fn maxprot(&self, endian: Self::Endian) -> u32 {
272 self.maxprot.get(endian)
273 }
274 fn initprot(&self, endian: Self::Endian) -> u32 {
275 self.initprot.get(endian)
276 }
277 fn nsects(&self, endian: Self::Endian) -> u32 {
278 self.nsects.get(endian)
279 }
280 fn flags(&self, endian: Self::Endian) -> u32 {
281 self.flags.get(endian)
282 }
283}
284
285impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> {
286 type Word = u64;
287 type Endian = Endian;
288 type Section = macho::Section64<Self::Endian>;
289
290 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
291 command.segment_64()
292 }
293
294 fn cmd(&self, endian: Self::Endian) -> u32 {
295 self.cmd.get(endian)
296 }
297 fn cmdsize(&self, endian: Self::Endian) -> u32 {
298 self.cmdsize.get(endian)
299 }
300 fn segname(&self) -> &[u8; 16] {
301 &self.segname
302 }
303 fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
304 self.vmaddr.get(endian)
305 }
306 fn vmsize(&self, endian: Self::Endian) -> Self::Word {
307 self.vmsize.get(endian)
308 }
309 fn fileoff(&self, endian: Self::Endian) -> Self::Word {
310 self.fileoff.get(endian)
311 }
312 fn filesize(&self, endian: Self::Endian) -> Self::Word {
313 self.filesize.get(endian)
314 }
315 fn maxprot(&self, endian: Self::Endian) -> u32 {
316 self.maxprot.get(endian)
317 }
318 fn initprot(&self, endian: Self::Endian) -> u32 {
319 self.initprot.get(endian)
320 }
321 fn nsects(&self, endian: Self::Endian) -> u32 {
322 self.nsects.get(endian)
323 }
324 fn flags(&self, endian: Self::Endian) -> u32 {
325 self.flags.get(endian)
326 }
327}