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