]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | use core::marker::PhantomData; |
2 | ||
3 | use crate::endian::Endian; | |
4 | use crate::macho; | |
5 | use crate::pod::Bytes; | |
6 | use crate::read::macho::{MachHeader, SymbolTable}; | |
7 | use crate::read::{ReadError, Result, StringTable}; | |
8 | ||
9 | /// An iterator over the load commands of a `MachHeader`. | |
10 | #[derive(Debug, Default, Clone, Copy)] | |
11 | pub struct MachOLoadCommandIterator<'data, E: Endian> { | |
12 | endian: E, | |
13 | data: Bytes<'data>, | |
14 | ncmds: u32, | |
15 | } | |
16 | ||
17 | impl<'data, E: Endian> MachOLoadCommandIterator<'data, E> { | |
18 | pub(super) fn new(endian: E, data: Bytes<'data>, ncmds: u32) -> Self { | |
19 | MachOLoadCommandIterator { | |
20 | endian, | |
21 | data, | |
22 | ncmds, | |
23 | } | |
24 | } | |
25 | ||
26 | /// Return the next load command. | |
27 | pub fn next(&mut self) -> Result<Option<MachOLoadCommand<'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(MachOLoadCommand { | |
43 | cmd, | |
44 | data, | |
45 | marker: Default::default(), | |
46 | })) | |
47 | } | |
48 | } | |
49 | ||
50 | /// A parsed `LoadCommand`. | |
51 | #[derive(Debug, Clone, Copy)] | |
52 | pub struct MachOLoadCommand<'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> MachOLoadCommand<'data, E> { | |
60 | /// Try to parse this command as a `SegmentCommand32`. | |
61 | pub fn segment_32(self) -> Result<Option<(&'data macho::SegmentCommand32<E>, Bytes<'data>)>> { | |
62 | if self.cmd == macho::LC_SEGMENT { | |
63 | let mut data = self.data; | |
64 | let command = data | |
65 | .read() | |
66 | .read_error("Invalid Mach-O LC_SEGMENT command size")?; | |
67 | Ok(Some((command, data))) | |
68 | } else { | |
69 | Ok(None) | |
70 | } | |
71 | } | |
72 | ||
73 | /// Try to parse this command as a `SymtabCommand`. | |
74 | pub fn symtab(self) -> Result<Option<&'data macho::SymtabCommand<E>>> { | |
75 | if self.cmd == macho::LC_SYMTAB { | |
76 | Some( | |
77 | self.data | |
78 | .clone() | |
79 | .read() | |
80 | .read_error("Invalid Mach-O LC_SYMTAB command size"), | |
81 | ) | |
82 | .transpose() | |
83 | } else { | |
84 | Ok(None) | |
85 | } | |
86 | } | |
87 | ||
88 | /// Try to parse this command as a `UuidCommand`. | |
89 | pub fn uuid(self) -> Result<Option<&'data macho::UuidCommand<E>>> { | |
90 | if self.cmd == macho::LC_UUID { | |
91 | Some( | |
92 | self.data | |
93 | .clone() | |
94 | .read() | |
95 | .read_error("Invalid Mach-O LC_UUID command size"), | |
96 | ) | |
97 | .transpose() | |
98 | } else { | |
99 | Ok(None) | |
100 | } | |
101 | } | |
102 | ||
103 | /// Try to parse this command as a `SegmentCommand64`. | |
104 | pub fn segment_64(self) -> Result<Option<(&'data macho::SegmentCommand64<E>, Bytes<'data>)>> { | |
105 | if self.cmd == macho::LC_SEGMENT_64 { | |
106 | let mut data = self.data; | |
107 | let command = data | |
108 | .read() | |
109 | .read_error("Invalid Mach-O LC_SEGMENT_64 command size")?; | |
110 | Ok(Some((command, data))) | |
111 | } else { | |
112 | Ok(None) | |
113 | } | |
114 | } | |
115 | ||
116 | /// Try to parse this command as an `EntryPointCommand`. | |
117 | pub fn entry_point(self) -> Result<Option<&'data macho::EntryPointCommand<E>>> { | |
118 | if self.cmd == macho::LC_MAIN { | |
119 | Some( | |
120 | self.data | |
121 | .clone() | |
122 | .read() | |
123 | .read_error("Invalid Mach-O LC_MAIN command size"), | |
124 | ) | |
125 | .transpose() | |
126 | } else { | |
127 | Ok(None) | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | impl<E: Endian> macho::SymtabCommand<E> { | |
133 | /// Return the symbol table that this command references. | |
134 | pub fn symbols<'data, Mach: MachHeader<Endian = E>>( | |
135 | &self, | |
136 | endian: E, | |
137 | data: Bytes<'data>, | |
138 | ) -> Result<SymbolTable<'data, Mach>> { | |
139 | let symbols = data | |
140 | .read_slice_at( | |
141 | self.symoff.get(endian) as usize, | |
142 | self.nsyms.get(endian) as usize, | |
143 | ) | |
144 | .read_error("Invalid Mach-O symbol table offset or size")?; | |
145 | let strings = data | |
146 | .read_bytes_at( | |
147 | self.stroff.get(endian) as usize, | |
148 | self.strsize.get(endian) as usize, | |
149 | ) | |
150 | .read_error("Invalid Mach-O string table offset or size")?; | |
151 | let strings = StringTable::new(strings); | |
152 | Ok(SymbolTable::new(symbols, strings)) | |
153 | } | |
154 | } |