1use crate::io::{Endian, ReadExt as _, WriteExt as _};
2use byteorder::{NativeEndian, ReadBytesExt as _};
3use num_derive::FromPrimitive;
4use num_traits::FromPrimitive;
5use std::{
6 fmt,
7 io::{Read, Write},
8};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Header64 {
12 pub magic: Magic,
13 pub cpu_type: CpuType,
14 pub file_type: FileType,
15 pub n_cmds: u32,
16 pub size_of_cmds: u32,
17 pub flags: Flags,
18 pub reserved: u32,
19}
20
21impl Header64 {
22 pub const SIZE: u32 = 0x20; pub fn read_from<R: Read>(read: &mut R) -> Self {
25 let magic_n = read.read_u32::<NativeEndian>().unwrap();
26 let magic = Magic::from_u32(magic_n);
27 let endian = magic.endian();
28
29 let cpu_type_n = read.read_i32_in(endian);
30 let cpu_subtype_n = read.read_i32_in(endian);
31 let cpu_type = CpuType::from_i32_i32(cpu_type_n, cpu_subtype_n);
32
33 let file_type_n = read.read_u32_in(endian);
34 let file_type = FileType::from_u32(file_type_n);
35
36 let n_cmds = read.read_u32_in(endian);
37
38 let size_of_cmds = read.read_u32_in(endian);
39
40 let flags_n = read.read_u32_in(endian);
41 let flags = Flags::from_u32(flags_n);
42
43 let reserved = read.read_u32_in(endian);
44
45 let header = Header64 {
46 magic,
47 cpu_type,
48 file_type,
49 n_cmds,
50 size_of_cmds,
51 flags,
52 reserved,
53 };
54
55 header
56 }
57
58 pub fn write_into<W: Write>(&self, write: &mut W) {
59 write.write_u32_native(self.magic.to_u32());
60 let (cpu_type_n, cpu_subtype_n) = self.cpu_type.to_i32_i32();
61 write.write_i32_native(cpu_type_n);
62 write.write_i32_native(cpu_subtype_n);
63 write.write_u32_native(self.file_type.to_u32());
64 write.write_u32_native(self.n_cmds);
65 write.write_u32_native(self.size_of_cmds);
66 write.write_u32_native(self.flags.to_u32());
67 write.write_u32_native(self.reserved);
68 }
69
70 pub fn endian(&self) -> Endian {
71 self.magic.endian()
72 }
73}
74
75#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
77pub enum Magic {
78 Magic64 = 0xfeedfacf,
81 Cigam64 = 0xcffaedfe,
84 Magic = 0xfeedface,
87 Cigam = 0xcefaedfe,
90 FatMagic = 0xcafebabe,
93 FatCigam = 0xbebafeca,
96}
97
98impl Magic {
99 pub fn from_u32_checked(n: u32) -> Option<Self> {
100 FromPrimitive::from_u32(n)
101 }
102
103 pub fn from_u32(n: u32) -> Self {
104 Magic::from_u32_checked(n).unwrap()
105 }
106
107 pub fn to_u32(&self) -> u32 {
108 *self as u32
109 }
110
111 pub fn endian(&self) -> Endian {
112 match self {
113 Magic::Magic64 | Magic::Magic | Magic::FatMagic => Endian::NATIVE,
114 Magic::Cigam64 | Magic::Cigam | Magic::FatCigam => Endian::REVERSE,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum CpuType {
121 X86(CpuSubTypeX86),
122 X86_64(CpuSubTypeX86_64),
123}
124
125#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
126pub enum CpuSubTypeX86 {
127 All = 0x3,
128}
129
130#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
131pub enum CpuSubTypeX86_64 {
132 All = 0x3,
133}
134
135impl CpuType {
136 const CPU_ARCH_ABI64: i32 = 0x01000000;
137 const CPU_TYPE_X86: i32 = 0x7;
138 const CPU_TYPE_X86_64: i32 = Self::CPU_TYPE_X86 | Self::CPU_ARCH_ABI64;
139
140 pub fn from_i32_i32(cpu_type_n: i32, cpu_subtype_n: i32) -> Self {
141 if cpu_type_n == Self::CPU_TYPE_X86 {
143 let cpu_subtype = CpuSubTypeX86::from_i32(cpu_subtype_n).unwrap();
144 CpuType::X86(cpu_subtype)
145 } else if cpu_type_n == Self::CPU_TYPE_X86_64 {
147 let cpu_subtype = CpuSubTypeX86_64::from_i32(cpu_subtype_n).unwrap();
148 CpuType::X86_64(cpu_subtype)
149 } else {
150 panic!("Unsupported cpu type")
151 }
152 }
153
154 pub fn to_i32_i32(&self) -> (i32, i32) {
155 match self {
156 CpuType::X86(sub) => (CpuType::CPU_TYPE_X86, *sub as i32),
157 CpuType::X86_64(sub) => (CpuType::CPU_TYPE_X86_64, *sub as i32),
158 }
159 }
160}
161
162#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
163pub enum FileType {
165 Object = 0x1,
166 Execute = 0x2,
167 FVMLib = 0x3,
168 Core = 0x4,
169 Preload = 0x5,
170 Dylib = 0x6,
171 Dylinker = 0x7,
172 Bundle = 0x8,
173 Dsym = 0xA,
174}
175
176impl FileType {
177 pub fn from_u32(n: u32) -> Self {
178 FromPrimitive::from_u32(n).unwrap()
179 }
180
181 pub fn to_u32(self) -> u32 {
182 self as u32
183 }
184}
185
186#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
187#[rustfmt::skip]
188pub enum Flag {
189 NoUndefs = 0x000001,
190 IncrLink = 0x000002,
191 DyldLink = 0x000004,
192 BindAtLoad = 0x000008,
193 PreBound = 0x000010,
194 SplitSegs = 0x000020,
195 TwoLevel = 0x000080,
196 ForceFlat = 0x000100,
197 NoMultiDefs = 0x000200,
198 NoFixPreBinding = 0x000400,
199 PreBindable = 0x000800,
200 AllModsBound = 0x001000,
201 SubsectionsViaSymbols = 0x002000,
202 Canonical = 0x004000,
203 Pie = 0x200000,
204 HasTlvDescriptors = 0x800000,
205}
206
207impl Flag {
208 pub fn from_u32(n: u32) -> Self {
209 FromPrimitive::from_u32(n).unwrap()
210 }
211
212 pub fn to_u32(self) -> u32 {
213 self as u32
214 }
215}
216
217#[derive(Clone, PartialEq, Eq)]
218pub struct Flags {
219 flags: Vec<Flag>,
220}
221
222impl Flags {
223 pub fn new() -> Flags {
224 Flags { flags: Vec::new() }
225 }
226
227 pub fn push(&mut self, flag: Flag) {
228 self.flags.push(flag);
229 }
230
231 pub fn is_empty(&self) -> bool {
232 self.flags.is_empty()
233 }
234
235 pub fn iter<'a>(&'a self) -> impl Iterator<Item = Flag> + 'a {
236 self.flags.iter().copied()
237 }
238
239 pub fn from_u32(flags_n: u32) -> Self {
240 let mut flags = Flags::new();
241 for i in 0..=31 {
242 let flag_n = flags_n & (1 << i);
243 if flag_n != 0 {
244 let flag = Flag::from_u32(flag_n);
245 flags.push(flag);
246 }
247 }
248
249 flags
250 }
251
252 pub fn to_u32(&self) -> u32 {
253 let mut flag_n = 0u32;
254
255 for flag in self.flags.iter() {
256 flag_n |= flag.to_u32();
257 }
258
259 flag_n
260 }
261}
262
263impl fmt::Debug for Flags {
264 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
265 fmt.debug_set().entries(self.flags.iter()).finish()
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn write_and_read_header64() {
275 let header = Header64 {
276 magic: Magic::Magic64,
277 cpu_type: CpuType::X86_64(CpuSubTypeX86_64::All),
278 file_type: FileType::Object,
279 n_cmds: 2,
280 size_of_cmds: 42,
281 flags: Flags::new(),
282 reserved: 0,
283 };
284
285 let mut buf = Vec::new();
286
287 header.write_into(&mut buf);
288
289 assert_eq!(buf.len(), Header64::SIZE as usize);
290
291 let read = Header64::read_from(&mut buf.as_slice());
292 assert_eq!(read, header);
293 }
294}