]> git.proxmox.com Git - rustc.git/blob - vendor/object/src/read/macho/load_command.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / vendor / object / src / read / macho / load_command.rs
1 use core::marker::PhantomData;
2
3 use crate::endian::Endian;
4 use crate::macho;
5 use crate::pod::{Bytes, Pod};
6 use crate::read::macho::{MachHeader, SymbolTable};
7 use crate::read::{ReadError, ReadRef, Result, StringTable};
8
9 /// An iterator over the load commands of a `MachHeader`.
10 #[derive(Debug, Default, Clone, Copy)]
11 pub struct LoadCommandIterator<'data, E: Endian> {
12 endian: E,
13 data: Bytes<'data>,
14 ncmds: u32,
15 }
16
17 impl<'data, E: Endian> LoadCommandIterator<'data, E> {
18 pub(super) fn new(endian: E, data: &'data [u8], ncmds: u32) -> Self {
19 LoadCommandIterator {
20 endian,
21 data: Bytes(data),
22 ncmds,
23 }
24 }
25
26 /// Return the next load command.
27 pub fn next(&mut self) -> Result<Option<LoadCommandData<'data, E>>> {
28 if self.ncmds == 0 {
29 return Ok(None);
30 }
31 let header = self
32 .data
33 .read_at::<macho::LoadCommand<E>>(0)
34 .read_error("Invalid Mach-O load command header")?;
35 let cmd = header.cmd.get(self.endian);
36 let cmdsize = header.cmdsize.get(self.endian) as usize;
37 let data = self
38 .data
39 .read_bytes(cmdsize)
40 .read_error("Invalid Mach-O load command size")?;
41 self.ncmds -= 1;
42 Ok(Some(LoadCommandData {
43 cmd,
44 data,
45 marker: Default::default(),
46 }))
47 }
48 }
49
50 /// The data for a `LoadCommand`.
51 #[derive(Debug, Clone, Copy)]
52 pub struct LoadCommandData<'data, E: Endian> {
53 cmd: u32,
54 // Includes the header.
55 data: Bytes<'data>,
56 marker: PhantomData<E>,
57 }
58
59 impl<'data, E: Endian> LoadCommandData<'data, E> {
60 /// Return the `cmd` field of the `LoadCommand`.
61 ///
62 /// This is one of the `LC_` constants.
63 pub fn cmd(&self) -> u32 {
64 self.cmd
65 }
66
67 /// Return the `cmdsize` field of the `LoadCommand`.
68 pub fn cmdsize(&self) -> u32 {
69 self.data.len() as u32
70 }
71
72 /// Parse the data as the given type.
73 #[inline]
74 pub fn data<T: Pod>(&self) -> Result<&'data T> {
75 self.data
76 .read_at(0)
77 .read_error("Invalid Mach-O command size")
78 }
79
80 /// Parse a load command string value.
81 ///
82 /// Strings used by load commands are specified by offsets that are
83 /// relative to the load command header.
84 pub fn string(&self, endian: E, s: macho::LcStr<E>) -> Result<&'data [u8]> {
85 self.data
86 .read_string_at(s.offset.get(endian) as usize)
87 .read_error("Invalid load command string offset")
88 }
89
90 /// Parse the command data according to the `cmd` field.
91 pub fn variant(&self) -> Result<LoadCommandVariant<'data, E>> {
92 Ok(match self.cmd {
93 macho::LC_SEGMENT => {
94 let mut data = self.data;
95 let segment = data.read().read_error("Invalid Mach-O command size")?;
96 LoadCommandVariant::Segment32(segment, data.0)
97 }
98 macho::LC_SYMTAB => LoadCommandVariant::Symtab(self.data()?),
99 macho::LC_THREAD | macho::LC_UNIXTHREAD => {
100 let mut data = self.data;
101 let thread = data.read().read_error("Invalid Mach-O command size")?;
102 LoadCommandVariant::Thread(thread, data.0)
103 }
104 macho::LC_DYSYMTAB => LoadCommandVariant::Dysymtab(self.data()?),
105 macho::LC_LOAD_DYLIB
106 | macho::LC_LOAD_WEAK_DYLIB
107 | macho::LC_REEXPORT_DYLIB
108 | macho::LC_LAZY_LOAD_DYLIB
109 | macho::LC_LOAD_UPWARD_DYLIB => LoadCommandVariant::Dylib(self.data()?),
110 macho::LC_ID_DYLIB => LoadCommandVariant::IdDylib(self.data()?),
111 macho::LC_LOAD_DYLINKER => LoadCommandVariant::LoadDylinker(self.data()?),
112 macho::LC_ID_DYLINKER => LoadCommandVariant::IdDylinker(self.data()?),
113 macho::LC_PREBOUND_DYLIB => LoadCommandVariant::PreboundDylib(self.data()?),
114 macho::LC_ROUTINES => LoadCommandVariant::Routines32(self.data()?),
115 macho::LC_SUB_FRAMEWORK => LoadCommandVariant::SubFramework(self.data()?),
116 macho::LC_SUB_UMBRELLA => LoadCommandVariant::SubUmbrella(self.data()?),
117 macho::LC_SUB_CLIENT => LoadCommandVariant::SubClient(self.data()?),
118 macho::LC_SUB_LIBRARY => LoadCommandVariant::SubLibrary(self.data()?),
119 macho::LC_TWOLEVEL_HINTS => LoadCommandVariant::TwolevelHints(self.data()?),
120 macho::LC_PREBIND_CKSUM => LoadCommandVariant::PrebindCksum(self.data()?),
121 macho::LC_SEGMENT_64 => {
122 let mut data = self.data;
123 let segment = data.read().read_error("Invalid Mach-O command size")?;
124 LoadCommandVariant::Segment64(segment, data.0)
125 }
126 macho::LC_ROUTINES_64 => LoadCommandVariant::Routines64(self.data()?),
127 macho::LC_UUID => LoadCommandVariant::Uuid(self.data()?),
128 macho::LC_RPATH => LoadCommandVariant::Rpath(self.data()?),
129 macho::LC_CODE_SIGNATURE
130 | macho::LC_SEGMENT_SPLIT_INFO
131 | macho::LC_FUNCTION_STARTS
132 | macho::LC_DATA_IN_CODE
133 | macho::LC_DYLIB_CODE_SIGN_DRS
134 | macho::LC_LINKER_OPTIMIZATION_HINT
135 | macho::LC_DYLD_EXPORTS_TRIE
136 | macho::LC_DYLD_CHAINED_FIXUPS => LoadCommandVariant::LinkeditData(self.data()?),
137 macho::LC_ENCRYPTION_INFO => LoadCommandVariant::EncryptionInfo32(self.data()?),
138 macho::LC_DYLD_INFO | macho::LC_DYLD_INFO_ONLY => {
139 LoadCommandVariant::DyldInfo(self.data()?)
140 }
141 macho::LC_VERSION_MIN_MACOSX
142 | macho::LC_VERSION_MIN_IPHONEOS
143 | macho::LC_VERSION_MIN_TVOS
144 | macho::LC_VERSION_MIN_WATCHOS => LoadCommandVariant::VersionMin(self.data()?),
145 macho::LC_DYLD_ENVIRONMENT => LoadCommandVariant::DyldEnvironment(self.data()?),
146 macho::LC_MAIN => LoadCommandVariant::EntryPoint(self.data()?),
147 macho::LC_SOURCE_VERSION => LoadCommandVariant::SourceVersion(self.data()?),
148 macho::LC_ENCRYPTION_INFO_64 => LoadCommandVariant::EncryptionInfo64(self.data()?),
149 macho::LC_LINKER_OPTION => LoadCommandVariant::LinkerOption(self.data()?),
150 macho::LC_NOTE => LoadCommandVariant::Note(self.data()?),
151 macho::LC_BUILD_VERSION => LoadCommandVariant::BuildVersion(self.data()?),
152 macho::LC_FILESET_ENTRY => LoadCommandVariant::FilesetEntry(self.data()?),
153 _ => LoadCommandVariant::Other,
154 })
155 }
156
157 /// Try to parse this command as a `SegmentCommand32`.
158 ///
159 /// Returns the segment command and the data containing the sections.
160 pub fn segment_32(self) -> Result<Option<(&'data macho::SegmentCommand32<E>, &'data [u8])>> {
161 if self.cmd == macho::LC_SEGMENT {
162 let mut data = self.data;
163 let segment = data.read().read_error("Invalid Mach-O command size")?;
164 Ok(Some((segment, data.0)))
165 } else {
166 Ok(None)
167 }
168 }
169
170 /// Try to parse this command as a `SymtabCommand`.
171 ///
172 /// Returns the segment command and the data containing the sections.
173 pub fn symtab(self) -> Result<Option<&'data macho::SymtabCommand<E>>> {
174 if self.cmd == macho::LC_SYMTAB {
175 Some(self.data()).transpose()
176 } else {
177 Ok(None)
178 }
179 }
180
181 /// Try to parse this command as a `DysymtabCommand`.
182 pub fn dysymtab(self) -> Result<Option<&'data macho::DysymtabCommand<E>>> {
183 if self.cmd == macho::LC_DYSYMTAB {
184 Some(self.data()).transpose()
185 } else {
186 Ok(None)
187 }
188 }
189
190 /// Try to parse this command as a `DylibCommand`.
191 pub fn dylib(self) -> Result<Option<&'data macho::DylibCommand<E>>> {
192 if self.cmd == macho::LC_LOAD_DYLIB
193 || self.cmd == macho::LC_LOAD_WEAK_DYLIB
194 || self.cmd == macho::LC_REEXPORT_DYLIB
195 || self.cmd == macho::LC_LAZY_LOAD_DYLIB
196 || self.cmd == macho::LC_LOAD_UPWARD_DYLIB
197 {
198 Some(self.data()).transpose()
199 } else {
200 Ok(None)
201 }
202 }
203
204 /// Try to parse this command as a `UuidCommand`.
205 pub fn uuid(self) -> Result<Option<&'data macho::UuidCommand<E>>> {
206 if self.cmd == macho::LC_UUID {
207 Some(self.data()).transpose()
208 } else {
209 Ok(None)
210 }
211 }
212
213 /// Try to parse this command as a `SegmentCommand64`.
214 pub fn segment_64(self) -> Result<Option<(&'data macho::SegmentCommand64<E>, &'data [u8])>> {
215 if self.cmd == macho::LC_SEGMENT_64 {
216 let mut data = self.data;
217 let command = data.read().read_error("Invalid Mach-O command size")?;
218 Ok(Some((command, data.0)))
219 } else {
220 Ok(None)
221 }
222 }
223
224 /// Try to parse this command as a `DyldInfoCommand`.
225 pub fn dyld_info(self) -> Result<Option<&'data macho::DyldInfoCommand<E>>> {
226 if self.cmd == macho::LC_DYLD_INFO || self.cmd == macho::LC_DYLD_INFO_ONLY {
227 Some(self.data()).transpose()
228 } else {
229 Ok(None)
230 }
231 }
232
233 /// Try to parse this command as an `EntryPointCommand`.
234 pub fn entry_point(self) -> Result<Option<&'data macho::EntryPointCommand<E>>> {
235 if self.cmd == macho::LC_MAIN {
236 Some(self.data()).transpose()
237 } else {
238 Ok(None)
239 }
240 }
241 }
242
243 /// A `LoadCommand` that has been interpreted according to its `cmd` field.
244 #[derive(Debug, Clone, Copy)]
245 #[non_exhaustive]
246 pub enum LoadCommandVariant<'data, E: Endian> {
247 /// `LC_SEGMENT`
248 Segment32(&'data macho::SegmentCommand32<E>, &'data [u8]),
249 /// `LC_SYMTAB`
250 Symtab(&'data macho::SymtabCommand<E>),
251 // obsolete: `LC_SYMSEG`
252 //Symseg(&'data macho::SymsegCommand<E>),
253 /// `LC_THREAD` or `LC_UNIXTHREAD`
254 Thread(&'data macho::ThreadCommand<E>, &'data [u8]),
255 // obsolete: `LC_IDFVMLIB` or `LC_LOADFVMLIB`
256 //Fvmlib(&'data macho::FvmlibCommand<E>),
257 // obsolete: `LC_IDENT`
258 //Ident(&'data macho::IdentCommand<E>),
259 // internal: `LC_FVMFILE`
260 //Fvmfile(&'data macho::FvmfileCommand<E>),
261 // internal: `LC_PREPAGE`
262 /// `LC_DYSYMTAB`
263 Dysymtab(&'data macho::DysymtabCommand<E>),
264 /// `LC_LOAD_DYLIB`, `LC_LOAD_WEAK_DYLIB`, `LC_REEXPORT_DYLIB`,
265 /// `LC_LAZY_LOAD_DYLIB`, or `LC_LOAD_UPWARD_DYLIB`
266 Dylib(&'data macho::DylibCommand<E>),
267 /// `LC_ID_DYLIB`
268 IdDylib(&'data macho::DylibCommand<E>),
269 /// `LC_LOAD_DYLINKER`
270 LoadDylinker(&'data macho::DylinkerCommand<E>),
271 /// `LC_ID_DYLINKER`
272 IdDylinker(&'data macho::DylinkerCommand<E>),
273 /// `LC_PREBOUND_DYLIB`
274 PreboundDylib(&'data macho::PreboundDylibCommand<E>),
275 /// `LC_ROUTINES`
276 Routines32(&'data macho::RoutinesCommand32<E>),
277 /// `LC_SUB_FRAMEWORK`
278 SubFramework(&'data macho::SubFrameworkCommand<E>),
279 /// `LC_SUB_UMBRELLA`
280 SubUmbrella(&'data macho::SubUmbrellaCommand<E>),
281 /// `LC_SUB_CLIENT`
282 SubClient(&'data macho::SubClientCommand<E>),
283 /// `LC_SUB_LIBRARY`
284 SubLibrary(&'data macho::SubLibraryCommand<E>),
285 /// `LC_TWOLEVEL_HINTS`
286 TwolevelHints(&'data macho::TwolevelHintsCommand<E>),
287 /// `LC_PREBIND_CKSUM`
288 PrebindCksum(&'data macho::PrebindCksumCommand<E>),
289 /// `LC_SEGMENT_64`
290 Segment64(&'data macho::SegmentCommand64<E>, &'data [u8]),
291 /// `LC_ROUTINES_64`
292 Routines64(&'data macho::RoutinesCommand64<E>),
293 /// `LC_UUID`
294 Uuid(&'data macho::UuidCommand<E>),
295 /// `LC_RPATH`
296 Rpath(&'data macho::RpathCommand<E>),
297 /// `LC_CODE_SIGNATURE`, `LC_SEGMENT_SPLIT_INFO`, `LC_FUNCTION_STARTS`,
298 /// `LC_DATA_IN_CODE`, `LC_DYLIB_CODE_SIGN_DRS`, `LC_LINKER_OPTIMIZATION_HINT`,
299 /// `LC_DYLD_EXPORTS_TRIE`, or `LC_DYLD_CHAINED_FIXUPS`.
300 LinkeditData(&'data macho::LinkeditDataCommand<E>),
301 /// `LC_ENCRYPTION_INFO`
302 EncryptionInfo32(&'data macho::EncryptionInfoCommand32<E>),
303 /// `LC_DYLD_INFO` or `LC_DYLD_INFO_ONLY`
304 DyldInfo(&'data macho::DyldInfoCommand<E>),
305 /// `LC_VERSION_MIN_MACOSX`, `LC_VERSION_MIN_IPHONEOS`, `LC_VERSION_MIN_WATCHOS`,
306 /// or `LC_VERSION_MIN_TVOS`
307 VersionMin(&'data macho::VersionMinCommand<E>),
308 /// `LC_DYLD_ENVIRONMENT`
309 DyldEnvironment(&'data macho::DylinkerCommand<E>),
310 /// `LC_MAIN`
311 EntryPoint(&'data macho::EntryPointCommand<E>),
312 /// `LC_SOURCE_VERSION`
313 SourceVersion(&'data macho::SourceVersionCommand<E>),
314 /// `LC_ENCRYPTION_INFO_64`
315 EncryptionInfo64(&'data macho::EncryptionInfoCommand64<E>),
316 /// `LC_LINKER_OPTION`
317 LinkerOption(&'data macho::LinkerOptionCommand<E>),
318 /// `LC_NOTE`
319 Note(&'data macho::NoteCommand<E>),
320 /// `LC_BUILD_VERSION`
321 BuildVersion(&'data macho::BuildVersionCommand<E>),
322 /// `LC_FILESET_ENTRY`
323 FilesetEntry(&'data macho::FilesetEntryCommand<E>),
324 /// An unrecognized or obsolete load command.
325 Other,
326 }
327
328 impl<E: Endian> macho::SymtabCommand<E> {
329 /// Return the symbol table that this command references.
330 pub fn symbols<'data, Mach: MachHeader<Endian = E>, R: ReadRef<'data>>(
331 &self,
332 endian: E,
333 data: R,
334 ) -> Result<SymbolTable<'data, Mach>> {
335 let symbols = data
336 .read_slice_at(
337 self.symoff.get(endian).into(),
338 self.nsyms.get(endian) as usize,
339 )
340 .read_error("Invalid Mach-O symbol table offset or size")?;
341 let strings = data
342 .read_bytes_at(
343 self.stroff.get(endian).into(),
344 self.strsize.get(endian).into(),
345 )
346 .read_error("Invalid Mach-O string table offset or size")?;
347 let strings = StringTable::new(strings);
348 Ok(SymbolTable::new(symbols, strings))
349 }
350 }