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