1cb14a3feSDimitry Andric //===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===// 2cb14a3feSDimitry Andric // 3cb14a3feSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4cb14a3feSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5cb14a3feSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6cb14a3feSDimitry Andric // 7cb14a3feSDimitry Andric //===----------------------------------------------------------------------===// 8cb14a3feSDimitry Andric /// 9cb14a3feSDimitry Andric /// Implements the TAPI Reader for Mach-O dynamic libraries. 10cb14a3feSDimitry Andric /// 11cb14a3feSDimitry Andric //===----------------------------------------------------------------------===// 12cb14a3feSDimitry Andric 13cb14a3feSDimitry Andric #include "llvm/TextAPI/DylibReader.h" 14cb14a3feSDimitry Andric #include "llvm/ADT/STLExtras.h" 15*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 16*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 17cb14a3feSDimitry Andric #include "llvm/Object/Binary.h" 18cb14a3feSDimitry Andric #include "llvm/Object/MachOUniversal.h" 19cb14a3feSDimitry Andric #include "llvm/Support/Endian.h" 20cb14a3feSDimitry Andric #include "llvm/TargetParser/Triple.h" 21*0fca6ea1SDimitry Andric #include "llvm/TextAPI/InterfaceFile.h" 22cb14a3feSDimitry Andric #include "llvm/TextAPI/RecordsSlice.h" 23cb14a3feSDimitry Andric #include "llvm/TextAPI/TextAPIError.h" 24cb14a3feSDimitry Andric #include <iomanip> 25cb14a3feSDimitry Andric #include <set> 26cb14a3feSDimitry Andric #include <sstream> 27cb14a3feSDimitry Andric #include <string> 28cb14a3feSDimitry Andric #include <tuple> 29cb14a3feSDimitry Andric 30cb14a3feSDimitry Andric using namespace llvm; 31cb14a3feSDimitry Andric using namespace llvm::object; 32cb14a3feSDimitry Andric using namespace llvm::MachO; 33cb14a3feSDimitry Andric using namespace llvm::MachO::DylibReader; 34cb14a3feSDimitry Andric 35cb14a3feSDimitry Andric using TripleVec = std::vector<Triple>; 36cb14a3feSDimitry Andric static typename TripleVec::iterator emplace(TripleVec &Container, Triple &&T) { 37cb14a3feSDimitry Andric auto I = partition_point(Container, [=](const Triple &CT) { 38cb14a3feSDimitry Andric return std::forward_as_tuple(CT.getArch(), CT.getOS(), 39cb14a3feSDimitry Andric CT.getEnvironment()) < 40cb14a3feSDimitry Andric std::forward_as_tuple(T.getArch(), T.getOS(), T.getEnvironment()); 41cb14a3feSDimitry Andric }); 42cb14a3feSDimitry Andric 43cb14a3feSDimitry Andric if (I != Container.end() && *I == T) 44cb14a3feSDimitry Andric return I; 45cb14a3feSDimitry Andric return Container.emplace(I, T); 46cb14a3feSDimitry Andric } 47cb14a3feSDimitry Andric 48cb14a3feSDimitry Andric static TripleVec constructTriples(MachOObjectFile *Obj, 49cb14a3feSDimitry Andric const Architecture ArchT) { 50cb14a3feSDimitry Andric auto getOSVersionStr = [](uint32_t V) { 51cb14a3feSDimitry Andric PackedVersion OSVersion(V); 52cb14a3feSDimitry Andric std::string Vers; 53cb14a3feSDimitry Andric raw_string_ostream VStream(Vers); 54cb14a3feSDimitry Andric VStream << OSVersion; 55cb14a3feSDimitry Andric return VStream.str(); 56cb14a3feSDimitry Andric }; 57cb14a3feSDimitry Andric auto getOSVersion = [&](const MachOObjectFile::LoadCommandInfo &cmd) { 58cb14a3feSDimitry Andric auto Vers = Obj->getVersionMinLoadCommand(cmd); 59cb14a3feSDimitry Andric return getOSVersionStr(Vers.version); 60cb14a3feSDimitry Andric }; 61cb14a3feSDimitry Andric 62cb14a3feSDimitry Andric TripleVec Triples; 63cb14a3feSDimitry Andric bool IsIntel = ArchitectureSet(ArchT).hasX86(); 64cb14a3feSDimitry Andric auto Arch = getArchitectureName(ArchT); 65cb14a3feSDimitry Andric 66cb14a3feSDimitry Andric for (const auto &cmd : Obj->load_commands()) { 67cb14a3feSDimitry Andric std::string OSVersion; 68cb14a3feSDimitry Andric switch (cmd.C.cmd) { 69cb14a3feSDimitry Andric case MachO::LC_VERSION_MIN_MACOSX: 70cb14a3feSDimitry Andric OSVersion = getOSVersion(cmd); 71cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "macos" + OSVersion}); 72cb14a3feSDimitry Andric break; 73cb14a3feSDimitry Andric case MachO::LC_VERSION_MIN_IPHONEOS: 74cb14a3feSDimitry Andric OSVersion = getOSVersion(cmd); 75cb14a3feSDimitry Andric if (IsIntel) 76cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"}); 77cb14a3feSDimitry Andric else 78cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "ios" + OSVersion}); 79cb14a3feSDimitry Andric break; 80cb14a3feSDimitry Andric case MachO::LC_VERSION_MIN_TVOS: 81cb14a3feSDimitry Andric OSVersion = getOSVersion(cmd); 82cb14a3feSDimitry Andric if (IsIntel) 83cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"}); 84cb14a3feSDimitry Andric else 85cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "tvos" + OSVersion}); 86cb14a3feSDimitry Andric break; 87cb14a3feSDimitry Andric case MachO::LC_VERSION_MIN_WATCHOS: 88cb14a3feSDimitry Andric OSVersion = getOSVersion(cmd); 89cb14a3feSDimitry Andric if (IsIntel) 90cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"}); 91cb14a3feSDimitry Andric else 92cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "watchos" + OSVersion}); 93cb14a3feSDimitry Andric break; 94cb14a3feSDimitry Andric case MachO::LC_BUILD_VERSION: { 95cb14a3feSDimitry Andric OSVersion = getOSVersionStr(Obj->getBuildVersionLoadCommand(cmd).minos); 96cb14a3feSDimitry Andric switch (Obj->getBuildVersionLoadCommand(cmd).platform) { 97cb14a3feSDimitry Andric case MachO::PLATFORM_MACOS: 98cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "macos" + OSVersion}); 99cb14a3feSDimitry Andric break; 100cb14a3feSDimitry Andric case MachO::PLATFORM_IOS: 101cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "ios" + OSVersion}); 102cb14a3feSDimitry Andric break; 103cb14a3feSDimitry Andric case MachO::PLATFORM_TVOS: 104cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "tvos" + OSVersion}); 105cb14a3feSDimitry Andric break; 106cb14a3feSDimitry Andric case MachO::PLATFORM_WATCHOS: 107cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "watchos" + OSVersion}); 108cb14a3feSDimitry Andric break; 109cb14a3feSDimitry Andric case MachO::PLATFORM_BRIDGEOS: 110cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "bridgeos" + OSVersion}); 111cb14a3feSDimitry Andric break; 112cb14a3feSDimitry Andric case MachO::PLATFORM_MACCATALYST: 113cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "ios" + OSVersion, "macabi"}); 114cb14a3feSDimitry Andric break; 115cb14a3feSDimitry Andric case MachO::PLATFORM_IOSSIMULATOR: 116cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"}); 117cb14a3feSDimitry Andric break; 118cb14a3feSDimitry Andric case MachO::PLATFORM_TVOSSIMULATOR: 119cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"}); 120cb14a3feSDimitry Andric break; 121cb14a3feSDimitry Andric case MachO::PLATFORM_WATCHOSSIMULATOR: 122cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"}); 123cb14a3feSDimitry Andric break; 124cb14a3feSDimitry Andric case MachO::PLATFORM_DRIVERKIT: 125cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "driverkit" + OSVersion}); 126cb14a3feSDimitry Andric break; 127cb14a3feSDimitry Andric default: 128cb14a3feSDimitry Andric break; // Skip any others. 129cb14a3feSDimitry Andric } 130cb14a3feSDimitry Andric break; 131cb14a3feSDimitry Andric } 132cb14a3feSDimitry Andric default: 133cb14a3feSDimitry Andric break; 134cb14a3feSDimitry Andric } 135cb14a3feSDimitry Andric } 136cb14a3feSDimitry Andric 137cb14a3feSDimitry Andric // Record unknown platform for older binaries that don't enforce platform 138cb14a3feSDimitry Andric // load commands. 139cb14a3feSDimitry Andric if (Triples.empty()) 140cb14a3feSDimitry Andric emplace(Triples, {Arch, "apple", "unknown"}); 141cb14a3feSDimitry Andric 142cb14a3feSDimitry Andric return Triples; 143cb14a3feSDimitry Andric } 144cb14a3feSDimitry Andric 145cb14a3feSDimitry Andric static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice) { 146cb14a3feSDimitry Andric auto H = Obj->getHeader(); 147cb14a3feSDimitry Andric auto &BA = Slice.getBinaryAttrs(); 148cb14a3feSDimitry Andric 149cb14a3feSDimitry Andric switch (H.filetype) { 150cb14a3feSDimitry Andric default: 151cb14a3feSDimitry Andric llvm_unreachable("unsupported binary type"); 152cb14a3feSDimitry Andric case MachO::MH_DYLIB: 153cb14a3feSDimitry Andric BA.File = FileType::MachO_DynamicLibrary; 154cb14a3feSDimitry Andric break; 155cb14a3feSDimitry Andric case MachO::MH_DYLIB_STUB: 156cb14a3feSDimitry Andric BA.File = FileType::MachO_DynamicLibrary_Stub; 157cb14a3feSDimitry Andric break; 158cb14a3feSDimitry Andric case MachO::MH_BUNDLE: 159cb14a3feSDimitry Andric BA.File = FileType::MachO_Bundle; 160cb14a3feSDimitry Andric break; 161cb14a3feSDimitry Andric } 162cb14a3feSDimitry Andric 163cb14a3feSDimitry Andric if (H.flags & MachO::MH_TWOLEVEL) 164cb14a3feSDimitry Andric BA.TwoLevelNamespace = true; 165cb14a3feSDimitry Andric if (H.flags & MachO::MH_APP_EXTENSION_SAFE) 166cb14a3feSDimitry Andric BA.AppExtensionSafe = true; 167cb14a3feSDimitry Andric 168cb14a3feSDimitry Andric for (const auto &LCI : Obj->load_commands()) { 169cb14a3feSDimitry Andric switch (LCI.C.cmd) { 170cb14a3feSDimitry Andric case MachO::LC_ID_DYLIB: { 171cb14a3feSDimitry Andric auto DLLC = Obj->getDylibIDLoadCommand(LCI); 172cb14a3feSDimitry Andric BA.InstallName = Slice.copyString(LCI.Ptr + DLLC.dylib.name); 173cb14a3feSDimitry Andric BA.CurrentVersion = DLLC.dylib.current_version; 174cb14a3feSDimitry Andric BA.CompatVersion = DLLC.dylib.compatibility_version; 175cb14a3feSDimitry Andric break; 176cb14a3feSDimitry Andric } 177cb14a3feSDimitry Andric case MachO::LC_REEXPORT_DYLIB: { 178cb14a3feSDimitry Andric auto DLLC = Obj->getDylibIDLoadCommand(LCI); 179cb14a3feSDimitry Andric BA.RexportedLibraries.emplace_back( 180cb14a3feSDimitry Andric Slice.copyString(LCI.Ptr + DLLC.dylib.name)); 181cb14a3feSDimitry Andric break; 182cb14a3feSDimitry Andric } 183cb14a3feSDimitry Andric case MachO::LC_SUB_FRAMEWORK: { 184cb14a3feSDimitry Andric auto SFC = Obj->getSubFrameworkCommand(LCI); 185cb14a3feSDimitry Andric BA.ParentUmbrella = Slice.copyString(LCI.Ptr + SFC.umbrella); 186cb14a3feSDimitry Andric break; 187cb14a3feSDimitry Andric } 188cb14a3feSDimitry Andric case MachO::LC_SUB_CLIENT: { 189cb14a3feSDimitry Andric auto SCLC = Obj->getSubClientCommand(LCI); 190cb14a3feSDimitry Andric BA.AllowableClients.emplace_back(Slice.copyString(LCI.Ptr + SCLC.client)); 191cb14a3feSDimitry Andric break; 192cb14a3feSDimitry Andric } 193cb14a3feSDimitry Andric case MachO::LC_UUID: { 194cb14a3feSDimitry Andric auto UUIDLC = Obj->getUuidCommand(LCI); 195cb14a3feSDimitry Andric std::stringstream Stream; 196cb14a3feSDimitry Andric for (unsigned I = 0; I < 16; ++I) { 197cb14a3feSDimitry Andric if (I == 4 || I == 6 || I == 8 || I == 10) 198cb14a3feSDimitry Andric Stream << '-'; 199cb14a3feSDimitry Andric Stream << std::setfill('0') << std::setw(2) << std::uppercase 200cb14a3feSDimitry Andric << std::hex << static_cast<int>(UUIDLC.uuid[I]); 201cb14a3feSDimitry Andric } 202cb14a3feSDimitry Andric BA.UUID = Slice.copyString(Stream.str()); 203cb14a3feSDimitry Andric break; 204cb14a3feSDimitry Andric } 205cb14a3feSDimitry Andric case MachO::LC_RPATH: { 206cb14a3feSDimitry Andric auto RPLC = Obj->getRpathCommand(LCI); 207cb14a3feSDimitry Andric BA.RPaths.emplace_back(Slice.copyString(LCI.Ptr + RPLC.path)); 208cb14a3feSDimitry Andric break; 209cb14a3feSDimitry Andric } 210cb14a3feSDimitry Andric case MachO::LC_SEGMENT_SPLIT_INFO: { 211cb14a3feSDimitry Andric auto SSILC = Obj->getLinkeditDataLoadCommand(LCI); 212cb14a3feSDimitry Andric if (SSILC.datasize == 0) 213cb14a3feSDimitry Andric BA.OSLibNotForSharedCache = true; 214cb14a3feSDimitry Andric break; 215cb14a3feSDimitry Andric } 216cb14a3feSDimitry Andric default: 217cb14a3feSDimitry Andric break; 218cb14a3feSDimitry Andric } 219cb14a3feSDimitry Andric } 220cb14a3feSDimitry Andric 221cb14a3feSDimitry Andric for (auto &Sect : Obj->sections()) { 222cb14a3feSDimitry Andric auto SectName = Sect.getName(); 223cb14a3feSDimitry Andric if (!SectName) 224cb14a3feSDimitry Andric return SectName.takeError(); 225cb14a3feSDimitry Andric if (*SectName != "__objc_imageinfo" && *SectName != "__image_info") 226cb14a3feSDimitry Andric continue; 227cb14a3feSDimitry Andric 228cb14a3feSDimitry Andric auto Content = Sect.getContents(); 229cb14a3feSDimitry Andric if (!Content) 230cb14a3feSDimitry Andric return Content.takeError(); 231cb14a3feSDimitry Andric 232cb14a3feSDimitry Andric if ((Content->size() >= 8) && (Content->front() == 0)) { 233cb14a3feSDimitry Andric uint32_t Flags; 234cb14a3feSDimitry Andric if (Obj->isLittleEndian()) { 235cb14a3feSDimitry Andric auto *p = 236cb14a3feSDimitry Andric reinterpret_cast<const support::ulittle32_t *>(Content->data() + 4); 237cb14a3feSDimitry Andric Flags = *p; 238cb14a3feSDimitry Andric } else { 239cb14a3feSDimitry Andric auto *p = 240cb14a3feSDimitry Andric reinterpret_cast<const support::ubig32_t *>(Content->data() + 4); 241cb14a3feSDimitry Andric Flags = *p; 242cb14a3feSDimitry Andric } 243cb14a3feSDimitry Andric BA.SwiftABI = (Flags >> 8) & 0xFF; 244cb14a3feSDimitry Andric } 245cb14a3feSDimitry Andric } 246cb14a3feSDimitry Andric return Error::success(); 247cb14a3feSDimitry Andric } 248cb14a3feSDimitry Andric 249cb14a3feSDimitry Andric static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice, 250cb14a3feSDimitry Andric const ParseOption &Opt) { 251cb14a3feSDimitry Andric 252cb14a3feSDimitry Andric auto parseExport = [](const auto ExportFlags, 253cb14a3feSDimitry Andric auto Addr) -> std::tuple<SymbolFlags, RecordLinkage> { 254cb14a3feSDimitry Andric SymbolFlags Flags = SymbolFlags::None; 255cb14a3feSDimitry Andric switch (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) { 256cb14a3feSDimitry Andric case MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR: 257cb14a3feSDimitry Andric if (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION) 258cb14a3feSDimitry Andric Flags |= SymbolFlags::WeakDefined; 259cb14a3feSDimitry Andric break; 260cb14a3feSDimitry Andric case MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: 261cb14a3feSDimitry Andric Flags |= SymbolFlags::ThreadLocalValue; 262cb14a3feSDimitry Andric break; 263cb14a3feSDimitry Andric } 264cb14a3feSDimitry Andric 265cb14a3feSDimitry Andric RecordLinkage Linkage = (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) 266cb14a3feSDimitry Andric ? RecordLinkage::Rexported 267cb14a3feSDimitry Andric : RecordLinkage::Exported; 268cb14a3feSDimitry Andric return {Flags, Linkage}; 269cb14a3feSDimitry Andric }; 270cb14a3feSDimitry Andric 271cb14a3feSDimitry Andric Error Err = Error::success(); 272cb14a3feSDimitry Andric 273cb14a3feSDimitry Andric StringMap<std::pair<SymbolFlags, RecordLinkage>> Exports; 274cb14a3feSDimitry Andric // Collect symbols from export trie first. Sometimes, there are more exports 275cb14a3feSDimitry Andric // in the trie than in n-list due to stripping. This is common for swift 276cb14a3feSDimitry Andric // mangled symbols. 277cb14a3feSDimitry Andric for (auto &Sym : Obj->exports(Err)) { 278cb14a3feSDimitry Andric auto [Flags, Linkage] = parseExport(Sym.flags(), Sym.address()); 279cb14a3feSDimitry Andric Slice.addRecord(Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage); 280cb14a3feSDimitry Andric Exports[Sym.name()] = {Flags, Linkage}; 281cb14a3feSDimitry Andric } 282cb14a3feSDimitry Andric 283cb14a3feSDimitry Andric for (const auto &Sym : Obj->symbols()) { 284cb14a3feSDimitry Andric auto FlagsOrErr = Sym.getFlags(); 285cb14a3feSDimitry Andric if (!FlagsOrErr) 286cb14a3feSDimitry Andric return FlagsOrErr.takeError(); 287cb14a3feSDimitry Andric auto Flags = *FlagsOrErr; 288cb14a3feSDimitry Andric 289cb14a3feSDimitry Andric auto NameOrErr = Sym.getName(); 290cb14a3feSDimitry Andric if (!NameOrErr) 291cb14a3feSDimitry Andric return NameOrErr.takeError(); 292cb14a3feSDimitry Andric auto Name = *NameOrErr; 293cb14a3feSDimitry Andric 294cb14a3feSDimitry Andric RecordLinkage Linkage = RecordLinkage::Unknown; 295cb14a3feSDimitry Andric SymbolFlags RecordFlags = SymbolFlags::None; 296cb14a3feSDimitry Andric 297*0fca6ea1SDimitry Andric if (Flags & SymbolRef::SF_Undefined) { 298*0fca6ea1SDimitry Andric if (Opt.Undefineds) 299cb14a3feSDimitry Andric Linkage = RecordLinkage::Undefined; 300*0fca6ea1SDimitry Andric else 301*0fca6ea1SDimitry Andric continue; 302cb14a3feSDimitry Andric if (Flags & SymbolRef::SF_Weak) 303cb14a3feSDimitry Andric RecordFlags |= SymbolFlags::WeakReferenced; 304cb14a3feSDimitry Andric } else if (Flags & SymbolRef::SF_Exported) { 305cb14a3feSDimitry Andric auto Exp = Exports.find(Name); 306cb14a3feSDimitry Andric // This should never be possible when binaries are produced with Apple 307cb14a3feSDimitry Andric // linkers. However it is possible to craft dylibs where the export trie 308cb14a3feSDimitry Andric // is either malformed or has conflicting symbols compared to n_list. 309cb14a3feSDimitry Andric if (Exp != Exports.end()) 310cb14a3feSDimitry Andric std::tie(RecordFlags, Linkage) = Exp->second; 311cb14a3feSDimitry Andric else 312cb14a3feSDimitry Andric Linkage = RecordLinkage::Exported; 313cb14a3feSDimitry Andric } else if (Flags & SymbolRef::SF_Hidden) { 314cb14a3feSDimitry Andric Linkage = RecordLinkage::Internal; 315cb14a3feSDimitry Andric } else 316cb14a3feSDimitry Andric continue; 317cb14a3feSDimitry Andric 318cb14a3feSDimitry Andric auto TypeOrErr = Sym.getType(); 319cb14a3feSDimitry Andric if (!TypeOrErr) 320cb14a3feSDimitry Andric return TypeOrErr.takeError(); 321cb14a3feSDimitry Andric auto Type = *TypeOrErr; 322cb14a3feSDimitry Andric 323cb14a3feSDimitry Andric GlobalRecord::Kind GV = (Type & SymbolRef::ST_Function) 324cb14a3feSDimitry Andric ? GlobalRecord::Kind::Function 325cb14a3feSDimitry Andric : GlobalRecord::Kind::Variable; 326cb14a3feSDimitry Andric 327cb14a3feSDimitry Andric if (GV == GlobalRecord::Kind::Function) 328cb14a3feSDimitry Andric RecordFlags |= SymbolFlags::Text; 329cb14a3feSDimitry Andric else 330cb14a3feSDimitry Andric RecordFlags |= SymbolFlags::Data; 331cb14a3feSDimitry Andric 332cb14a3feSDimitry Andric Slice.addRecord(Name, RecordFlags, GV, Linkage); 333cb14a3feSDimitry Andric } 334cb14a3feSDimitry Andric return Err; 335cb14a3feSDimitry Andric } 336cb14a3feSDimitry Andric 337cb14a3feSDimitry Andric static Error load(MachOObjectFile *Obj, RecordsSlice &Slice, 338cb14a3feSDimitry Andric const ParseOption &Opt, const Architecture Arch) { 339cb14a3feSDimitry Andric if (Arch == AK_unknown) 340cb14a3feSDimitry Andric return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget); 341cb14a3feSDimitry Andric 342cb14a3feSDimitry Andric if (Opt.MachOHeader) 343cb14a3feSDimitry Andric if (auto Err = readMachOHeader(Obj, Slice)) 344cb14a3feSDimitry Andric return Err; 345cb14a3feSDimitry Andric 346cb14a3feSDimitry Andric if (Opt.SymbolTable) 347cb14a3feSDimitry Andric if (auto Err = readSymbols(Obj, Slice, Opt)) 348cb14a3feSDimitry Andric return Err; 349cb14a3feSDimitry Andric 350cb14a3feSDimitry Andric return Error::success(); 351cb14a3feSDimitry Andric } 352cb14a3feSDimitry Andric 353cb14a3feSDimitry Andric Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer, 354cb14a3feSDimitry Andric const ParseOption &Opt) { 355cb14a3feSDimitry Andric Records Results; 356cb14a3feSDimitry Andric 357cb14a3feSDimitry Andric auto BinOrErr = createBinary(Buffer); 358cb14a3feSDimitry Andric if (!BinOrErr) 359cb14a3feSDimitry Andric return BinOrErr.takeError(); 360cb14a3feSDimitry Andric 361cb14a3feSDimitry Andric Binary &Bin = *BinOrErr.get(); 362cb14a3feSDimitry Andric if (auto *Obj = dyn_cast<MachOObjectFile>(&Bin)) { 363cb14a3feSDimitry Andric const auto Arch = getArchitectureFromCpuType(Obj->getHeader().cputype, 364cb14a3feSDimitry Andric Obj->getHeader().cpusubtype); 365cb14a3feSDimitry Andric if (!Opt.Archs.has(Arch)) 366cb14a3feSDimitry Andric return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture); 367cb14a3feSDimitry Andric 368cb14a3feSDimitry Andric auto Triples = constructTriples(Obj, Arch); 369cb14a3feSDimitry Andric for (const auto &T : Triples) { 370cb14a3feSDimitry Andric if (mapToPlatformType(T) == PLATFORM_UNKNOWN) 371cb14a3feSDimitry Andric return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget); 372cb14a3feSDimitry Andric Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T}))); 373cb14a3feSDimitry Andric if (auto Err = load(Obj, *Results.back(), Opt, Arch)) 374cb14a3feSDimitry Andric return std::move(Err); 375cb14a3feSDimitry Andric Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier(); 376cb14a3feSDimitry Andric } 377cb14a3feSDimitry Andric return Results; 378cb14a3feSDimitry Andric } 379cb14a3feSDimitry Andric 380cb14a3feSDimitry Andric // Only expect MachO universal binaries at this point. 381cb14a3feSDimitry Andric assert(isa<MachOUniversalBinary>(&Bin) && 382cb14a3feSDimitry Andric "Expected a MachO universal binary."); 383cb14a3feSDimitry Andric auto *UB = cast<MachOUniversalBinary>(&Bin); 384cb14a3feSDimitry Andric 385cb14a3feSDimitry Andric for (auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) { 386cb14a3feSDimitry Andric // Skip architecture if not requested. 387cb14a3feSDimitry Andric auto Arch = 388cb14a3feSDimitry Andric getArchitectureFromCpuType(OI->getCPUType(), OI->getCPUSubType()); 389cb14a3feSDimitry Andric if (!Opt.Archs.has(Arch)) 390cb14a3feSDimitry Andric continue; 391cb14a3feSDimitry Andric 392cb14a3feSDimitry Andric // Skip unknown architectures. 393cb14a3feSDimitry Andric if (Arch == AK_unknown) 394cb14a3feSDimitry Andric continue; 395cb14a3feSDimitry Andric 396cb14a3feSDimitry Andric // This can fail if the object is an archive. 397cb14a3feSDimitry Andric auto ObjOrErr = OI->getAsObjectFile(); 398cb14a3feSDimitry Andric 399cb14a3feSDimitry Andric // Skip the archive and consume the error. 400cb14a3feSDimitry Andric if (!ObjOrErr) { 401cb14a3feSDimitry Andric consumeError(ObjOrErr.takeError()); 402cb14a3feSDimitry Andric continue; 403cb14a3feSDimitry Andric } 404cb14a3feSDimitry Andric 405cb14a3feSDimitry Andric auto &Obj = *ObjOrErr.get(); 406cb14a3feSDimitry Andric switch (Obj.getHeader().filetype) { 407cb14a3feSDimitry Andric default: 408cb14a3feSDimitry Andric break; 409cb14a3feSDimitry Andric case MachO::MH_BUNDLE: 410cb14a3feSDimitry Andric case MachO::MH_DYLIB: 411cb14a3feSDimitry Andric case MachO::MH_DYLIB_STUB: 412cb14a3feSDimitry Andric for (const auto &T : constructTriples(&Obj, Arch)) { 413cb14a3feSDimitry Andric Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T}))); 414cb14a3feSDimitry Andric if (auto Err = load(&Obj, *Results.back(), Opt, Arch)) 415cb14a3feSDimitry Andric return std::move(Err); 416*0fca6ea1SDimitry Andric Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier(); 417cb14a3feSDimitry Andric } 418cb14a3feSDimitry Andric break; 419cb14a3feSDimitry Andric } 420cb14a3feSDimitry Andric } 421cb14a3feSDimitry Andric 422cb14a3feSDimitry Andric if (Results.empty()) 423cb14a3feSDimitry Andric return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults); 424cb14a3feSDimitry Andric return Results; 425cb14a3feSDimitry Andric } 426cb14a3feSDimitry Andric 427cb14a3feSDimitry Andric Expected<std::unique_ptr<InterfaceFile>> 428cb14a3feSDimitry Andric DylibReader::get(MemoryBufferRef Buffer) { 429cb14a3feSDimitry Andric ParseOption Options; 430cb14a3feSDimitry Andric auto SlicesOrErr = readFile(Buffer, Options); 431cb14a3feSDimitry Andric if (!SlicesOrErr) 432cb14a3feSDimitry Andric return SlicesOrErr.takeError(); 433cb14a3feSDimitry Andric 434cb14a3feSDimitry Andric return convertToInterfaceFile(*SlicesOrErr); 435cb14a3feSDimitry Andric } 436*0fca6ea1SDimitry Andric 437*0fca6ea1SDimitry Andric static void DWARFErrorHandler(Error Err) { /**/ } 438*0fca6ea1SDimitry Andric 439*0fca6ea1SDimitry Andric static SymbolToSourceLocMap 440*0fca6ea1SDimitry Andric accumulateLocs(MachOObjectFile &Obj, 441*0fca6ea1SDimitry Andric const std::unique_ptr<DWARFContext> &DiCtx) { 442*0fca6ea1SDimitry Andric SymbolToSourceLocMap LocMap; 443*0fca6ea1SDimitry Andric for (const auto &Symbol : Obj.symbols()) { 444*0fca6ea1SDimitry Andric Expected<uint32_t> FlagsOrErr = Symbol.getFlags(); 445*0fca6ea1SDimitry Andric if (!FlagsOrErr) { 446*0fca6ea1SDimitry Andric consumeError(FlagsOrErr.takeError()); 447*0fca6ea1SDimitry Andric continue; 448*0fca6ea1SDimitry Andric } 449*0fca6ea1SDimitry Andric 450*0fca6ea1SDimitry Andric if (!(*FlagsOrErr & SymbolRef::SF_Exported)) 451*0fca6ea1SDimitry Andric continue; 452*0fca6ea1SDimitry Andric 453*0fca6ea1SDimitry Andric Expected<uint64_t> AddressOrErr = Symbol.getAddress(); 454*0fca6ea1SDimitry Andric if (!AddressOrErr) { 455*0fca6ea1SDimitry Andric consumeError(AddressOrErr.takeError()); 456*0fca6ea1SDimitry Andric continue; 457*0fca6ea1SDimitry Andric } 458*0fca6ea1SDimitry Andric const uint64_t Address = *AddressOrErr; 459*0fca6ea1SDimitry Andric 460*0fca6ea1SDimitry Andric auto TypeOrErr = Symbol.getType(); 461*0fca6ea1SDimitry Andric if (!TypeOrErr) { 462*0fca6ea1SDimitry Andric consumeError(TypeOrErr.takeError()); 463*0fca6ea1SDimitry Andric continue; 464*0fca6ea1SDimitry Andric } 465*0fca6ea1SDimitry Andric const bool IsCode = (*TypeOrErr & SymbolRef::ST_Function); 466*0fca6ea1SDimitry Andric 467*0fca6ea1SDimitry Andric auto *DWARFCU = IsCode ? DiCtx->getCompileUnitForCodeAddress(Address) 468*0fca6ea1SDimitry Andric : DiCtx->getCompileUnitForDataAddress(Address); 469*0fca6ea1SDimitry Andric if (!DWARFCU) 470*0fca6ea1SDimitry Andric continue; 471*0fca6ea1SDimitry Andric 472*0fca6ea1SDimitry Andric const DWARFDie &DIE = IsCode ? DWARFCU->getSubroutineForAddress(Address) 473*0fca6ea1SDimitry Andric : DWARFCU->getVariableForAddress(Address); 474*0fca6ea1SDimitry Andric const std::string File = DIE.getDeclFile( 475*0fca6ea1SDimitry Andric llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 476*0fca6ea1SDimitry Andric const uint64_t Line = DIE.getDeclLine(); 477*0fca6ea1SDimitry Andric 478*0fca6ea1SDimitry Andric auto NameOrErr = Symbol.getName(); 479*0fca6ea1SDimitry Andric if (!NameOrErr) { 480*0fca6ea1SDimitry Andric consumeError(NameOrErr.takeError()); 481*0fca6ea1SDimitry Andric continue; 482*0fca6ea1SDimitry Andric } 483*0fca6ea1SDimitry Andric auto Name = *NameOrErr; 484*0fca6ea1SDimitry Andric auto Sym = parseSymbol(Name); 485*0fca6ea1SDimitry Andric 486*0fca6ea1SDimitry Andric if (!File.empty() && Line != 0) 487*0fca6ea1SDimitry Andric LocMap.insert({Sym.Name, RecordLoc(File, Line)}); 488*0fca6ea1SDimitry Andric } 489*0fca6ea1SDimitry Andric 490*0fca6ea1SDimitry Andric return LocMap; 491*0fca6ea1SDimitry Andric } 492*0fca6ea1SDimitry Andric 493*0fca6ea1SDimitry Andric SymbolToSourceLocMap 494*0fca6ea1SDimitry Andric DylibReader::accumulateSourceLocFromDSYM(const StringRef DSYM, 495*0fca6ea1SDimitry Andric const Target &T) { 496*0fca6ea1SDimitry Andric // Find sidecar file. 497*0fca6ea1SDimitry Andric auto DSYMsOrErr = MachOObjectFile::findDsymObjectMembers(DSYM); 498*0fca6ea1SDimitry Andric if (!DSYMsOrErr) { 499*0fca6ea1SDimitry Andric consumeError(DSYMsOrErr.takeError()); 500*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 501*0fca6ea1SDimitry Andric } 502*0fca6ea1SDimitry Andric if (DSYMsOrErr->empty()) 503*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 504*0fca6ea1SDimitry Andric 505*0fca6ea1SDimitry Andric const StringRef Path = DSYMsOrErr->front(); 506*0fca6ea1SDimitry Andric auto BufOrErr = MemoryBuffer::getFile(Path); 507*0fca6ea1SDimitry Andric if (auto Err = BufOrErr.getError()) 508*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 509*0fca6ea1SDimitry Andric 510*0fca6ea1SDimitry Andric auto BinOrErr = createBinary(*BufOrErr.get()); 511*0fca6ea1SDimitry Andric if (!BinOrErr) { 512*0fca6ea1SDimitry Andric consumeError(BinOrErr.takeError()); 513*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 514*0fca6ea1SDimitry Andric } 515*0fca6ea1SDimitry Andric // Handle single arch. 516*0fca6ea1SDimitry Andric if (auto *Single = dyn_cast<MachOObjectFile>(BinOrErr->get())) { 517*0fca6ea1SDimitry Andric auto DiCtx = DWARFContext::create( 518*0fca6ea1SDimitry Andric *Single, DWARFContext::ProcessDebugRelocations::Process, nullptr, "", 519*0fca6ea1SDimitry Andric DWARFErrorHandler, DWARFErrorHandler); 520*0fca6ea1SDimitry Andric 521*0fca6ea1SDimitry Andric return accumulateLocs(*Single, DiCtx); 522*0fca6ea1SDimitry Andric } 523*0fca6ea1SDimitry Andric // Handle universal companion file. 524*0fca6ea1SDimitry Andric if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) { 525*0fca6ea1SDimitry Andric auto ObjForArch = Fat->getObjectForArch(getArchitectureName(T.Arch)); 526*0fca6ea1SDimitry Andric if (!ObjForArch) { 527*0fca6ea1SDimitry Andric consumeError(ObjForArch.takeError()); 528*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 529*0fca6ea1SDimitry Andric } 530*0fca6ea1SDimitry Andric auto MachOOrErr = ObjForArch->getAsObjectFile(); 531*0fca6ea1SDimitry Andric if (!MachOOrErr) { 532*0fca6ea1SDimitry Andric consumeError(MachOOrErr.takeError()); 533*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 534*0fca6ea1SDimitry Andric } 535*0fca6ea1SDimitry Andric auto &Obj = **MachOOrErr; 536*0fca6ea1SDimitry Andric auto DiCtx = DWARFContext::create( 537*0fca6ea1SDimitry Andric Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "", 538*0fca6ea1SDimitry Andric DWARFErrorHandler, DWARFErrorHandler); 539*0fca6ea1SDimitry Andric 540*0fca6ea1SDimitry Andric return accumulateLocs(Obj, DiCtx); 541*0fca6ea1SDimitry Andric } 542*0fca6ea1SDimitry Andric return SymbolToSourceLocMap(); 543*0fca6ea1SDimitry Andric } 544