1 | use crate::read::{Architecture, Error, ReadError, ReadRef, Result}; |
2 | use crate::{macho, BigEndian, Pod}; |
3 | |
4 | pub use macho::{FatArch32, FatArch64, FatHeader}; |
5 | |
6 | impl FatHeader { |
7 | /// Attempt to parse a fat header. |
8 | /// |
9 | /// Does not validate the magic value. |
10 | pub fn parse<'data, R: ReadRef<'data>>(file: R) -> Result<&'data FatHeader> { |
11 | file.read_at::<FatHeader>(0) |
12 | .read_error("Invalid fat header size or alignment" ) |
13 | } |
14 | |
15 | /// Attempt to parse a fat header and 32-bit fat arches. |
16 | pub fn parse_arch32<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch32]> { |
17 | let mut offset = 0; |
18 | let header = file |
19 | .read::<FatHeader>(&mut offset) |
20 | .read_error("Invalid fat header size or alignment" )?; |
21 | if header.magic.get(BigEndian) != macho::FAT_MAGIC { |
22 | return Err(Error("Invalid 32-bit fat magic" )); |
23 | } |
24 | file.read_slice::<FatArch32>(&mut offset, header.nfat_arch.get(BigEndian) as usize) |
25 | .read_error("Invalid nfat_arch" ) |
26 | } |
27 | |
28 | /// Attempt to parse a fat header and 64-bit fat arches. |
29 | pub fn parse_arch64<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch64]> { |
30 | let mut offset = 0; |
31 | let header = file |
32 | .read::<FatHeader>(&mut offset) |
33 | .read_error("Invalid fat header size or alignment" )?; |
34 | if header.magic.get(BigEndian) != macho::FAT_MAGIC_64 { |
35 | return Err(Error("Invalid 64-bit fat magic" )); |
36 | } |
37 | file.read_slice::<FatArch64>(&mut offset, header.nfat_arch.get(BigEndian) as usize) |
38 | .read_error("Invalid nfat_arch" ) |
39 | } |
40 | } |
41 | |
42 | /// A trait for generic access to [`macho::FatArch32`] and [`macho::FatArch64`]. |
43 | #[allow (missing_docs)] |
44 | pub trait FatArch: Pod { |
45 | type Word: Into<u64>; |
46 | |
47 | fn cputype(&self) -> u32; |
48 | fn cpusubtype(&self) -> u32; |
49 | fn offset(&self) -> Self::Word; |
50 | fn size(&self) -> Self::Word; |
51 | fn align(&self) -> u32; |
52 | |
53 | fn architecture(&self) -> Architecture { |
54 | match self.cputype() { |
55 | macho::CPU_TYPE_ARM => Architecture::Arm, |
56 | macho::CPU_TYPE_ARM64 => Architecture::Aarch64, |
57 | macho::CPU_TYPE_X86 => Architecture::I386, |
58 | macho::CPU_TYPE_X86_64 => Architecture::X86_64, |
59 | macho::CPU_TYPE_MIPS => Architecture::Mips, |
60 | macho::CPU_TYPE_POWERPC => Architecture::PowerPc, |
61 | macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64, |
62 | _ => Architecture::Unknown, |
63 | } |
64 | } |
65 | |
66 | fn file_range(&self) -> (u64, u64) { |
67 | (self.offset().into(), self.size().into()) |
68 | } |
69 | |
70 | fn data<'data, R: ReadRef<'data>>(&self, file: R) -> Result<&'data [u8]> { |
71 | file.read_bytes_at(self.offset().into(), self.size().into()) |
72 | .read_error("Invalid fat arch offset or size" ) |
73 | } |
74 | } |
75 | |
76 | impl FatArch for FatArch32 { |
77 | type Word = u32; |
78 | |
79 | fn cputype(&self) -> u32 { |
80 | self.cputype.get(BigEndian) |
81 | } |
82 | |
83 | fn cpusubtype(&self) -> u32 { |
84 | self.cpusubtype.get(BigEndian) |
85 | } |
86 | |
87 | fn offset(&self) -> Self::Word { |
88 | self.offset.get(BigEndian) |
89 | } |
90 | |
91 | fn size(&self) -> Self::Word { |
92 | self.size.get(BigEndian) |
93 | } |
94 | |
95 | fn align(&self) -> u32 { |
96 | self.align.get(BigEndian) |
97 | } |
98 | } |
99 | |
100 | impl FatArch for FatArch64 { |
101 | type Word = u64; |
102 | |
103 | fn cputype(&self) -> u32 { |
104 | self.cputype.get(BigEndian) |
105 | } |
106 | |
107 | fn cpusubtype(&self) -> u32 { |
108 | self.cpusubtype.get(BigEndian) |
109 | } |
110 | |
111 | fn offset(&self) -> Self::Word { |
112 | self.offset.get(BigEndian) |
113 | } |
114 | |
115 | fn size(&self) -> Self::Word { |
116 | self.size.get(BigEndian) |
117 | } |
118 | |
119 | fn align(&self) -> u32 { |
120 | self.align.get(BigEndian) |
121 | } |
122 | } |
123 | |