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