1 | use core::fmt::Debug; |
2 | use core::{result, slice, str}; |
3 | |
4 | use crate::endian::{self, Endianness}; |
5 | use crate::macho; |
6 | use crate::pod::Pod; |
7 | use crate::read::{self, ObjectSegment, ReadError, ReadRef, Result, SegmentFlags}; |
8 | |
9 | use super::{LoadCommandData, MachHeader, MachOFile, Section}; |
10 | |
11 | /// An iterator for the segments in a [`MachOFile32`](super::MachOFile32). |
12 | pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = |
13 | MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>, R>; |
14 | /// An iterator for the segments in a [`MachOFile64`](super::MachOFile64). |
15 | pub type MachOSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = |
16 | MachOSegmentIterator<'data, 'file, macho::MachHeader64<Endian>, R>; |
17 | |
18 | /// An iterator for the segments in a [`MachOFile`]. |
19 | #[derive (Debug)] |
20 | pub struct MachOSegmentIterator<'data, 'file, Mach, R = &'data [u8]> |
21 | where |
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 | |
29 | impl<'data, 'file, Mach, R> Iterator for MachOSegmentIterator<'data, 'file, Mach, R> |
30 | where |
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: &MachOSegmentInternal<'_, …, …>| MachOSegment { |
38 | file: self.file, |
39 | internal, |
40 | }) |
41 | } |
42 | } |
43 | |
44 | /// A segment in a [`MachOFile32`](super::MachOFile32). |
45 | pub type MachOSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> = |
46 | MachOSegment<'data, 'file, macho::MachHeader32<Endian>, R>; |
47 | /// A segment in a [`MachOFile64`](super::MachOFile64). |
48 | pub type MachOSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = |
49 | MachOSegment<'data, 'file, macho::MachHeader64<Endian>, R>; |
50 | |
51 | /// A segment in a [`MachOFile`]. |
52 | /// |
53 | /// Most functionality is provided by the [`ObjectSegment`] trait implementation. |
54 | #[derive (Debug)] |
55 | pub struct MachOSegment<'data, 'file, Mach, R = &'data [u8]> |
56 | where |
57 | Mach: MachHeader, |
58 | R: ReadRef<'data>, |
59 | { |
60 | file: &'file MachOFile<'data, Mach, R>, |
61 | internal: &'file MachOSegmentInternal<'data, Mach, R>, |
62 | } |
63 | |
64 | impl<'data, 'file, Mach, R> MachOSegment<'data, 'file, Mach, R> |
65 | where |
66 | Mach: MachHeader, |
67 | R: ReadRef<'data>, |
68 | { |
69 | fn bytes(&self) -> Result<&'data [u8]> { |
70 | self.internal |
71 | .segment |
72 | .data(self.file.endian, self.file.data) |
73 | .read_error("Invalid Mach-O segment size or offset" ) |
74 | } |
75 | } |
76 | |
77 | impl<'data, 'file, Mach, R> read::private::Sealed for MachOSegment<'data, 'file, Mach, R> |
78 | where |
79 | Mach: MachHeader, |
80 | R: ReadRef<'data>, |
81 | { |
82 | } |
83 | |
84 | impl<'data, 'file, Mach, R> ObjectSegment<'data> for MachOSegment<'data, 'file, Mach, R> |
85 | where |
86 | Mach: MachHeader, |
87 | R: ReadRef<'data>, |
88 | { |
89 | #[inline ] |
90 | fn address(&self) -> u64 { |
91 | self.internal.segment.vmaddr(self.file.endian).into() |
92 | } |
93 | |
94 | #[inline ] |
95 | fn size(&self) -> u64 { |
96 | self.internal.segment.vmsize(self.file.endian).into() |
97 | } |
98 | |
99 | #[inline ] |
100 | fn align(&self) -> u64 { |
101 | // Page size. |
102 | 0x1000 |
103 | } |
104 | |
105 | #[inline ] |
106 | fn file_range(&self) -> (u64, u64) { |
107 | self.internal.segment.file_range(self.file.endian) |
108 | } |
109 | |
110 | fn data(&self) -> Result<&'data [u8]> { |
111 | self.bytes() |
112 | } |
113 | |
114 | fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { |
115 | Ok(read::util::data_range( |
116 | self.bytes()?, |
117 | self.address(), |
118 | address, |
119 | size, |
120 | )) |
121 | } |
122 | |
123 | #[inline ] |
124 | fn name_bytes(&self) -> Result<Option<&[u8]>> { |
125 | Ok(Some(self.internal.segment.name())) |
126 | } |
127 | |
128 | #[inline ] |
129 | fn name(&self) -> Result<Option<&str>> { |
130 | Ok(Some( |
131 | str::from_utf8(self.internal.segment.name()) |
132 | .ok() |
133 | .read_error("Non UTF-8 Mach-O segment name" )?, |
134 | )) |
135 | } |
136 | |
137 | #[inline ] |
138 | fn flags(&self) -> SegmentFlags { |
139 | let flags = self.internal.segment.flags(self.file.endian); |
140 | let maxprot = self.internal.segment.maxprot(self.file.endian); |
141 | let initprot = self.internal.segment.initprot(self.file.endian); |
142 | SegmentFlags::MachO { |
143 | flags, |
144 | maxprot, |
145 | initprot, |
146 | } |
147 | } |
148 | } |
149 | |
150 | #[derive (Debug, Clone, Copy)] |
151 | pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> { |
152 | pub data: R, |
153 | pub segment: &'data Mach::Segment, |
154 | } |
155 | |
156 | /// A trait for generic access to [`macho::SegmentCommand32`] and [`macho::SegmentCommand64`]. |
157 | #[allow (missing_docs)] |
158 | pub trait Segment: Debug + Pod { |
159 | type Word: Into<u64>; |
160 | type Endian: endian::Endian; |
161 | type Section: Section<Endian = Self::Endian>; |
162 | |
163 | fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>>; |
164 | |
165 | fn cmd(&self, endian: Self::Endian) -> u32; |
166 | fn cmdsize(&self, endian: Self::Endian) -> u32; |
167 | fn segname(&self) -> &[u8; 16]; |
168 | fn vmaddr(&self, endian: Self::Endian) -> Self::Word; |
169 | fn vmsize(&self, endian: Self::Endian) -> Self::Word; |
170 | fn fileoff(&self, endian: Self::Endian) -> Self::Word; |
171 | fn filesize(&self, endian: Self::Endian) -> Self::Word; |
172 | fn maxprot(&self, endian: Self::Endian) -> u32; |
173 | fn initprot(&self, endian: Self::Endian) -> u32; |
174 | fn nsects(&self, endian: Self::Endian) -> u32; |
175 | fn flags(&self, endian: Self::Endian) -> u32; |
176 | |
177 | /// Return the `segname` bytes up until the null terminator. |
178 | fn name(&self) -> &[u8] { |
179 | let segname = &self.segname()[..]; |
180 | match memchr::memchr(b' \0' , segname) { |
181 | Some(end) => &segname[..end], |
182 | None => segname, |
183 | } |
184 | } |
185 | |
186 | /// Return the offset and size of the segment in the file. |
187 | fn file_range(&self, endian: Self::Endian) -> (u64, u64) { |
188 | (self.fileoff(endian).into(), self.filesize(endian).into()) |
189 | } |
190 | |
191 | /// Get the segment data from the file data. |
192 | /// |
193 | /// Returns `Err` for invalid values. |
194 | fn data<'data, R: ReadRef<'data>>( |
195 | &self, |
196 | endian: Self::Endian, |
197 | data: R, |
198 | ) -> result::Result<&'data [u8], ()> { |
199 | let (offset, size) = self.file_range(endian); |
200 | data.read_bytes_at(offset, size) |
201 | } |
202 | |
203 | /// Get the array of sections from the data following the segment command. |
204 | /// |
205 | /// Returns `Err` for invalid values. |
206 | fn sections<'data, R: ReadRef<'data>>( |
207 | &self, |
208 | endian: Self::Endian, |
209 | section_data: R, |
210 | ) -> Result<&'data [Self::Section]> { |
211 | section_data |
212 | .read_slice_at(0, self.nsects(endian) as usize) |
213 | .read_error("Invalid Mach-O number of sections" ) |
214 | } |
215 | } |
216 | |
217 | impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> { |
218 | type Word = u32; |
219 | type Endian = Endian; |
220 | type Section = macho::Section32<Self::Endian>; |
221 | |
222 | fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> { |
223 | command.segment_32() |
224 | } |
225 | |
226 | fn cmd(&self, endian: Self::Endian) -> u32 { |
227 | self.cmd.get(endian) |
228 | } |
229 | fn cmdsize(&self, endian: Self::Endian) -> u32 { |
230 | self.cmdsize.get(endian) |
231 | } |
232 | fn segname(&self) -> &[u8; 16] { |
233 | &self.segname |
234 | } |
235 | fn vmaddr(&self, endian: Self::Endian) -> Self::Word { |
236 | self.vmaddr.get(endian) |
237 | } |
238 | fn vmsize(&self, endian: Self::Endian) -> Self::Word { |
239 | self.vmsize.get(endian) |
240 | } |
241 | fn fileoff(&self, endian: Self::Endian) -> Self::Word { |
242 | self.fileoff.get(endian) |
243 | } |
244 | fn filesize(&self, endian: Self::Endian) -> Self::Word { |
245 | self.filesize.get(endian) |
246 | } |
247 | fn maxprot(&self, endian: Self::Endian) -> u32 { |
248 | self.maxprot.get(endian) |
249 | } |
250 | fn initprot(&self, endian: Self::Endian) -> u32 { |
251 | self.initprot.get(endian) |
252 | } |
253 | fn nsects(&self, endian: Self::Endian) -> u32 { |
254 | self.nsects.get(endian) |
255 | } |
256 | fn flags(&self, endian: Self::Endian) -> u32 { |
257 | self.flags.get(endian) |
258 | } |
259 | } |
260 | |
261 | impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> { |
262 | type Word = u64; |
263 | type Endian = Endian; |
264 | type Section = macho::Section64<Self::Endian>; |
265 | |
266 | fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> { |
267 | command.segment_64() |
268 | } |
269 | |
270 | fn cmd(&self, endian: Self::Endian) -> u32 { |
271 | self.cmd.get(endian) |
272 | } |
273 | fn cmdsize(&self, endian: Self::Endian) -> u32 { |
274 | self.cmdsize.get(endian) |
275 | } |
276 | fn segname(&self) -> &[u8; 16] { |
277 | &self.segname |
278 | } |
279 | fn vmaddr(&self, endian: Self::Endian) -> Self::Word { |
280 | self.vmaddr.get(endian) |
281 | } |
282 | fn vmsize(&self, endian: Self::Endian) -> Self::Word { |
283 | self.vmsize.get(endian) |
284 | } |
285 | fn fileoff(&self, endian: Self::Endian) -> Self::Word { |
286 | self.fileoff.get(endian) |
287 | } |
288 | fn filesize(&self, endian: Self::Endian) -> Self::Word { |
289 | self.filesize.get(endian) |
290 | } |
291 | fn maxprot(&self, endian: Self::Endian) -> u32 { |
292 | self.maxprot.get(endian) |
293 | } |
294 | fn initprot(&self, endian: Self::Endian) -> u32 { |
295 | self.initprot.get(endian) |
296 | } |
297 | fn nsects(&self, endian: Self::Endian) -> u32 { |
298 | self.nsects.get(endian) |
299 | } |
300 | fn flags(&self, endian: Self::Endian) -> u32 { |
301 | self.flags.get(endian) |
302 | } |
303 | } |
304 | |