xref: /llvm-project/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp (revision 7ea7267cc5bcc13d6cd5c9f31bf645416e13b0c1)
1 //===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// Implements the TAPI Reader for Mach-O dynamic libraries.
10 ///
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/TextAPI/DylibReader.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/Object/Binary.h"
16 #include "llvm/Object/MachOUniversal.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/TargetParser/Triple.h"
19 #include "llvm/TextAPI/RecordsSlice.h"
20 #include "llvm/TextAPI/TextAPIError.h"
21 #include <iomanip>
22 #include <set>
23 #include <sstream>
24 #include <string>
25 
26 using namespace llvm;
27 using namespace llvm::object;
28 using namespace llvm::MachO;
29 using namespace llvm::MachO::DylibReader;
30 
31 using TripleVec = std::vector<Triple>;
32 
33 static TripleVec constructTriples(MachOObjectFile *Obj,
34                                   const Architecture ArchT) {
35   auto getOSVersionStr = [](uint32_t V) {
36     PackedVersion OSVersion(V);
37     std::string Vers;
38     raw_string_ostream VStream(Vers);
39     VStream << OSVersion;
40     return VStream.str();
41   };
42   auto getOSVersion = [&](const MachOObjectFile::LoadCommandInfo &cmd) {
43     auto Vers = Obj->getVersionMinLoadCommand(cmd);
44     return getOSVersionStr(Vers.version);
45   };
46 
47   TripleVec Triples;
48   bool IsIntel = ArchitectureSet(ArchT).hasX86();
49   auto Arch = getArchitectureName(ArchT);
50 
51   for (const auto &cmd : Obj->load_commands()) {
52     std::string OSVersion;
53     switch (cmd.C.cmd) {
54     case MachO::LC_VERSION_MIN_MACOSX:
55       OSVersion = getOSVersion(cmd);
56       Triples.emplace_back(Arch, "apple", "macos" + OSVersion);
57       break;
58     case MachO::LC_VERSION_MIN_IPHONEOS:
59       OSVersion = getOSVersion(cmd);
60       if (IsIntel)
61         Triples.emplace_back(Arch, "apple", "ios" + OSVersion, "simulator");
62       else
63         Triples.emplace_back(Arch, "apple", "ios" + OSVersion);
64       break;
65     case MachO::LC_VERSION_MIN_TVOS:
66       OSVersion = getOSVersion(cmd);
67       if (IsIntel)
68         Triples.emplace_back(Arch, "apple", "tvos" + OSVersion, "simulator");
69       else
70         Triples.emplace_back(Arch, "apple", "tvos" + OSVersion);
71       break;
72     case MachO::LC_VERSION_MIN_WATCHOS:
73       OSVersion = getOSVersion(cmd);
74       if (IsIntel)
75         Triples.emplace_back(Arch, "apple", "watchos" + OSVersion, "simulator");
76       else
77         Triples.emplace_back(Arch, "apple", "watchos" + OSVersion);
78       break;
79     case MachO::LC_BUILD_VERSION: {
80       OSVersion = getOSVersionStr(Obj->getBuildVersionLoadCommand(cmd).minos);
81       switch (Obj->getBuildVersionLoadCommand(cmd).platform) {
82       case MachO::PLATFORM_MACOS:
83         Triples.emplace_back(Arch, "apple", "macos" + OSVersion);
84         break;
85       case MachO::PLATFORM_IOS:
86         Triples.emplace_back(Arch, "apple", "ios" + OSVersion);
87         break;
88       case MachO::PLATFORM_TVOS:
89         Triples.emplace_back(Arch, "apple", "tvos" + OSVersion);
90         break;
91       case MachO::PLATFORM_WATCHOS:
92         Triples.emplace_back(Arch, "apple", "watchos" + OSVersion);
93         break;
94       case MachO::PLATFORM_BRIDGEOS:
95         Triples.emplace_back(Arch, "apple", "bridgeos" + OSVersion);
96         break;
97       case MachO::PLATFORM_MACCATALYST:
98         Triples.emplace_back(Arch, "apple", "ios" + OSVersion, "macabi");
99         break;
100       case MachO::PLATFORM_IOSSIMULATOR:
101         Triples.emplace_back(Arch, "apple", "ios" + OSVersion, "simulator");
102         break;
103       case MachO::PLATFORM_TVOSSIMULATOR:
104         Triples.emplace_back(Arch, "apple", "tvos" + OSVersion, "simulator");
105         break;
106       case MachO::PLATFORM_WATCHOSSIMULATOR:
107         Triples.emplace_back(Arch, "apple", "watchos" + OSVersion, "simulator");
108         break;
109       case MachO::PLATFORM_DRIVERKIT:
110         Triples.emplace_back(Arch, "apple", "driverkit" + OSVersion);
111         break;
112       default:
113         break; // Skip any others.
114       }
115       break;
116     }
117     default:
118       break;
119     }
120   }
121 
122   // Record unknown platform for older binaries that don't enforce platform
123   // load commands.
124   if (Triples.empty())
125     Triples.emplace_back(Arch, "apple", "unknown");
126 
127   return Triples;
128 }
129 
130 static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice) {
131   auto H = Obj->getHeader();
132   auto &BA = Slice.getBinaryAttrs();
133 
134   switch (H.filetype) {
135   default:
136     llvm_unreachable("unsupported binary type");
137   case MachO::MH_DYLIB:
138     BA.File = FileType::MachO_DynamicLibrary;
139     break;
140   case MachO::MH_DYLIB_STUB:
141     BA.File = FileType::MachO_DynamicLibrary_Stub;
142     break;
143   case MachO::MH_BUNDLE:
144     BA.File = FileType::MachO_Bundle;
145     break;
146   }
147 
148   if (H.flags & MachO::MH_TWOLEVEL)
149     BA.TwoLevelNamespace = true;
150   if (H.flags & MachO::MH_APP_EXTENSION_SAFE)
151     BA.AppExtensionSafe = true;
152 
153   for (const auto &LCI : Obj->load_commands()) {
154     switch (LCI.C.cmd) {
155     case MachO::LC_ID_DYLIB: {
156       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
157       BA.InstallName = Slice.copyString(LCI.Ptr + DLLC.dylib.name);
158       BA.CurrentVersion = DLLC.dylib.current_version;
159       BA.CompatVersion = DLLC.dylib.compatibility_version;
160       break;
161     }
162     case MachO::LC_REEXPORT_DYLIB: {
163       auto DLLC = Obj->getDylibIDLoadCommand(LCI);
164       BA.RexportedLibraries.emplace_back(
165           Slice.copyString(LCI.Ptr + DLLC.dylib.name));
166       break;
167     }
168     case MachO::LC_SUB_FRAMEWORK: {
169       auto SFC = Obj->getSubFrameworkCommand(LCI);
170       BA.ParentUmbrella = Slice.copyString(LCI.Ptr + SFC.umbrella);
171       break;
172     }
173     case MachO::LC_SUB_CLIENT: {
174       auto SCLC = Obj->getSubClientCommand(LCI);
175       BA.AllowableClients.emplace_back(Slice.copyString(LCI.Ptr + SCLC.client));
176       break;
177     }
178     case MachO::LC_UUID: {
179       auto UUIDLC = Obj->getUuidCommand(LCI);
180       std::stringstream Stream;
181       for (unsigned I = 0; I < 16; ++I) {
182         if (I == 4 || I == 6 || I == 8 || I == 10)
183           Stream << '-';
184         Stream << std::setfill('0') << std::setw(2) << std::uppercase
185                << std::hex << static_cast<int>(UUIDLC.uuid[I]);
186       }
187       BA.UUID = Slice.copyString(Stream.str());
188       break;
189     }
190     case MachO::LC_RPATH: {
191       auto RPLC = Obj->getRpathCommand(LCI);
192       BA.RPaths.emplace_back(Slice.copyString(LCI.Ptr + RPLC.path));
193       break;
194     }
195     case MachO::LC_SEGMENT_SPLIT_INFO: {
196       auto SSILC = Obj->getLinkeditDataLoadCommand(LCI);
197       if (SSILC.datasize == 0)
198         BA.OSLibNotForSharedCache = true;
199       break;
200     }
201     default:
202       break;
203     }
204   }
205 
206   for (auto &Sect : Obj->sections()) {
207     auto SectName = Sect.getName();
208     if (!SectName)
209       return SectName.takeError();
210     if (*SectName != "__objc_imageinfo" && *SectName != "__image_info")
211       continue;
212 
213     auto Content = Sect.getContents();
214     if (!Content)
215       return Content.takeError();
216 
217     if ((Content->size() >= 8) && (Content->front() == 0)) {
218       uint32_t Flags;
219       if (Obj->isLittleEndian()) {
220         auto *p =
221             reinterpret_cast<const support::ulittle32_t *>(Content->data() + 4);
222         Flags = *p;
223       } else {
224         auto *p =
225             reinterpret_cast<const support::ubig32_t *>(Content->data() + 4);
226         Flags = *p;
227       }
228       BA.SwiftABI = (Flags >> 8) & 0xFF;
229     }
230   }
231   return Error::success();
232 }
233 
234 static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice,
235                          const ParseOption &Opt) {
236 
237   auto parseExport = [](const auto ExportFlags,
238                         auto Addr) -> std::tuple<SymbolFlags, RecordLinkage> {
239     SymbolFlags Flags = SymbolFlags::None;
240     switch (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) {
241     case MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
242       if (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION)
243         Flags |= SymbolFlags::WeakDefined;
244       break;
245     case MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
246       Flags |= SymbolFlags::ThreadLocalValue;
247       break;
248     }
249 
250     RecordLinkage Linkage = (ExportFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT)
251                                 ? RecordLinkage::Rexported
252                                 : RecordLinkage::Exported;
253     return {Flags, Linkage};
254   };
255 
256   Error Err = Error::success();
257 
258   StringMap<std::pair<SymbolFlags, RecordLinkage>> Exports;
259   // Collect symbols from export trie first. Sometimes, there are more exports
260   // in the trie than in n-list due to stripping. This is common for swift
261   // mangled symbols.
262   for (auto &Sym : Obj->exports(Err)) {
263     auto [Flags, Linkage] = parseExport(Sym.flags(), Sym.address());
264     Slice.addRecord(Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage);
265     Exports[Sym.name()] = {Flags, Linkage};
266   }
267 
268   for (const auto &Sym : Obj->symbols()) {
269     auto FlagsOrErr = Sym.getFlags();
270     if (!FlagsOrErr)
271       return FlagsOrErr.takeError();
272     auto Flags = *FlagsOrErr;
273 
274     auto NameOrErr = Sym.getName();
275     if (!NameOrErr)
276       return NameOrErr.takeError();
277     auto Name = *NameOrErr;
278 
279     RecordLinkage Linkage = RecordLinkage::Unknown;
280     SymbolFlags RecordFlags = SymbolFlags::None;
281 
282     if (Opt.Undefineds && (Flags & SymbolRef::SF_Undefined)) {
283       Linkage = RecordLinkage::Undefined;
284       if (Flags & SymbolRef::SF_Weak)
285         RecordFlags |= SymbolFlags::WeakReferenced;
286     } else if (Flags & SymbolRef::SF_Exported) {
287       auto Exp = Exports.find(Name);
288       // This should never be possible when binaries are produced with Apple
289       // linkers. However it is possible to craft dylibs where the export trie
290       // is either malformed or has conflicting symbols compared to n_list.
291       if (Exp != Exports.end())
292         std::tie(RecordFlags, Linkage) = Exp->second;
293       else
294         Linkage = RecordLinkage::Exported;
295     } else if (Flags & SymbolRef::SF_Hidden) {
296       Linkage = RecordLinkage::Internal;
297     } else
298       continue;
299 
300     auto TypeOrErr = Sym.getType();
301     if (!TypeOrErr)
302       return TypeOrErr.takeError();
303     auto Type = *TypeOrErr;
304 
305     GlobalRecord::Kind GV = (Type & SymbolRef::ST_Function)
306                                 ? GlobalRecord::Kind::Function
307                                 : GlobalRecord::Kind::Variable;
308 
309     if (GV == GlobalRecord::Kind::Function)
310       RecordFlags |= SymbolFlags::Text;
311     else
312       RecordFlags |= SymbolFlags::Data;
313 
314     Slice.addRecord(Name, RecordFlags, GV, Linkage);
315   }
316   return Err;
317 }
318 
319 static Error load(MachOObjectFile *Obj, RecordsSlice &Slice,
320                   const ParseOption &Opt, const Architecture Arch) {
321   if (Arch == AK_unknown)
322     return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
323 
324   if (Opt.MachOHeader)
325     if (auto Err = readMachOHeader(Obj, Slice))
326       return Err;
327 
328   if (Opt.SymbolTable)
329     if (auto Err = readSymbols(Obj, Slice, Opt))
330       return Err;
331 
332   return Error::success();
333 }
334 
335 Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer,
336                                         const ParseOption &Opt) {
337   Records Results;
338 
339   auto BinOrErr = createBinary(Buffer);
340   if (!BinOrErr)
341     return BinOrErr.takeError();
342 
343   Binary &Bin = *BinOrErr.get();
344   if (auto *Obj = dyn_cast<MachOObjectFile>(&Bin)) {
345     const auto Arch = getArchitectureFromCpuType(Obj->getHeader().cputype,
346                                                  Obj->getHeader().cpusubtype);
347     if (!Opt.Archs.has(Arch))
348       return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
349 
350     auto Triples = constructTriples(Obj, Arch);
351     for (const auto &T : Triples) {
352       if (mapToPlatformType(T) == PLATFORM_UNKNOWN)
353         return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
354       Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
355       if (auto Err = load(Obj, *Results.back(), Opt, Arch))
356         return std::move(Err);
357       Results.back()->getBinaryAttrs().Path = Buffer.getBufferIdentifier();
358     }
359     return Results;
360   }
361 
362   // Only expect MachO universal binaries at this point.
363   assert(isa<MachOUniversalBinary>(&Bin) &&
364          "Expected a MachO universal binary.");
365   auto *UB = cast<MachOUniversalBinary>(&Bin);
366 
367   for (auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) {
368     // Skip architecture if not requested.
369     auto Arch =
370         getArchitectureFromCpuType(OI->getCPUType(), OI->getCPUSubType());
371     if (!Opt.Archs.has(Arch))
372       continue;
373 
374     // Skip unknown architectures.
375     if (Arch == AK_unknown)
376       continue;
377 
378     // This can fail if the object is an archive.
379     auto ObjOrErr = OI->getAsObjectFile();
380 
381     // Skip the archive and consume the error.
382     if (!ObjOrErr) {
383       consumeError(ObjOrErr.takeError());
384       continue;
385     }
386 
387     auto &Obj = *ObjOrErr.get();
388     switch (Obj.getHeader().filetype) {
389     default:
390       break;
391     case MachO::MH_BUNDLE:
392     case MachO::MH_DYLIB:
393     case MachO::MH_DYLIB_STUB:
394       for (const auto &T : constructTriples(&Obj, Arch)) {
395         Results.emplace_back(std::make_shared<RecordsSlice>(RecordsSlice({T})));
396         if (auto Err = load(&Obj, *Results.back(), Opt, Arch))
397           return std::move(Err);
398       }
399       break;
400     }
401   }
402 
403   if (Results.empty())
404     return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults);
405   return Results;
406 }
407