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