1use crate::format::constants::*;
2use crate::model::addr::ThinFileOffset;
3use std::fmt;
4
5#[derive(Debug, Clone)]
6pub struct ParsedLoadCommand {
8 pub(crate) kind: LoadCommand,
9 pub(crate) file_offset: ThinFileOffset,
10 pub(crate) raw_size: u32,
11}
12
13impl ParsedLoadCommand {
14 pub fn kind(&self) -> &LoadCommand {
16 &self.kind
17 }
18 pub const fn file_offset(&self) -> ThinFileOffset {
20 self.file_offset
21 }
22 pub const fn raw_size(&self) -> u32 {
24 self.raw_size
25 }
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum LoadCommand {
31 Segment32(SegmentCommandData),
33 Segment64(SegmentCommandData),
35 Symtab(SymtabData),
37 Dysymtab(DysymtabData),
39 DyldInfo(DyldInfoData),
41 DyldInfoOnly(DyldInfoData),
43 DyldExportsTrie(LinkeditData),
45 DyldChainedFixups(LinkeditData),
47 Main(EntryPointData),
49 Uuid(UuidData),
51 BuildVersion(BuildVersionData),
53 SourceVersion(SourceVersionData),
55 VersionMinMacOS(VersionMinData),
57 VersionMinIOS(VersionMinData),
59 VersionMinTvOS(VersionMinData),
61 VersionMinWatchOS(VersionMinData),
63 IdDylib(DylibData),
65 LoadDylib(DylibData),
67 LoadWeakDylib(DylibData),
69 ReexportDylib(DylibData),
71 LazyLoadDylib(DylibData),
73 LoadUpwardDylib(DylibData),
75 Rpath(StringData),
77 TargetTriple(StringData),
79 IdDylinker(StringData),
81 LoadDylinker(StringData),
83 DyldEnvironment(StringData),
85 SubFramework(StringData),
87 SubUmbrella(StringData),
89 SubClient(StringData),
91 SubLibrary(StringData),
93 CodeSignature(LinkeditData),
95 SegmentSplitInfo(LinkeditData),
97 FunctionStarts(LinkeditData),
99 DataInCode(LinkeditData),
101 DylibCodeSignDrs(LinkeditData),
103 LinkerOptimizationHint(LinkeditData),
105 AtomInfo(LinkeditData),
107 FunctionVariants(LinkeditData),
109 FunctionVariantFixups(LinkeditData),
111 EncryptionInfo(EncryptionInfoData),
113 EncryptionInfo64(EncryptionInfoData),
115 LinkerOption(LinkerOptionData),
117 Note(NoteData),
119 FilesetEntry(FilesetEntryData),
121 PrebindCksum(PrebindCksumData),
123 TwolevelHints(TwolevelHintsData),
125 Routines(RoutinesData),
127 Routines64(RoutinesData),
129 Thread(RawData),
131 UnixThread(RawData),
133 PreboundDylib(RawData),
135 Ident(RawData),
137 Unknown(UnknownLoadCommand),
139}
140
141impl LoadCommand {
142 pub fn name(&self) -> &'static str {
144 match self {
145 Self::Segment32(_) => "LC_SEGMENT",
146 Self::Segment64(_) => "LC_SEGMENT_64",
147 Self::Symtab(_) => "LC_SYMTAB",
148 Self::Dysymtab(_) => "LC_DYSYMTAB",
149 Self::DyldInfo(_) => "LC_DYLD_INFO",
150 Self::DyldInfoOnly(_) => "LC_DYLD_INFO_ONLY",
151 Self::DyldExportsTrie(_) => "LC_DYLD_EXPORTS_TRIE",
152 Self::DyldChainedFixups(_) => "LC_DYLD_CHAINED_FIXUPS",
153 Self::Main(_) => "LC_MAIN",
154 Self::Uuid(_) => "LC_UUID",
155 Self::BuildVersion(_) => "LC_BUILD_VERSION",
156 Self::SourceVersion(_) => "LC_SOURCE_VERSION",
157 Self::VersionMinMacOS(_) => "LC_VERSION_MIN_MACOSX",
158 Self::VersionMinIOS(_) => "LC_VERSION_MIN_IPHONEOS",
159 Self::VersionMinTvOS(_) => "LC_VERSION_MIN_TVOS",
160 Self::VersionMinWatchOS(_) => "LC_VERSION_MIN_WATCHOS",
161 Self::IdDylib(_) => "LC_ID_DYLIB",
162 Self::LoadDylib(_) => "LC_LOAD_DYLIB",
163 Self::LoadWeakDylib(_) => "LC_LOAD_WEAK_DYLIB",
164 Self::ReexportDylib(_) => "LC_REEXPORT_DYLIB",
165 Self::LazyLoadDylib(_) => "LC_LAZY_LOAD_DYLIB",
166 Self::LoadUpwardDylib(_) => "LC_LOAD_UPWARD_DYLIB",
167 Self::Rpath(_) => "LC_RPATH",
168 Self::TargetTriple(_) => "LC_TARGET_TRIPLE",
169 Self::IdDylinker(_) => "LC_ID_DYLINKER",
170 Self::LoadDylinker(_) => "LC_LOAD_DYLINKER",
171 Self::DyldEnvironment(_) => "LC_DYLD_ENVIRONMENT",
172 Self::SubFramework(_) => "LC_SUB_FRAMEWORK",
173 Self::SubUmbrella(_) => "LC_SUB_UMBRELLA",
174 Self::SubClient(_) => "LC_SUB_CLIENT",
175 Self::SubLibrary(_) => "LC_SUB_LIBRARY",
176 Self::CodeSignature(_) => "LC_CODE_SIGNATURE",
177 Self::SegmentSplitInfo(_) => "LC_SEGMENT_SPLIT_INFO",
178 Self::FunctionStarts(_) => "LC_FUNCTION_STARTS",
179 Self::DataInCode(_) => "LC_DATA_IN_CODE",
180 Self::DylibCodeSignDrs(_) => "LC_DYLIB_CODE_SIGN_DRS",
181 Self::LinkerOptimizationHint(_) => "LC_LINKER_OPTIMIZATION_HINT",
182 Self::AtomInfo(_) => "LC_ATOM_INFO",
183 Self::FunctionVariants(_) => "LC_FUNCTION_VARIANTS",
184 Self::FunctionVariantFixups(_) => "LC_FUNCTION_VARIANT_FIXUPS",
185 Self::EncryptionInfo(_) => "LC_ENCRYPTION_INFO",
186 Self::EncryptionInfo64(_) => "LC_ENCRYPTION_INFO_64",
187 Self::LinkerOption(_) => "LC_LINKER_OPTION",
188 Self::Note(_) => "LC_NOTE",
189 Self::FilesetEntry(_) => "LC_FILESET_ENTRY",
190 Self::PrebindCksum(_) => "LC_PREBIND_CKSUM",
191 Self::TwolevelHints(_) => "LC_TWOLEVEL_HINTS",
192 Self::Routines(_) => "LC_ROUTINES",
193 Self::Routines64(_) => "LC_ROUTINES_64",
194 Self::Thread(_) => "LC_THREAD",
195 Self::UnixThread(_) => "LC_UNIXTHREAD",
196 Self::PreboundDylib(_) => "LC_PREBOUND_DYLIB",
197 Self::Ident(_) => "LC_IDENT",
198 Self::Unknown(_) => "LC_UNKNOWN",
199 }
200 }
201
202 pub fn summary(&self) -> String {
204 match self {
205 Self::Segment32(d) | Self::Segment64(d) => {
206 format!("segment_index={}", d.segment_index)
207 }
208 Self::Uuid(d) => format_uuid(&d.uuid),
209 Self::BuildVersion(d) => {
210 format!("{} {}", d.platform.name(), d.minos)
211 }
212 Self::Main(d) => format!("entry_offset={:#x}", d.entry_offset),
213 Self::SourceVersion(d) => format!("{}", d.version),
214 Self::LoadDylib(d)
215 | Self::LoadWeakDylib(d)
216 | Self::ReexportDylib(d)
217 | Self::LazyLoadDylib(d)
218 | Self::LoadUpwardDylib(d)
219 | Self::IdDylib(d) => d.name.clone(),
220 Self::Rpath(d)
221 | Self::TargetTriple(d)
222 | Self::LoadDylinker(d)
223 | Self::IdDylinker(d)
224 | Self::DyldEnvironment(d)
225 | Self::SubFramework(d)
226 | Self::SubUmbrella(d)
227 | Self::SubClient(d)
228 | Self::SubLibrary(d) => d.value.clone(),
229 Self::Symtab(d) => format!("nsyms={}", d.nsyms),
230 Self::CodeSignature(d)
231 | Self::FunctionStarts(d)
232 | Self::DataInCode(d)
233 | Self::DyldExportsTrie(d)
234 | Self::DyldChainedFixups(d)
235 | Self::SegmentSplitInfo(d)
236 | Self::DylibCodeSignDrs(d)
237 | Self::LinkerOptimizationHint(d)
238 | Self::AtomInfo(d)
239 | Self::FunctionVariants(d)
240 | Self::FunctionVariantFixups(d) => {
241 format!("off={:#x} size={:#x}", d.data_offset, d.data_size)
242 }
243 Self::VersionMinMacOS(d)
244 | Self::VersionMinIOS(d)
245 | Self::VersionMinTvOS(d)
246 | Self::VersionMinWatchOS(d) => {
247 format!("{}", d.version)
248 }
249 Self::EncryptionInfo(d) | Self::EncryptionInfo64(d) => {
250 format!(
251 "cryptoff={:#x} cryptsize={:#x} cryptid={}",
252 d.crypt_offset, d.crypt_size, d.crypt_id
253 )
254 }
255 Self::DyldInfo(d) | Self::DyldInfoOnly(d) => {
256 format!(
257 "rebase={:#x}+{:#x} bind={:#x}+{:#x} export={:#x}+{:#x}",
258 d.rebase_off,
259 d.rebase_size,
260 d.bind_off,
261 d.bind_size,
262 d.export_off,
263 d.export_size
264 )
265 }
266 Self::FilesetEntry(d) => d.entry_id.clone(),
267 Self::Note(d) => d.data_owner.clone(),
268 _ => String::new(),
269 }
270 }
271
272 pub fn as_uuid(&self) -> Option<&UuidData> {
274 match self {
275 Self::Uuid(d) => Some(d),
276 _ => None,
277 }
278 }
279
280 pub fn as_build_version(&self) -> Option<&BuildVersionData> {
282 match self {
283 Self::BuildVersion(d) => Some(d),
284 _ => None,
285 }
286 }
287
288 pub fn as_symtab(&self) -> Option<&SymtabData> {
290 match self {
291 Self::Symtab(d) => Some(d),
292 _ => None,
293 }
294 }
295
296 pub fn as_dysymtab(&self) -> Option<&DysymtabData> {
298 match self {
299 Self::Dysymtab(d) => Some(d),
300 _ => None,
301 }
302 }
303
304 pub fn as_main(&self) -> Option<&EntryPointData> {
306 match self {
307 Self::Main(d) => Some(d),
308 _ => None,
309 }
310 }
311
312 pub fn as_dylib(&self) -> Option<&DylibData> {
314 match self {
315 Self::LoadDylib(d)
316 | Self::LoadWeakDylib(d)
317 | Self::ReexportDylib(d)
318 | Self::LazyLoadDylib(d)
319 | Self::LoadUpwardDylib(d)
320 | Self::IdDylib(d) => Some(d),
321 _ => None,
322 }
323 }
324
325 pub fn as_rpath(&self) -> Option<&str> {
327 match self {
328 Self::Rpath(d) => Some(&d.value),
329 _ => None,
330 }
331 }
332
333 pub fn as_segment(&self) -> Option<&SegmentCommandData> {
335 match self {
336 Self::Segment32(d) | Self::Segment64(d) => Some(d),
337 _ => None,
338 }
339 }
340
341 pub fn as_linkedit_data(&self) -> Option<&LinkeditData> {
343 match self {
344 Self::CodeSignature(d)
345 | Self::FunctionStarts(d)
346 | Self::DataInCode(d)
347 | Self::DyldExportsTrie(d)
348 | Self::DyldChainedFixups(d)
349 | Self::SegmentSplitInfo(d)
350 | Self::DylibCodeSignDrs(d)
351 | Self::LinkerOptimizationHint(d)
352 | Self::AtomInfo(d)
353 | Self::FunctionVariants(d)
354 | Self::FunctionVariantFixups(d) => Some(d),
355 _ => None,
356 }
357 }
358}
359
360pub fn format_uuid(uuid: &[u8; 16]) -> String {
362 format!(
363 "{:02X}{:02X}{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
364 uuid[0],
365 uuid[1],
366 uuid[2],
367 uuid[3],
368 uuid[4],
369 uuid[5],
370 uuid[6],
371 uuid[7],
372 uuid[8],
373 uuid[9],
374 uuid[10],
375 uuid[11],
376 uuid[12],
377 uuid[13],
378 uuid[14],
379 uuid[15],
380 )
381}
382
383#[derive(Debug, Clone, PartialEq, Eq)]
386pub struct SegmentCommandData {
388 pub segment_index: usize,
390}
391
392#[derive(Debug, Clone, PartialEq, Eq)]
393pub struct SymtabData {
395 pub sym_offset: u32,
397 pub nsyms: u32,
399 pub str_offset: u32,
401 pub str_size: u32,
403}
404
405#[derive(Debug, Clone, PartialEq, Eq)]
406pub struct DysymtabData {
408 pub ilocalsym: u32,
410 pub nlocalsym: u32,
412 pub iextdefsym: u32,
414 pub nextdefsym: u32,
416 pub iundefsym: u32,
418 pub nundefsym: u32,
420 pub tocoff: u32,
422 pub ntoc: u32,
424 pub modtaboff: u32,
426 pub nmodtab: u32,
428 pub extrefsymoff: u32,
430 pub nextrefsyms: u32,
432 pub indirectsymoff: u32,
434 pub nindirectsyms: u32,
436 pub extreloff: u32,
438 pub nextrel: u32,
440 pub locreloff: u32,
442 pub nlocrel: u32,
444}
445
446#[derive(Debug, Clone, PartialEq, Eq)]
447pub struct DyldInfoData {
449 pub rebase_off: u32,
451 pub rebase_size: u32,
453 pub bind_off: u32,
455 pub bind_size: u32,
457 pub weak_bind_off: u32,
459 pub weak_bind_size: u32,
461 pub lazy_bind_off: u32,
463 pub lazy_bind_size: u32,
465 pub export_off: u32,
467 pub export_size: u32,
469}
470
471#[derive(Debug, Clone, PartialEq, Eq)]
472pub struct LinkeditData {
474 pub data_offset: u32,
476 pub data_size: u32,
478}
479
480#[derive(Debug, Clone, PartialEq, Eq)]
481pub struct EntryPointData {
483 pub entry_offset: u64,
485 pub stack_size: u64,
487}
488
489#[derive(Debug, Clone, PartialEq, Eq)]
490pub struct UuidData {
492 pub uuid: [u8; 16],
494}
495
496#[derive(Debug, Clone, PartialEq, Eq)]
497pub struct BuildVersionData {
499 pub platform: Platform,
501 pub minos: PackedVersion,
503 pub sdk: PackedVersion,
505 pub tools: Vec<BuildToolVersion>,
507}
508
509#[derive(Debug, Clone, PartialEq, Eq)]
510pub struct BuildToolVersion {
512 pub tool: Tool,
514 pub version: PackedVersion,
516}
517
518#[derive(Debug, Clone, PartialEq, Eq)]
519pub struct SourceVersionData {
521 pub version: SourceVersion,
523}
524
525#[derive(Debug, Clone, PartialEq, Eq)]
526pub struct VersionMinData {
528 pub version: PackedVersion,
530 pub sdk: PackedVersion,
532}
533
534#[derive(Debug, Clone, PartialEq, Eq)]
535pub struct DylibData {
537 pub name: String,
539 pub timestamp: u32,
541 pub current_version: PackedVersion,
543 pub compatibility_version: PackedVersion,
545}
546
547#[derive(Debug, Clone, PartialEq, Eq)]
548pub struct StringData {
550 pub value: String,
552}
553
554#[derive(Debug, Clone, PartialEq, Eq)]
555pub struct EncryptionInfoData {
557 pub crypt_offset: u32,
559 pub crypt_size: u32,
561 pub crypt_id: u32,
563}
564
565#[derive(Debug, Clone, PartialEq, Eq)]
566pub struct LinkerOptionData {
568 pub strings: Vec<String>,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq)]
573pub struct NoteData {
575 pub data_owner: String,
577 pub offset: u64,
579 pub size: u64,
581}
582
583#[derive(Debug, Clone, PartialEq, Eq)]
584pub struct FilesetEntryData {
586 pub vm_addr: u64,
588 pub file_offset: u64,
590 pub entry_id: String,
592}
593
594#[derive(Debug, Clone, PartialEq, Eq)]
595pub struct PrebindCksumData {
597 pub cksum: u32,
599}
600
601#[derive(Debug, Clone, PartialEq, Eq)]
602pub struct TwolevelHintsData {
604 pub offset: u32,
606 pub nhints: u32,
608}
609
610#[derive(Debug, Clone, PartialEq, Eq)]
611pub struct RoutinesData {
613 pub init_address: u64,
615 pub init_module: u64,
617}
618
619#[derive(Debug, Clone, PartialEq, Eq)]
620pub struct RawData {
622 pub data: Vec<u8>,
624}
625
626#[derive(Debug, Clone, PartialEq, Eq)]
627pub struct UnknownLoadCommand {
629 pub cmd: u32,
631 pub data: Vec<u8>,
633}
634
635#[derive(Clone, Copy, PartialEq, Eq)]
638pub struct PackedVersion(pub u32);
640
641impl PackedVersion {
642 pub fn major(self) -> u32 {
644 self.0 >> 16
645 }
646
647 pub fn minor(self) -> u32 {
649 (self.0 >> 8) & 0xFF
650 }
651
652 pub fn patch(self) -> u32 {
654 self.0 & 0xFF
655 }
656}
657
658impl fmt::Debug for PackedVersion {
659 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660 write!(f, "{self}")
661 }
662}
663
664impl fmt::Display for PackedVersion {
665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666 write!(f, "{}.{}.{}", self.major(), self.minor(), self.patch())
667 }
668}
669
670#[derive(Clone, Copy, PartialEq, Eq)]
671pub struct SourceVersion(pub u64);
673
674impl SourceVersion {
675 pub fn a(self) -> u64 {
677 (self.0 >> 40) & 0xFFFFFF
678 }
679 pub fn b(self) -> u64 {
681 (self.0 >> 30) & 0x3FF
682 }
683 pub fn c(self) -> u64 {
685 (self.0 >> 20) & 0x3FF
686 }
687 pub fn d(self) -> u64 {
689 (self.0 >> 10) & 0x3FF
690 }
691 pub fn e(self) -> u64 {
693 self.0 & 0x3FF
694 }
695}
696
697impl fmt::Debug for SourceVersion {
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 write!(f, "{self}")
700 }
701}
702
703impl fmt::Display for SourceVersion {
704 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
705 write!(
706 f,
707 "{}.{}.{}.{}.{}",
708 self.a(),
709 self.b(),
710 self.c(),
711 self.d(),
712 self.e()
713 )
714 }
715}
716
717#[derive(Clone, Copy, PartialEq, Eq)]
718pub struct Platform(pub u32);
720
721impl Platform {
722 pub fn name(self) -> &'static str {
724 match self.0 {
725 PLATFORM_MACOS => "macOS",
726 PLATFORM_IOS => "iOS",
727 PLATFORM_TVOS => "tvOS",
728 PLATFORM_WATCHOS => "watchOS",
729 PLATFORM_BRIDGEOS => "bridgeOS",
730 PLATFORM_MACCATALYST => "Mac Catalyst",
731 PLATFORM_IOSSIMULATOR => "iOS Simulator",
732 PLATFORM_TVOSSIMULATOR => "tvOS Simulator",
733 PLATFORM_WATCHOSSIMULATOR => "watchOS Simulator",
734 PLATFORM_DRIVERKIT => "DriverKit",
735 PLATFORM_VISIONOS => "visionOS",
736 PLATFORM_VISIONOSSIMULATOR => "visionOS Simulator",
737 PLATFORM_FIRMWARE => "Firmware",
738 PLATFORM_SEPOS => "sepOS",
739 _ => "unknown",
740 }
741 }
742}
743
744impl fmt::Debug for Platform {
745 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
746 write!(f, "Platform({})", self.name())
747 }
748}
749
750impl fmt::Display for Platform {
751 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
752 write!(f, "{}", self.name())
753 }
754}
755
756#[derive(Clone, Copy, PartialEq, Eq)]
757pub struct Tool(pub u32);
759
760impl Tool {
761 pub fn name(self) -> &'static str {
763 match self.0 {
764 TOOL_CLANG => "clang",
765 TOOL_SWIFT => "swift",
766 TOOL_LD => "ld",
767 TOOL_LLD => "lld",
768 TOOL_METAL => "metal",
769 TOOL_AIRLLD => "airlld",
770 TOOL_AIRNT => "airnt",
771 TOOL_AIRNT_PLUGIN => "airnt_plugin",
772 TOOL_AIRPACK => "airpack",
773 TOOL_GPUARCHIVER => "gpuarchiver",
774 TOOL_METAL_FRAMEWORK => "metal_framework",
775 _ => "unknown",
776 }
777 }
778}
779
780impl fmt::Debug for Tool {
781 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
782 write!(f, "Tool({})", self.name())
783 }
784}