2121#include < string_view>
2222
2323#include " absl/strings/str_join.h"
24+ #include " absl/strings/str_format.h"
2425#include " absl/strings/substitute.h"
26+ #include " third_party/darwin_xnu_macho/mach/machine.h"
2527#include " third_party/darwin_xnu_macho/mach-o/loader.h"
2628#include " third_party/darwin_xnu_macho/mach-o/fat.h"
2729#include " third_party/darwin_xnu_macho/mach-o/nlist.h"
@@ -69,6 +71,57 @@ void MaybeAddOverhead(RangeSink* sink, const char* label, string_view data) {
6971 }
7072}
7173
74+ // ARM64E capability field constants
75+ static constexpr uint32_t ARM64E_SUBTYPE_MASK = 0x00FFFFFF ; // Low 24 bits: subtype proper
76+
77+ static bool IsArm64eSubtype (uint32_t cpusubtype) {
78+ uint32_t subtype_proper = cpusubtype & ARM64E_SUBTYPE_MASK;
79+ return subtype_proper == CPU_SUBTYPE_ARM64E;
80+ }
81+
82+ std::string CpuTypeToString (uint32_t cputype, uint32_t cpusubtype) {
83+ switch (cputype) {
84+ case CPU_TYPE_X86_64:
85+ switch (cpusubtype) {
86+ case CPU_SUBTYPE_X86_64_H:
87+ return " x86_64h" ;
88+ default :
89+ return " x86_64" ;
90+ }
91+ case CPU_TYPE_ARM64:
92+ if (IsArm64eSubtype (cpusubtype)) {
93+ return " arm64e" ;
94+ }
95+ switch (cpusubtype) {
96+ case CPU_SUBTYPE_ARM64_V8:
97+ return " arm64v8" ;
98+ default :
99+ return " arm64" ;
100+ }
101+ case CPU_TYPE_X86:
102+ return " i386" ;
103+ case CPU_TYPE_ARM:
104+ switch (cpusubtype) {
105+ case CPU_SUBTYPE_ARM_V6:
106+ return " armv6" ;
107+ case CPU_SUBTYPE_ARM_V7:
108+ return " armv7" ;
109+ case CPU_SUBTYPE_ARM_V7F:
110+ return " armv7f" ;
111+ case CPU_SUBTYPE_ARM_V7S:
112+ return " armv7s" ;
113+ case CPU_SUBTYPE_ARM_V7K:
114+ return " armv7k" ;
115+ case CPU_SUBTYPE_ARM_V8:
116+ return " armv8" ;
117+ default :
118+ return " arm" ;
119+ }
120+ default :
121+ return absl::StrFormat (" cpu_%d" , cputype);
122+ }
123+ }
124+
72125struct LoadCommand {
73126 bool is64bit;
74127 uint32_t cmd;
@@ -652,6 +705,10 @@ class MachOObjectFile : public ObjectFile {
652705 ReadDWARFInlines (dwarf, sink, true );
653706 break ;
654707 }
708+ case DataSource::kArchs : {
709+ ProcessArchitectures (sink);
710+ break ;
711+ }
655712 case DataSource::kArchiveMembers :
656713 default :
657714 THROW (" Mach-O doesn't support this data source" );
@@ -660,6 +717,34 @@ class MachOObjectFile : public ObjectFile {
660717 }
661718 }
662719
720+ void ProcessArchitectures (RangeSink* sink) const {
721+ uint32_t magic = ReadMagic (file_data ().data ());
722+
723+ if (magic == FAT_CIGAM) {
724+ string_view header_data = file_data ().data ();
725+ auto header = GetStructPointerAndAdvance<fat_header>(&header_data);
726+ uint32_t nfat_arch = ByteSwap (header->nfat_arch );
727+
728+ for (uint32_t i = 0 ; i < nfat_arch; i++) {
729+ auto arch = GetStructPointerAndAdvance<fat_arch>(&header_data);
730+ uint32_t cputype = ByteSwap (arch->cputype );
731+ uint32_t cpusubtype = ByteSwap (arch->cpusubtype );
732+ uint32_t offset = ByteSwap (arch->offset );
733+ uint32_t size = ByteSwap (arch->size );
734+
735+ std::string arch_name = CpuTypeToString (cputype, cpusubtype);
736+ string_view slice_data = StrictSubstr (file_data ().data (), offset, size);
737+
738+ sink->AddFileRange (" archs" , arch_name, slice_data);
739+ }
740+ } else {
741+ auto header = GetStructPointer<mach_header>(file_data ().data ());
742+ std::string arch_name = CpuTypeToString (header->cputype , header->cpusubtype );
743+
744+ sink->AddFileRange (" archs" , arch_name, file_data ().data ());
745+ }
746+ }
747+
663748 bool GetDisassemblyInfo (std::string_view /* symbol*/ ,
664749 DataSource /* symbol_source*/ ,
665750 DisassemblyInfo* /* info*/ ) const override {
0 commit comments