Line data Source code
1 : use lief_ffi as ffi;
2 :
3 : use crate::Error;
4 : use crate::common::{FromFFI, into_optional};
5 : use crate::{declare_iterator, declare_fwd_iterator, to_result};
6 : use super::{SubCache, Dylib, MappingInfo};
7 :
8 : use crate::assembly;
9 :
10 : #[allow(non_camel_case_types)]
11 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
12 : /// This enum wraps the dyld's git tags for which the structure of
13 : /// dyld shared cache evolved
14 : pub enum Version {
15 : /// dyld-95.3 (2007-10-30)
16 : DYLD_95_3,
17 : /// dyld-195.5 (2011-07-13)
18 : DYLD_195_5,
19 : /// dyld-239.3 (2013-10-29)
20 : DYLD_239_3,
21 : /// dyld-360.14 (2015-09-04)
22 : DYLD_360_14,
23 : /// dyld-421.1 (2016-09-22)
24 : DYLD_421_1,
25 : /// dyld-832.7.1 (2020-11-19)
26 : DYLD_832_7_1,
27 : /// dyld-940 (2021-02-09)
28 : DYLD_940,
29 : /// dyld-1042.1 (2022-10-19)
30 : DYLD_1042_1,
31 : /// This value is used for versions of dyld not publicly released or not yet
32 : /// supported by LIEF
33 : UNRELEASED,
34 : UNKNOWN(u32),
35 : }
36 :
37 : impl From<u32> for Version {
38 0 : fn from(value: u32) -> Self {
39 0 : match value {
40 0 : 0x00000001 => Version::DYLD_95_3,
41 0 : 0x00000002 => Version::DYLD_195_5,
42 0 : 0x00000003 => Version::DYLD_239_3,
43 0 : 0x00000004 => Version::DYLD_360_14,
44 0 : 0x00000005 => Version::DYLD_421_1,
45 0 : 0x00000006 => Version::DYLD_832_7_1,
46 0 : 0x00000007 => Version::DYLD_940,
47 0 : 0x00000008 => Version::DYLD_1042_1,
48 0 : 0x00000009 => Version::UNRELEASED,
49 0 : _ => Version::UNKNOWN(value),
50 :
51 : }
52 0 : }
53 : }
54 : impl From<Version> for u32 {
55 0 : fn from(value: Version) -> u32 {
56 0 : match value {
57 0 : Version::DYLD_95_3 => 0x00000001,
58 0 : Version::DYLD_195_5 => 0x00000002,
59 0 : Version::DYLD_239_3 => 0x00000003,
60 0 : Version::DYLD_360_14 => 0x00000004,
61 0 : Version::DYLD_421_1 => 0x00000005,
62 0 : Version::DYLD_832_7_1 => 0x00000006,
63 0 : Version::DYLD_940 => 0x00000007,
64 0 : Version::DYLD_1042_1 => 0x00000008,
65 0 : Version::UNRELEASED => 0x00000009,
66 0 : Version::UNKNOWN(_) => 0,
67 :
68 : }
69 0 : }
70 : }
71 :
72 :
73 : #[allow(non_camel_case_types)]
74 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
75 : /// Platforms supported by the dyld shared cache
76 : pub enum Platform {
77 : MACOS,
78 : IOS,
79 : TVOS,
80 : WATCHOS,
81 : BRIDGEOS,
82 : IOSMAC,
83 : IOS_SIMULATOR,
84 : TVOS_SIMULATOR,
85 : WATCHOS_SIMULATOR,
86 : DRIVERKIT,
87 : VISIONOS,
88 : VISIONOS_SIMULATOR,
89 : FIRMWARE,
90 : SEPOS,
91 : ANY,
92 : UNKNOWN(u32),
93 : }
94 :
95 : impl From<u32> for Platform {
96 0 : fn from(value: u32) -> Self {
97 0 : match value {
98 0 : 0x00000001 => Platform::MACOS,
99 0 : 0x00000002 => Platform::IOS,
100 0 : 0x00000003 => Platform::TVOS,
101 0 : 0x00000004 => Platform::WATCHOS,
102 0 : 0x00000005 => Platform::BRIDGEOS,
103 0 : 0x00000006 => Platform::IOSMAC,
104 0 : 0x00000007 => Platform::IOS_SIMULATOR,
105 0 : 0x00000008 => Platform::TVOS_SIMULATOR,
106 0 : 0x00000009 => Platform::WATCHOS_SIMULATOR,
107 0 : 0x0000000a => Platform::DRIVERKIT,
108 0 : 0x0000000b => Platform::VISIONOS,
109 0 : 0x0000000c => Platform::VISIONOS_SIMULATOR,
110 0 : 0x0000000d => Platform::FIRMWARE,
111 0 : 0x0000000e => Platform::SEPOS,
112 0 : 0xffffffff => Platform::ANY,
113 0 : _ => Platform::UNKNOWN(value),
114 :
115 : }
116 0 : }
117 : }
118 : impl From<Platform> for u32 {
119 0 : fn from(value: Platform) -> u32 {
120 0 : match value {
121 0 : Platform::MACOS => 0x00000001,
122 0 : Platform::IOS => 0x00000002,
123 0 : Platform::TVOS => 0x00000003,
124 0 : Platform::WATCHOS => 0x00000004,
125 0 : Platform::BRIDGEOS => 0x00000005,
126 0 : Platform::IOSMAC => 0x00000006,
127 0 : Platform::IOS_SIMULATOR => 0x00000007,
128 0 : Platform::TVOS_SIMULATOR => 0x00000008,
129 0 : Platform::WATCHOS_SIMULATOR => 0x00000009,
130 0 : Platform::DRIVERKIT => 0x0000000a,
131 0 : Platform::VISIONOS => 0x0000000b,
132 0 : Platform::VISIONOS_SIMULATOR => 0x0000000c,
133 0 : Platform::FIRMWARE => 0x0000000d,
134 0 : Platform::SEPOS => 0x0000000e,
135 0 : Platform::ANY => 0xffffffff,
136 0 : Platform::UNKNOWN(_) => 0,
137 :
138 : }
139 0 : }
140 : }
141 :
142 : #[allow(non_camel_case_types)]
143 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
144 : /// Architecture supported by the dyld shared cache
145 : pub enum Arch {
146 : I386,
147 : X86_64,
148 : X86_64H,
149 : ARMV5,
150 : ARMV6,
151 : ARMV7,
152 : ARM64,
153 : ARM64E,
154 : UNKNOWN(u32),
155 : }
156 :
157 : impl From<u32> for Arch {
158 0 : fn from(value: u32) -> Self {
159 0 : match value {
160 0 : 0x00000001 => Arch::I386,
161 0 : 0x00000002 => Arch::X86_64,
162 0 : 0x00000003 => Arch::X86_64H,
163 0 : 0x00000004 => Arch::ARMV5,
164 0 : 0x00000005 => Arch::ARMV6,
165 0 : 0x00000006 => Arch::ARMV7,
166 0 : 0x00000007 => Arch::ARM64,
167 0 : 0x00000008 => Arch::ARM64E,
168 0 : _ => Arch::UNKNOWN(value),
169 :
170 : }
171 0 : }
172 : }
173 : impl From<Arch> for u32 {
174 0 : fn from(value: Arch) -> u32 {
175 0 : match value {
176 0 : Arch::I386 => 0x00000001,
177 0 : Arch::X86_64 => 0x00000002,
178 0 : Arch::X86_64H => 0x00000003,
179 0 : Arch::ARMV5 => 0x00000004,
180 0 : Arch::ARMV6 => 0x00000005,
181 0 : Arch::ARMV7 => 0x00000006,
182 0 : Arch::ARM64 => 0x00000007,
183 0 : Arch::ARM64E => 0x00000008,
184 0 : Arch::UNKNOWN(_) => 0,
185 :
186 : }
187 0 : }
188 : }
189 :
190 : /// This struct interfaces a dyld shared cache file.
191 : pub struct DyldSharedCache {
192 : ptr: cxx::UniquePtr<ffi::dsc_DyldSharedCache>,
193 : }
194 :
195 : impl FromFFI<ffi::dsc_DyldSharedCache> for DyldSharedCache {
196 0 : fn from_ffi(info: cxx::UniquePtr<ffi::dsc_DyldSharedCache>) -> Self {
197 0 : Self {
198 0 : ptr: info,
199 0 : }
200 0 : }
201 : }
202 :
203 : impl DyldSharedCache {
204 : /// Filename of the dyld shared file associated with this object.
205 : ///
206 : /// For instance: `dyld_shared_cache_arm64e, dyld_shared_cache_arm64e.62.dyldlinkedit`
207 0 : pub fn filename(&self) -> String {
208 0 : self.ptr.filename().to_string()
209 0 : }
210 :
211 : /// Full path to the original dyld shared cache file associated with object
212 : /// (e.g. `/home/lief/downloads/visionos/dyld_shared_cache_arm64e.42`)
213 0 : pub fn filepath(&self) -> String {
214 0 : self.ptr.filepath().to_string()
215 0 : }
216 :
217 : /// Based address of this cache
218 0 : pub fn load_address(&self) -> u64 {
219 0 : self.ptr.load_address()
220 0 : }
221 :
222 : /// Version of dyld used by this cache
223 0 : pub fn version(&self) -> Version {
224 0 : Version::from(self.ptr.version())
225 0 : }
226 :
227 : /// Name of the architecture targeted by this cache (`x86_64h`)
228 0 : pub fn arch_name(&self) -> String {
229 0 : self.ptr.arch_name().to_string()
230 0 : }
231 :
232 : /// Platform targeted by this cache (e.g. vision-os)
233 0 : pub fn platform(&self) -> Platform {
234 0 : Platform::from(self.ptr.platform())
235 0 : }
236 :
237 : /// Architecture targeted by this cache
238 0 : pub fn arch(&self) -> Arch {
239 0 : Arch::from(self.ptr.arch())
240 0 : }
241 :
242 : /// Find the [`Dylib`] that encompasses the given virtual address.
243 0 : pub fn find_lib_from_va(&self, va: u64) -> Option<Dylib> {
244 0 : into_optional(self.ptr.find_lib_from_va(va))
245 0 : }
246 :
247 : /// Find the [`Dylib`] whose [`Dylib::path`] matches the provided path.
248 0 : pub fn find_lib_from_path(&self, path: &str) -> Option<Dylib> {
249 0 : into_optional(self.ptr.find_lib_from_path(path))
250 0 : }
251 :
252 : /// Find the [`Dylib`] whose filename of [`Dylib::path`] matches the provided name.
253 : ///
254 : /// If multiple libraries have the same name (but with a different path),
255 : /// the **first one** matching the provided name is returned.
256 0 : pub fn find_lib_from_name(&self, name: &str) -> Option<Dylib> {
257 0 : into_optional(self.ptr.find_lib_from_name(name))
258 0 : }
259 :
260 : /// True if the subcaches are associated with this cache
261 0 : pub fn has_subcaches(&self) -> bool {
262 0 : self.ptr.has_subcaches()
263 0 : }
264 :
265 : /// Return an iterator over the different [`Dylib`] libraries embedded
266 : /// in this dyld shared cache
267 0 : pub fn libraries(&self) -> Dylibs {
268 0 : Dylibs::new(self.ptr.libraries())
269 0 : }
270 :
271 : /// Return an iterator over the different [`MappingInfo`] associated
272 : /// with this dyld shared cache
273 0 : pub fn mapping_info(&self) -> MappingInfoIt {
274 0 : MappingInfoIt::new(self.ptr.mapping_info())
275 0 : }
276 :
277 : /// Return an interator over the subcaches associated with this (main) dyld shared
278 : /// cache.
279 0 : pub fn subcaches(&self) -> SubCacheIt {
280 0 : SubCacheIt::new(self.ptr.subcaches())
281 0 : }
282 :
283 : /// Disassemble instructions at the provided virtual address.
284 : ///
285 : /// This function returns an iterator over [`assembly::Instructions`].
286 0 : pub fn disassemble(&self, address: u64) -> Instructions {
287 0 : Instructions::new(self.ptr.disassemble(address))
288 0 : }
289 :
290 : /// Return the content at the specified virtual address
291 0 : pub fn get_content_from_va(&self, address: u64, size: u64) -> Vec<u8> {
292 0 : Vec::from(self.ptr.get_content_from_va(address, size).as_slice())
293 0 : }
294 :
295 : /// Find the sub-DyldSharedCache that wraps the given virtual address
296 0 : pub fn cache_for_address(&self, address: u64) -> Option<DyldSharedCache> {
297 0 : into_optional(self.ptr.cache_for_address(address))
298 0 : }
299 :
300 : /// Return the principal dyld shared cache in the case of multiple subcaches
301 0 : pub fn main_cache(&self) -> Option<DyldSharedCache> {
302 0 : into_optional(self.ptr.main_cache())
303 0 : }
304 :
305 : /// Try to find the [`DyldSharedCache`] associated with the filename given
306 : /// in the first parameter.
307 0 : pub fn find_subcache(&self, filename: &str) -> Option<DyldSharedCache> {
308 0 : into_optional(self.ptr.find_subcache(filename))
309 0 : }
310 :
311 : /// Convert the given virtual address into an offset.
312 0 : pub fn va_to_offset(&self, address: u64) -> Result<u64, Error> {
313 0 : to_result!(ffi::dsc_DyldSharedCache::va_to_offset, &self, address);
314 0 : }
315 :
316 : /// When enabled, this function allows to record and to keep in *cache*,
317 : /// dyld shared cache information that are costly to access.
318 : ///
319 : /// For instance, GOT symbols, rebases information, stub symbols, ...
320 : ///
321 : /// It is **highly** recommended to enable this function when processing
322 : /// a dyld shared cache several times or when extracting a large number of
323 : /// [`Dylib`] with enhanced extraction options (e.g. [`crate::dsc::dylib::ExtractOpt::fix_memory`])
324 : ///
325 : /// One can enable caching by calling this function:
326 : ///
327 : /// ```rust
328 : /// let dyld_cache = lief::dsc::load_from_path("macos-15.0.1/", "");
329 : /// dyld_cache.enable_caching("/home/user/.cache/lief-dsc");
330 : /// ```
331 : ///
332 : /// One can also enable this cache optimization **globally** using the
333 : /// function: [`crate::dsc::enable_cache`] or by setting the environment variable
334 : /// `DYLDSC_ENABLE_CACHE` to 1.
335 0 : pub fn enable_caching(&self, target_cache_dir: &str) {
336 0 : self.ptr.enable_caching(target_cache_dir)
337 0 : }
338 :
339 : /// Flush internal information into the on-disk cache (see: enable_caching)
340 0 : pub fn flush_cache(&self) {
341 0 : self.ptr.flush_cache()
342 0 : }
343 : }
344 :
345 0 : declare_iterator!(
346 0 : Dylibs,
347 0 : Dylib<'a>,
348 0 : ffi::dsc_Dylib,
349 0 : ffi::dsc_DyldSharedCache,
350 0 : ffi::dsc_DyldSharedCache_it_libraries
351 0 : );
352 :
353 0 : declare_iterator!(
354 0 : MappingInfoIt,
355 0 : MappingInfo<'a>,
356 0 : ffi::dsc_MappingInfo,
357 0 : ffi::dsc_DyldSharedCache,
358 0 : ffi::dsc_DyldSharedCache_it_mapping_info
359 0 : );
360 :
361 0 : declare_iterator!(
362 0 : SubCacheIt,
363 0 : SubCache<'a>,
364 0 : ffi::dsc_SubCache,
365 0 : ffi::dsc_DyldSharedCache,
366 0 : ffi::dsc_DyldSharedCache_it_subcaches
367 0 : );
368 :
369 0 : declare_fwd_iterator!(
370 0 : Instructions,
371 0 : assembly::Instructions,
372 0 : ffi::asm_Instruction,
373 0 : ffi::dsc_DyldSharedCache,
374 0 : ffi::dsc_DyldSharedCache_it_instructions
375 0 : );
|