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, 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
160#[derive(Debug, Clone, Copy)]
161pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> {
162 pub segment: &'data Mach::Segment,
163 pub data: R,
168}
169
170#[allow(missing_docs)]
172pub trait Segment: Debug + Pod {
173 type Word: Into<u64>;
174 type Endian: endian::Endian;
175 type Section: Section<Endian = Self::Endian>;
176
177 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>>;
178
179 fn cmd(&self, endian: Self::Endian) -> u32;
180 fn cmdsize(&self, endian: Self::Endian) -> u32;
181 fn segname(&self) -> &[u8; 16];
182 fn vmaddr(&self, endian: Self::Endian) -> Self::Word;
183 fn vmsize(&self, endian: Self::Endian) -> Self::Word;
184 fn fileoff(&self, endian: Self::Endian) -> Self::Word;
185 fn filesize(&self, endian: Self::Endian) -> Self::Word;
186 fn maxprot(&self, endian: Self::Endian) -> u32;
187 fn initprot(&self, endian: Self::Endian) -> u32;
188 fn nsects(&self, endian: Self::Endian) -> u32;
189 fn flags(&self, endian: Self::Endian) -> u32;
190
191 fn name(&self) -> &[u8] {
193 let segname = &self.segname()[..];
194 match memchr::memchr(b'\0', segname) {
195 Some(end) => &segname[..end],
196 None => segname,
197 }
198 }
199
200 fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
202 (self.fileoff(endian).into(), self.filesize(endian).into())
203 }
204
205 fn data<'data, R: ReadRef<'data>>(
209 &self,
210 endian: Self::Endian,
211 data: R,
212 ) -> result::Result<&'data [u8], ()> {
213 let (offset, size) = self.file_range(endian);
214 data.read_bytes_at(offset, size)
215 }
216
217 fn sections<'data, R: ReadRef<'data>>(
221 &self,
222 endian: Self::Endian,
223 section_data: R,
224 ) -> Result<&'data [Self::Section]> {
225 section_data
226 .read_slice_at(0, self.nsects(endian) as usize)
227 .read_error("Invalid Mach-O number of sections")
228 }
229}
230
231impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> {
232 type Word = u32;
233 type Endian = Endian;
234 type Section = macho::Section32<Self::Endian>;
235
236 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
237 command.segment_32()
238 }
239
240 fn cmd(&self, endian: Self::Endian) -> u32 {
241 self.cmd.get(endian)
242 }
243 fn cmdsize(&self, endian: Self::Endian) -> u32 {
244 self.cmdsize.get(endian)
245 }
246 fn segname(&self) -> &[u8; 16] {
247 &self.segname
248 }
249 fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
250 self.vmaddr.get(endian)
251 }
252 fn vmsize(&self, endian: Self::Endian) -> Self::Word {
253 self.vmsize.get(endian)
254 }
255 fn fileoff(&self, endian: Self::Endian) -> Self::Word {
256 self.fileoff.get(endian)
257 }
258 fn filesize(&self, endian: Self::Endian) -> Self::Word {
259 self.filesize.get(endian)
260 }
261 fn maxprot(&self, endian: Self::Endian) -> u32 {
262 self.maxprot.get(endian)
263 }
264 fn initprot(&self, endian: Self::Endian) -> u32 {
265 self.initprot.get(endian)
266 }
267 fn nsects(&self, endian: Self::Endian) -> u32 {
268 self.nsects.get(endian)
269 }
270 fn flags(&self, endian: Self::Endian) -> u32 {
271 self.flags.get(endian)
272 }
273}
274
275impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> {
276 type Word = u64;
277 type Endian = Endian;
278 type Section = macho::Section64<Self::Endian>;
279
280 fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> {
281 command.segment_64()
282 }
283
284 fn cmd(&self, endian: Self::Endian) -> u32 {
285 self.cmd.get(endian)
286 }
287 fn cmdsize(&self, endian: Self::Endian) -> u32 {
288 self.cmdsize.get(endian)
289 }
290 fn segname(&self) -> &[u8; 16] {
291 &self.segname
292 }
293 fn vmaddr(&self, endian: Self::Endian) -> Self::Word {
294 self.vmaddr.get(endian)
295 }
296 fn vmsize(&self, endian: Self::Endian) -> Self::Word {
297 self.vmsize.get(endian)
298 }
299 fn fileoff(&self, endian: Self::Endian) -> Self::Word {
300 self.fileoff.get(endian)
301 }
302 fn filesize(&self, endian: Self::Endian) -> Self::Word {
303 self.filesize.get(endian)
304 }
305 fn maxprot(&self, endian: Self::Endian) -> u32 {
306 self.maxprot.get(endian)
307 }
308 fn initprot(&self, endian: Self::Endian) -> u32 {
309 self.initprot.get(endian)
310 }
311 fn nsects(&self, endian: Self::Endian) -> u32 {
312 self.nsects.get(endian)
313 }
314 fn flags(&self, endian: Self::Endian) -> u32 {
315 self.flags.get(endian)
316 }
317}