xref: /src/contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
199aabd70SDimitry Andric //===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===//
299aabd70SDimitry Andric //
399aabd70SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
499aabd70SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
599aabd70SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
699aabd70SDimitry Andric //
799aabd70SDimitry Andric //===----------------------------------------------------------------------===//
899aabd70SDimitry Andric ///
999aabd70SDimitry Andric /// Implements the TAPI Reader for Mach-O dynamic libraries.
1099aabd70SDimitry Andric ///
1199aabd70SDimitry Andric //===----------------------------------------------------------------------===//
1299aabd70SDimitry Andric 
1399aabd70SDimitry Andric #include "llvm/TextAPI/DylibReader.h"
1499aabd70SDimitry Andric #include "llvm/ADT/STLExtras.h"
15ac9a064cSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
16ac9a064cSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1799aabd70SDimitry Andric #include "llvm/Object/Binary.h"
1899aabd70SDimitry Andric #include "llvm/Object/MachOUniversal.h"
1999aabd70SDimitry Andric #include "llvm/Support/Endian.h"
2099aabd70SDimitry Andric #include "llvm/TargetParser/Triple.h"
21ac9a064cSDimitry Andric #include "llvm/TextAPI/InterfaceFile.h"
2299aabd70SDimitry Andric #include "llvm/TextAPI/RecordsSlice.h"
2399aabd70SDimitry Andric #include "llvm/TextAPI/TextAPIError.h"
2499aabd70SDimitry Andric #include <iomanip>
2599aabd70SDimitry Andric #include <set>
2699aabd70SDimitry Andric #include <sstream>
2799aabd70SDimitry Andric #include <string>
2899aabd70SDimitry Andric #include <tuple>
2999aabd70SDimitry Andric 
3099aabd70SDimitry Andric using namespace llvm;
3199aabd70SDimitry Andric using namespace llvm::object;
3299aabd70SDimitry Andric using namespace llvm::MachO;
3399aabd70SDimitry Andric using namespace llvm::MachO::DylibReader;
3499aabd70SDimitry Andric 
3599aabd70SDimitry Andric using TripleVec = std::vector<Triple>;
emplace(TripleVec & Container,Triple && T)3699aabd70SDimitry Andric static typename TripleVec::iterator emplace(TripleVec &Container, Triple &&T) {
3799aabd70SDimitry Andric   auto I = partition_point(Container, [=](const Triple &CT) {
3899aabd70SDimitry Andric     return std::forward_as_tuple(CT.getArch(), CT.getOS(),
3999aabd70SDimitry Andric                                  CT.getEnvironment()) <
4099aabd70SDimitry Andric            std::forward_as_tuple(T.getArch(), T.getOS(), T.getEnvironment());
4199aabd70SDimitry Andric   });
4299aabd70SDimitry Andric 
4399aabd70SDimitry Andric   if (I != Container.end() && *I == T)
4499aabd70SDimitry Andric     return I;
4599aabd70SDimitry Andric   return Container.emplace(I, T);
4699aabd70SDimitry Andric }
4799aabd70SDimitry Andric 
constructTriples(MachOObjectFile * Obj,const Architecture ArchT)4899aabd70SDimitry Andric static TripleVec constructTriples(MachOObjectFile *Obj,
4999aabd70SDimitry Andric                                   const Architecture ArchT) {
5099aabd70SDimitry Andric   auto getOSVersionStr = [](uint32_t V) {
5199aabd70SDimitry Andric     PackedVersion OSVersion(V);
5299aabd70SDimitry Andric     std::string Vers;
5399aabd70SDimitry Andric     raw_string_ostream VStream(Vers);
5499aabd70SDimitry Andric     VStream << OSVersion;
5599aabd70SDimitry Andric     return VStream.str();
5699aabd70SDimitry Andric   };
5799aabd70SDimitry Andric   auto getOSVersion = [&](const MachOObjectFile::LoadCommandInfo &cmd) {
5899aabd70SDimitry Andric     auto Vers = Obj->getVersionMinLoadCommand(cmd);
5999aabd70SDimitry Andric     return getOSVersionStr(Vers.version);
6099aabd70SDimitry Andric   };
6199aabd70SDimitry Andric 
6299aabd70SDimitry Andric   TripleVec Triples;
6399aabd70SDimitry Andric   bool IsIntel = ArchitectureSet(ArchT).hasX86();
6499aabd70SDimitry Andric   auto Arch = getArchitectureName(ArchT);
6599aabd70SDimitry Andric 
6699aabd70SDimitry Andric   for (const auto &cmd : Obj->load_commands()) {
6799aabd70SDimitry Andric     std::string OSVersion;
6899aabd70SDimitry Andric     switch (cmd.C.cmd) {
6999aabd70SDimitry Andric     case MachO::LC_VERSION_MIN_MACOSX:
7099aabd70SDimitry Andric       OSVersion = getOSVersion(cmd);
7199aabd70SDimitry Andric       emplace(Triples, {Arch, "apple", "macos" + OSVersion});
7299aabd70SDimitry Andric       break;
7399aabd70SDimitry Andric     case MachO::LC_VERSION_MIN_IPHONEOS:
7499aabd70SDimitry Andric       OSVersion = getOSVersion(cmd);
7599aabd70SDimitry Andric       if (IsIntel)
7699aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
7799aabd70SDimitry Andric       else
7899aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion});
7999aabd70SDimitry Andric       break;
8099aabd70SDimitry Andric     case MachO::LC_VERSION_MIN_TVOS:
8199aabd70SDimitry Andric       OSVersion = getOSVersion(cmd);
8299aabd70SDimitry Andric       if (IsIntel)
8399aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
8499aabd70SDimitry Andric       else
8599aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
8699aabd70SDimitry Andric       break;
8799aabd70SDimitry Andric     case MachO::LC_VERSION_MIN_WATCHOS:
8899aabd70SDimitry Andric       OSVersion = getOSVersion(cmd);
8999aabd70SDimitry Andric       if (IsIntel)
9099aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
9199aabd70SDimitry Andric       else
9299aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
9399aabd70SDimitry Andric       break;
9499aabd70SDimitry Andric     case MachO::LC_BUILD_VERSION: {
9599aabd70SDimitry Andric       OSVersion = getOSVersionStr(Obj->getBuildVersionLoadCommand(cmd).minos);
9699aabd70SDimitry Andric       switch (Obj->getBuildVersionLoadCommand(cmd).platform) {
9799aabd70SDimitry Andric       case MachO::PLATFORM_MACOS:
9899aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "macos" + OSVersion});
9999aabd70SDimitry Andric         break;
10099aabd70SDimitry Andric       case MachO::PLATFORM_IOS:
10199aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion});
10299aabd70SDimitry Andric         break;
10399aabd70SDimitry Andric       case MachO::PLATFORM_TVOS:
10499aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion});
10599aabd70SDimitry Andric         break;
10699aabd70SDimitry Andric       case MachO::PLATFORM_WATCHOS:
10799aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion});
10899aabd70SDimitry Andric         break;
10999aabd70SDimitry Andric       case MachO::PLATFORM_BRIDGEOS:
11099aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "bridgeos" + OSVersion});
11199aabd70SDimitry Andric         break;
11299aabd70SDimitry Andric       case MachO::PLATFORM_MACCATALYST:
11399aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "macabi"});
11499aabd70SDimitry Andric         break;
11599aabd70SDimitry Andric       case MachO::PLATFORM_IOSSIMULATOR:
11699aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "ios" + OSVersion, "simulator"});
11799aabd70SDimitry Andric         break;
11899aabd70SDimitry Andric       case MachO::PLATFORM_TVOSSIMULATOR:
11999aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "tvos" + OSVersion, "simulator"});
12099aabd70SDimitry Andric         break;
12199aabd70SDimitry Andric       case MachO::PLATFORM_WATCHOSSIMULATOR:
12299aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "watchos" + OSVersion, "simulator"});
12399aabd70SDimitry Andric         break;
12499aabd70SDimitry Andric       case MachO::PLATFORM_DRIVERKIT:
12599aabd70SDimitry Andric         emplace(Triples, {Arch, "apple", "driverkit" + OSVersion});
12699aabd70SDimitry Andric         break;
12799aabd70SDimitry Andric       default:
12899aabd70SDimitry Andric         break; // Skip any others.
12999aabd70SDimitry Andric       }
13099aabd70SDimitry Andric       break;
13199aabd70SDimitry Andric     }
13299aabd70SDimitry Andric     default:
13399aabd70SDimitry Andric       break;
13499aabd70SDimitry Andric     }
13599aabd70SDimitry Andric   }
13699aabd70SDimitry Andric 
13799aabd70SDimitry Andric   // Record unknown platform for older binaries that don't enforce platform
13899aabd70SDimitry Andric   // load commands.
13999aabd70SDimitry Andric   if (Triples.empty())
14099aabd70SDimitry Andric     emplace(Triples, {Arch, "apple", "unknown"});
14199aabd70SDimitry Andric 
14299aabd70SDimitry Andric   return Triples;
14399aabd70SDimitry Andric }
14499aabd70SDimitry Andric 
readMachOHeader(MachOObjectFile * Obj,RecordsSlice & Slice)14599aabd70SDimitry Andric static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice) {
14699aabd70SDimitry Andric   auto H = Obj->getHeader();
14799aabd70SDimitry Andric   auto &BA = Slice.getBinaryAttrs();
14899aabd70SDimitry Andric 
14999aabd70SDimitry Andric   switch (H.filetype) {
15099aabd70SDimitry Andric   default:
15199aabd70SDimitry Andric     llvm_unreachable("unsupported binary type");
15299aabd70SDimitry Andric   case MachO::MH_DYLIB:
15399aabd70SDimitry Andric     BA.File = FileType::MachO_DynamicLibrary;
15499aabd70SDimitry Andric     break;
15599aabd70SDimitry Andric   case MachO::MH_DYLIB_STUB:
15699aabd70SDimitry Andric     BA.File = FileType::MachO_DynamicLibrary_Stub;
15799aabd70SDimitry Andric     break;
15899aabd70SDimitry Andric   case MachO::MH_BUNDLE:
15999aabd70SDimitry Andric     BA.File = FileType::MachO_Bundle;
16099aabd70SDimitry Andric     break;
16199aabd70SDimitry Andric   }
16299aabd70SDimitry Andric 
16399aabd70SDimitry Andric   if (H.flags & MachO::MH_TWOLEVEL)
16499aabd70SDimitry Andric     BA.TwoLevelNamespace = true;
16599aabd70SDimitry Andric   if (H.flags & MachO::MH_APP_EXTENSION_SAFE)
16699aabd70SDimitry Andric     BA.AppExtensionSafe = true;
16799aabd70SDimitry Andric 
16899aabd70SDimitry Andric   for (const auto &LCI : Obj->load_commands()) {
16999aabd70SDimitry Andric     switch (LCI.C.cmd) {
17099aabd70SDimitry Andric     case MachO::LC_ID_DYLIB: {
17199aabd70SDimitry Andric       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
17299aabd70SDimitry Andric       BA.InstallName = Slice.copyString(LCI.Ptr + DLLC.dylib.name);
17399aabd70SDimitry Andric       BA.CurrentVersion = DLLC.dylib.current_version;
17499aabd70SDimitry Andric       BA.CompatVersion = DLLC.dylib.compatibility_version;
17599aabd70SDimitry Andric       break;
17699aabd70SDimitry Andric     }
17799aabd70SDimitry Andric     case MachO::LC_REEXPORT_DYLIB: {
17899aabd70SDimitry Andric       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
17999aabd70SDimitry Andric       BA.RexportedLibraries.emplace_back(
18099aabd70SDimitry Andric           Slice.copyString(LCI.Ptr + DLLC.dylib.name));
18199aabd70SDimitry Andric       break;
18299aabd70SDimitry Andric     }
18399aabd70SDimitry Andric     case MachO::LC_SUB_FRAMEWORK: {
18499aabd70SDimitry Andric       auto SFC = Obj->getSubFrameworkCommand(LCI);
18599aabd70SDimitry Andric       BA.ParentUmbrella = Slice.copyString(LCI.Ptr + SFC.umbrella);
18699aabd70SDimitry Andric       break;
18799aabd70SDimitry Andric     }
18899aabd70SDimitry Andric     case MachO::LC_SUB_CLIENT: {
18999aabd70SDimitry Andric       auto SCLC = Obj->getSubClientCommand(LCI);
19099aabd70SDimitry Andric       BA.AllowableClients.emplace_back(Slice.copyString(LCI.Ptr + SCLC.client));
19199aabd70SDimitry Andric       break;
19299aabd70SDimitry Andric     }
19399aabd70SDimitry Andric     case MachO::LC_UUID: {
19499aabd70SDimitry Andric       auto UUIDLC = Obj->getUuidCommand(LCI);
19599aabd70SDimitry Andric       std::stringstream Stream;
19699aabd70SDimitry Andric       for (unsigned I = 0; I < 16; ++I) {
19799aabd70SDimitry Andric         if (I == 4 || I == 6 || I == 8 || I == 10)
19899aabd70SDimitry Andric           Stream << '-';
19999aabd70SDimitry Andric         Stream << std::setfill('0') << std::setw(2) << std::uppercase
20099aabd70SDimitry Andric                << std::hex << static_cast<int>(UUIDLC.uuid[I]);
20199aabd70SDimitry Andric       }
20299aabd70SDimitry Andric       BA.UUID = Slice.copyString(Stream.str());
20399aabd70SDimitry Andric       break;
20499aabd70SDimitry Andric     }
20599aabd70SDimitry Andric     case MachO::LC_RPATH: {
20699aabd70SDimitry Andric       auto RPLC = Obj->getRpathCommand(LCI);
20799aabd70SDimitry Andric       BA.RPaths.emplace_back(Slice.copyString(LCI.Ptr + RPLC.path));
20899aabd70SDimitry Andric       break;
20999aabd70SDimitry Andric     }
21099aabd70SDimitry Andric     case MachO::LC_SEGMENT_SPLIT_INFO: {
21199aabd70SDimitry Andric       auto SSILC = Obj->getLinkeditDataLoadCommand(LCI);
21299aabd70SDimitry Andric       if (SSILC.datasize == 0)
21399aabd70SDimitry Andric         BA.OSLibNotForSharedCache = true;
21499aabd70SDimitry Andric       break;
21599aabd70SDimitry Andric     }
21699aabd70SDimitry Andric     default:
21799aabd70SDimitry Andric       break;
21899aabd70SDimitry Andric     }
21999aabd70SDimitry Andric   }
22099aabd70SDimitry Andric 
22199aabd70SDimitry Andric   for (auto &Sect : Obj->sections()) {
22299aabd70SDimitry Andric     auto SectName = Sect.getName();
22399aabd70SDimitry Andric     if (!SectName)
22499aabd70SDimitry Andric       return SectName.takeError();
22599aabd70SDimitry Andric     if (*SectName != "__objc_imageinfo" && *SectName != "__image_info")
22699aabd70SDimitry Andric       continue;
22799aabd70SDimitry Andric 
22899aabd70SDimitry Andric     auto Content = Sect.getContents();
22999aabd70SDimitry Andric     if (!Content)
23099aabd70SDimitry Andric       return Content.takeError();
23199aabd70SDimitry Andric 
23299aabd70SDimitry Andric     if ((Content->size() >= 8) && (Content->front() == 0)) {
23399aabd70SDimitry Andric       uint32_t Flags;
23499aabd70SDimitry Andric       if (Obj->isLittleEndian()) {
23599aabd70SDimitry Andric         auto *p =
23699aabd70SDimitry Andric             reinterpret_cast<const support::ulittle32_t *>(Content->data() + 4);
23799aabd70SDimitry Andric         Flags = *p;
23899aabd70SDimitry Andric       } else {
23999aabd70SDimitry Andric         auto *p =
24099aabd70SDimitry Andric             reinterpret_cast<const support::ubig32_t *>(Content->data() + 4);
24199aabd70SDimitry Andric         Flags = *p;
24299aabd70SDimitry Andric       }
24399aabd70SDimitry Andric       BA.SwiftABI = (Flags >> 8) & 0xFF;
24499aabd70SDimitry Andric     }
24599aabd70SDimitry Andric   }
24699aabd70SDimitry Andric   return Error::success();
24799aabd70SDimitry Andric }
24899aabd70SDimitry Andric 
readSymbols(MachOObjectFile * Obj,RecordsSlice & Slice,const ParseOption & Opt)24999aabd70SDimitry Andric static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice,
25099aabd70SDimitry Andric                          const ParseOption &Opt) {
25199aabd70SDimitry Andric 
25299aabd70SDimitry Andric   auto parseExport = [](const auto ExportFlags,
25399aabd70SDimitry Andric                         auto Addr) -> std::tuple<SymbolFlags, RecordLinkage> {
25499aabd70SDimitry Andric     SymbolFlags Flags = SymbolFlags::None;
25599aabd70SDimitry Andric     switch (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) {
25699aabd70SDimitry Andric     case MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
25799aabd70SDimitry Andric       if (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION)
25899aabd70SDimitry Andric         Flags |= SymbolFlags::WeakDefined;
25999aabd70SDimitry Andric       break;
26099aabd70SDimitry Andric     case MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
26199aabd70SDimitry Andric       Flags |= SymbolFlags::ThreadLocalValue;
26299aabd70SDimitry Andric       break;
26399aabd70SDimitry Andric     }
26499aabd70SDimitry Andric 
26599aabd70SDimitry Andric     RecordLinkage Linkage = (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT)
26699aabd70SDimitry Andric                                 ? RecordLinkage::Rexported
26799aabd70SDimitry Andric                                 : RecordLinkage::Exported;
26899aabd70SDimitry Andric     return {Flags, Linkage};
26999aabd70SDimitry Andric   };
27099aabd70SDimitry Andric 
27199aabd70SDimitry Andric   Error Err = Error::success();
27299aabd70SDimitry Andric 
27399aabd70SDimitry Andric   StringMap<std::pair<SymbolFlags, RecordLinkage>> Exports;
27499aabd70SDimitry Andric   // Collect symbols from export trie first. Sometimes, there are more exports
27599aabd70SDimitry Andric   // in the trie than in n-list due to stripping. This is common for swift
27699aabd70SDimitry Andric   // mangled symbols.
27799aabd70SDimitry Andric   for (auto &Sym : Obj->exports(Err)) {
27899aabd70SDimitry Andric     auto [Flags, Linkage] = parseExport(Sym.flags(), Sym.address());
27999aabd70SDimitry Andric     Slice.addRecord(Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage);
28099aabd70SDimitry Andric     Exports[Sym.name()] = {Flags, Linkage};
28199aabd70SDimitry Andric   }
28299aabd70SDimitry Andric 
28399aabd70SDimitry Andric   for (const auto &Sym : Obj->symbols()) {
28499aabd70SDimitry Andric     auto FlagsOrErr = Sym.getFlags();
28599aabd70SDimitry Andric     if (!FlagsOrErr)
28699aabd70SDimitry Andric       return FlagsOrErr.takeError();
28799aabd70SDimitry Andric     auto Flags = *FlagsOrErr;
28899aabd70SDimitry Andric 
28999aabd70SDimitry Andric     auto NameOrErr = Sym.getName();
29099aabd70SDimitry Andric     if (!NameOrErr)
29199aabd70SDimitry Andric       return NameOrErr.takeError();
29299aabd70SDimitry Andric     auto Name = *NameOrErr;
29399aabd70SDimitry Andric 
29499aabd70SDimitry Andric     RecordLinkage Linkage = RecordLinkage::Unknown;
29599aabd70SDimitry Andric     SymbolFlags RecordFlags = SymbolFlags::None;
29699aabd70SDimitry Andric 
297ac9a064cSDimitry Andric     if (Flags & SymbolRef::SF_Undefined) {
298ac9a064cSDimitry Andric       if (Opt.Undefineds)
29999aabd70SDimitry Andric         Linkage = RecordLinkage::Undefined;
300ac9a064cSDimitry Andric       else
301ac9a064cSDimitry Andric         continue;
30299aabd70SDimitry Andric       if (Flags & SymbolRef::SF_Weak)
30399aabd70SDimitry Andric         RecordFlags |= SymbolFlags::WeakReferenced;
30499aabd70SDimitry Andric     } else if (Flags & SymbolRef::SF_Exported) {
30599aabd70SDimitry Andric       auto Exp = Exports.find(Name);
30699aabd70SDimitry Andric       // This should never be possible when binaries are produced with Apple
30799aabd70SDimitry Andric       // linkers. However it is possible to craft dylibs where the export trie
30899aabd70SDimitry Andric       // is either malformed or has conflicting symbols compared to n_list.
30999aabd70SDimitry Andric       if (Exp != Exports.end())
31099aabd70SDimitry Andric         std::tie(RecordFlags, Linkage) = Exp->second;
31199aabd70SDimitry Andric       else
31299aabd70SDimitry Andric         Linkage = RecordLinkage::Exported;
31399aabd70SDimitry Andric     } else if (Flags & SymbolRef::SF_Hidden) {
31499aabd70SDimitry Andric       Linkage = RecordLinkage::Internal;
31599aabd70SDimitry Andric     } else
31699aabd70SDimitry Andric       continue;
31799aabd70SDimitry Andric 
31899aabd70SDimitry Andric     auto TypeOrErr = Sym.getType();
31999aabd70SDimitry Andric     if (!TypeOrErr)
32099aabd70SDimitry Andric       return TypeOrErr.takeError();
32199aabd70SDimitry Andric     auto Type = *TypeOrErr;
32299aabd70SDimitry Andric 
32399aabd70SDimitry Andric     GlobalRecord::Kind GV = (Type & SymbolRef::ST_Function)
32499aabd70SDimitry Andric                                 ? GlobalRecord::Kind::Function
32599aabd70SDimitry Andric                                 : GlobalRecord::Kind::Variable;
32699aabd70SDimitry Andric 
32799aabd70SDimitry Andric     if (GV == GlobalRecord::Kind::Function)
32899aabd70SDimitry Andric       RecordFlags |= SymbolFlags::Text;
32999aabd70SDimitry Andric     else
33099aabd70SDimitry Andric       RecordFlags |= SymbolFlags::Data;
33199aabd70SDimitry Andric 
33299aabd70SDimitry Andric     Slice.addRecord(Name, RecordFlags, GV, Linkage);
33399aabd70SDimitry Andric   }
33499aabd70SDimitry Andric   return Err;
33599aabd70SDimitry Andric }
33699aabd70SDimitry Andric 
load(MachOObjectFile * Obj,RecordsSlice & Slice,const ParseOption & Opt,const Architecture Arch)33799aabd70SDimitry Andric static Error load(MachOObjectFile *Obj, RecordsSlice &Slice,
33899aabd70SDimitry Andric                   const ParseOption &Opt, const Architecture Arch) {
33999aabd70SDimitry Andric   if (Arch == AK_unknown)
34099aabd70SDimitry Andric     return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
34199aabd70SDimitry Andric 
34299aabd70SDimitry Andric   if (Opt.MachOHeader)
34399aabd70SDimitry Andric     if (auto Err = readMachOHeader(Obj, Slice))
34499aabd70SDimitry Andric       return Err;
34599aabd70SDimitry Andric 
34699aabd70SDimitry Andric   if (Opt.SymbolTable)
34799aabd70SDimitry Andric     if (auto Err = readSymbols(Obj, Slice, Opt))
34899aabd70SDimitry Andric       return Err;
34999aabd70SDimitry Andric 
35099aabd70SDimitry Andric   return Error::success();
35199aabd70SDimitry Andric }
35299aabd70SDimitry Andric 
readFile(MemoryBufferRef Buffer,const ParseOption & Opt)35399aabd70SDimitry Andric Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer,
35499aabd70SDimitry Andric                                         const ParseOption &Opt) {
35599aabd70SDimitry Andric   Records Results;
35699aabd70SDimitry Andric 
35799aabd70SDimitry Andric   auto BinOrErr = createBinary(Buffer);
35899aabd70SDimitry Andric   if (!BinOrErr)
35999aabd70SDimitry Andric     return BinOrErr.takeError();
36099aabd70SDimitry Andric 
36199aabd70SDimitry Andric   Binary &Bin = *BinOrErr.get();
36299aabd70SDimitry Andric   if (auto *Obj = dyn_cast<MachOObjectFile>(&Bin)) {
36399aabd70SDimitry Andric     const auto Arch = getArchitectureFromCpuType(Obj->getHeader().cputype,
36499aabd70SDimitry Andric                                                  Obj->getHeader().cpusubtype);
36599aabd70SDimitry Andric     if (!Opt.Archs.has(Arch))
36699aabd70SDimitry Andric       return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
36799aabd70SDimitry Andric 
36899aabd70SDimitry Andric     auto Triples = constructTriples(Obj, Arch);
36999aabd70SDimitry Andric     for (const auto &T : Triples) {
37099aabd70SDimitry Andric       if (mapToPlatformType(T) == PLATFORM_UNKNOWN)
37199aabd70SDimitry Andric         return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
37299aabd70SDimitry Andric       Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
37399aabd70SDimitry Andric       if (auto Err = load(Obj, *Results.back(), Opt, Arch))
37499aabd70SDimitry Andric         return std::move(Err);
37599aabd70SDimitry Andric       Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier();
37699aabd70SDimitry Andric     }
37799aabd70SDimitry Andric     return Results;
37899aabd70SDimitry Andric   }
37999aabd70SDimitry Andric 
38099aabd70SDimitry Andric   // Only expect MachO universal binaries at this point.
38199aabd70SDimitry Andric   assert(isa<MachOUniversalBinary>(&Bin) &&
38299aabd70SDimitry Andric          "Expected a MachO universal binary.");
38399aabd70SDimitry Andric   auto *UB = cast<MachOUniversalBinary>(&Bin);
38499aabd70SDimitry Andric 
38599aabd70SDimitry Andric   for (auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) {
38699aabd70SDimitry Andric     // Skip architecture if not requested.
38799aabd70SDimitry Andric     auto Arch =
38899aabd70SDimitry Andric         getArchitectureFromCpuType(OI->getCPUType(), OI->getCPUSubType());
38999aabd70SDimitry Andric     if (!Opt.Archs.has(Arch))
39099aabd70SDimitry Andric       continue;
39199aabd70SDimitry Andric 
39299aabd70SDimitry Andric     // Skip unknown architectures.
39399aabd70SDimitry Andric     if (Arch == AK_unknown)
39499aabd70SDimitry Andric       continue;
39599aabd70SDimitry Andric 
39699aabd70SDimitry Andric     // This can fail if the object is an archive.
39799aabd70SDimitry Andric     auto ObjOrErr = OI->getAsObjectFile();
39899aabd70SDimitry Andric 
39999aabd70SDimitry Andric     // Skip the archive and consume the error.
40099aabd70SDimitry Andric     if (!ObjOrErr) {
40199aabd70SDimitry Andric       consumeError(ObjOrErr.takeError());
40299aabd70SDimitry Andric       continue;
40399aabd70SDimitry Andric     }
40499aabd70SDimitry Andric 
40599aabd70SDimitry Andric     auto &Obj = *ObjOrErr.get();
40699aabd70SDimitry Andric     switch (Obj.getHeader().filetype) {
40799aabd70SDimitry Andric     default:
40899aabd70SDimitry Andric       break;
40999aabd70SDimitry Andric     case MachO::MH_BUNDLE:
41099aabd70SDimitry Andric     case MachO::MH_DYLIB:
41199aabd70SDimitry Andric     case MachO::MH_DYLIB_STUB:
41299aabd70SDimitry Andric       for (const auto &T : constructTriples(&Obj, Arch)) {
41399aabd70SDimitry Andric         Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
41499aabd70SDimitry Andric         if (auto Err = load(&Obj, *Results.back(), Opt, Arch))
41599aabd70SDimitry Andric           return std::move(Err);
416ac9a064cSDimitry Andric         Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier();
41799aabd70SDimitry Andric       }
41899aabd70SDimitry Andric       break;
41999aabd70SDimitry Andric     }
42099aabd70SDimitry Andric   }
42199aabd70SDimitry Andric 
42299aabd70SDimitry Andric   if (Results.empty())
42399aabd70SDimitry Andric     return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults);
42499aabd70SDimitry Andric   return Results;
42599aabd70SDimitry Andric }
42699aabd70SDimitry Andric 
42799aabd70SDimitry Andric Expected<std::unique_ptr<InterfaceFile>>
get(MemoryBufferRef Buffer)42899aabd70SDimitry Andric DylibReader::get(MemoryBufferRef Buffer) {
42999aabd70SDimitry Andric   ParseOption Options;
43099aabd70SDimitry Andric   auto SlicesOrErr = readFile(Buffer, Options);
43199aabd70SDimitry Andric   if (!SlicesOrErr)
43299aabd70SDimitry Andric     return SlicesOrErr.takeError();
43399aabd70SDimitry Andric 
43499aabd70SDimitry Andric   return convertToInterfaceFile(*SlicesOrErr);
43599aabd70SDimitry Andric }
436ac9a064cSDimitry Andric 
DWARFErrorHandler(Error Err)437ac9a064cSDimitry Andric static void DWARFErrorHandler(Error Err) { /**/ }
438ac9a064cSDimitry Andric 
439ac9a064cSDimitry Andric static SymbolToSourceLocMap
accumulateLocs(MachOObjectFile & Obj,const std::unique_ptr<DWARFContext> & DiCtx)440ac9a064cSDimitry Andric accumulateLocs(MachOObjectFile &Obj,
441ac9a064cSDimitry Andric                const std::unique_ptr<DWARFContext> &DiCtx) {
442ac9a064cSDimitry Andric   SymbolToSourceLocMap LocMap;
443ac9a064cSDimitry Andric   for (const auto &Symbol : Obj.symbols()) {
444ac9a064cSDimitry Andric     Expected<uint32_t> FlagsOrErr = Symbol.getFlags();
445ac9a064cSDimitry Andric     if (!FlagsOrErr) {
446ac9a064cSDimitry Andric       consumeError(FlagsOrErr.takeError());
447ac9a064cSDimitry Andric       continue;
448ac9a064cSDimitry Andric     }
449ac9a064cSDimitry Andric 
450ac9a064cSDimitry Andric     if (!(*FlagsOrErr & SymbolRef::SF_Exported))
451ac9a064cSDimitry Andric       continue;
452ac9a064cSDimitry Andric 
453ac9a064cSDimitry Andric     Expected<uint64_t> AddressOrErr = Symbol.getAddress();
454ac9a064cSDimitry Andric     if (!AddressOrErr) {
455ac9a064cSDimitry Andric       consumeError(AddressOrErr.takeError());
456ac9a064cSDimitry Andric       continue;
457ac9a064cSDimitry Andric     }
458ac9a064cSDimitry Andric     const uint64_t Address = *AddressOrErr;
459ac9a064cSDimitry Andric 
460ac9a064cSDimitry Andric     auto TypeOrErr = Symbol.getType();
461ac9a064cSDimitry Andric     if (!TypeOrErr) {
462ac9a064cSDimitry Andric       consumeError(TypeOrErr.takeError());
463ac9a064cSDimitry Andric       continue;
464ac9a064cSDimitry Andric     }
465ac9a064cSDimitry Andric     const bool IsCode = (*TypeOrErr & SymbolRef::ST_Function);
466ac9a064cSDimitry Andric 
467ac9a064cSDimitry Andric     auto *DWARFCU = IsCode ? DiCtx->getCompileUnitForCodeAddress(Address)
468ac9a064cSDimitry Andric                            : DiCtx->getCompileUnitForDataAddress(Address);
469ac9a064cSDimitry Andric     if (!DWARFCU)
470ac9a064cSDimitry Andric       continue;
471ac9a064cSDimitry Andric 
472ac9a064cSDimitry Andric     const DWARFDie &DIE = IsCode ? DWARFCU->getSubroutineForAddress(Address)
473ac9a064cSDimitry Andric                                  : DWARFCU->getVariableForAddress(Address);
474ac9a064cSDimitry Andric     const std::string File = DIE.getDeclFile(
475ac9a064cSDimitry Andric         llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
476ac9a064cSDimitry Andric     const uint64_t Line = DIE.getDeclLine();
477ac9a064cSDimitry Andric 
478ac9a064cSDimitry Andric     auto NameOrErr = Symbol.getName();
479ac9a064cSDimitry Andric     if (!NameOrErr) {
480ac9a064cSDimitry Andric       consumeError(NameOrErr.takeError());
481ac9a064cSDimitry Andric       continue;
482ac9a064cSDimitry Andric     }
483ac9a064cSDimitry Andric     auto Name = *NameOrErr;
484ac9a064cSDimitry Andric     auto Sym = parseSymbol(Name);
485ac9a064cSDimitry Andric 
486ac9a064cSDimitry Andric     if (!File.empty() && Line != 0)
487ac9a064cSDimitry Andric       LocMap.insert({Sym.Name, RecordLoc(File, Line)});
488ac9a064cSDimitry Andric   }
489ac9a064cSDimitry Andric 
490ac9a064cSDimitry Andric   return LocMap;
491ac9a064cSDimitry Andric }
492ac9a064cSDimitry Andric 
493ac9a064cSDimitry Andric SymbolToSourceLocMap
accumulateSourceLocFromDSYM(const StringRef DSYM,const Target & T)494ac9a064cSDimitry Andric DylibReader::accumulateSourceLocFromDSYM(const StringRef DSYM,
495ac9a064cSDimitry Andric                                          const Target &T) {
496ac9a064cSDimitry Andric   // Find sidecar file.
497ac9a064cSDimitry Andric   auto DSYMsOrErr = MachOObjectFile::findDsymObjectMembers(DSYM);
498ac9a064cSDimitry Andric   if (!DSYMsOrErr) {
499ac9a064cSDimitry Andric     consumeError(DSYMsOrErr.takeError());
500ac9a064cSDimitry Andric     return SymbolToSourceLocMap();
501ac9a064cSDimitry Andric   }
502ac9a064cSDimitry Andric   if (DSYMsOrErr->empty())
503ac9a064cSDimitry Andric     return SymbolToSourceLocMap();
504ac9a064cSDimitry Andric 
505ac9a064cSDimitry Andric   const StringRef Path = DSYMsOrErr->front();
506ac9a064cSDimitry Andric   auto BufOrErr = MemoryBuffer::getFile(Path);
507ac9a064cSDimitry Andric   if (auto Err = BufOrErr.getError())
508ac9a064cSDimitry Andric     return SymbolToSourceLocMap();
509ac9a064cSDimitry Andric 
510ac9a064cSDimitry Andric   auto BinOrErr = createBinary(*BufOrErr.get());
511ac9a064cSDimitry Andric   if (!BinOrErr) {
512ac9a064cSDimitry Andric     consumeError(BinOrErr.takeError());
513ac9a064cSDimitry Andric     return SymbolToSourceLocMap();
514ac9a064cSDimitry Andric   }
515ac9a064cSDimitry Andric   // Handle single arch.
516ac9a064cSDimitry Andric   if (auto *Single = dyn_cast<MachOObjectFile>(BinOrErr->get())) {
517ac9a064cSDimitry Andric     auto DiCtx = DWARFContext::create(
518ac9a064cSDimitry Andric         *Single, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
519ac9a064cSDimitry Andric         DWARFErrorHandler, DWARFErrorHandler);
520ac9a064cSDimitry Andric 
521ac9a064cSDimitry Andric     return accumulateLocs(*Single, DiCtx);
522ac9a064cSDimitry Andric   }
523ac9a064cSDimitry Andric   // Handle universal companion file.
524ac9a064cSDimitry Andric   if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) {
525ac9a064cSDimitry Andric     auto ObjForArch = Fat->getObjectForArch(getArchitectureName(T.Arch));
526ac9a064cSDimitry Andric     if (!ObjForArch) {
527ac9a064cSDimitry Andric       consumeError(ObjForArch.takeError());
528ac9a064cSDimitry Andric       return SymbolToSourceLocMap();
529ac9a064cSDimitry Andric     }
530ac9a064cSDimitry Andric     auto MachOOrErr = ObjForArch->getAsObjectFile();
531ac9a064cSDimitry Andric     if (!MachOOrErr) {
532ac9a064cSDimitry Andric       consumeError(MachOOrErr.takeError());
533ac9a064cSDimitry Andric       return SymbolToSourceLocMap();
534ac9a064cSDimitry Andric     }
535ac9a064cSDimitry Andric     auto &Obj = **MachOOrErr;
536ac9a064cSDimitry Andric     auto DiCtx = DWARFContext::create(
537ac9a064cSDimitry Andric         Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
538ac9a064cSDimitry Andric         DWARFErrorHandler, DWARFErrorHandler);
539ac9a064cSDimitry Andric 
540ac9a064cSDimitry Andric     return accumulateLocs(Obj, DiCtx);
541ac9a064cSDimitry Andric   }
542ac9a064cSDimitry Andric   return SymbolToSourceLocMap();
543ac9a064cSDimitry Andric }
544