xref: /freebsd-src/contrib/llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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