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