]> git.proxmox.com Git - rustc.git/blame - vendor/object-0.22.0/src/read/macho/segment.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / object-0.22.0 / src / read / macho / segment.rs
CommitLineData
f035d41b
XL
1use core::fmt::Debug;
2use core::{result, str};
3
4use crate::endian::{self, Endianness};
5use crate::macho;
6use crate::pod::{Bytes, Pod};
7use crate::read::{self, ObjectSegment, ReadError, Result};
8
9use super::{MachHeader, MachOFile, MachOLoadCommand, MachOLoadCommandIterator, Section};
10
11/// An iterator over the segments of a `MachOFile32`.
12pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness> =
13 MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>>;
14/// An iterator over the segments of a `MachOFile64`.
15pub 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)]
20pub struct MachOSegmentIterator<'data, 'file, Mach>
21where
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
29impl<'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`.
46pub type MachOSegment32<'data, 'file, Endian = Endianness> =
47 MachOSegment<'data, 'file, macho::MachHeader32<Endian>>;
48/// A segment of a `MachOFile64`.
49pub type MachOSegment64<'data, 'file, Endian = Endianness> =
50 MachOSegment<'data, 'file, macho::MachHeader64<Endian>>;
51
52/// A segment of a `MachOFile`.
53#[derive(Debug)]
54pub struct MachOSegment<'data, 'file, Mach>
55where
56 'data: 'file,
57 Mach: MachHeader,
58{
59 file: &'file MachOFile<'data, Mach>,
60 segment: &'data Mach::Segment,
61}
62
63impl<'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
71impl<'data, 'file, Mach: MachHeader> read::private::Sealed for MachOSegment<'data, 'file, Mach> {}
72
73impl<'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)]
120pub 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
178impl<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
222impl<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}