1//===- DylibReader.cpp -------------- TAPI MachO Dylib Reader --*- C++ -*-===// 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 7//===----------------------------------------------------------------------===// 9/// Implements the TAPI Reader for Mach-O dynamic libraries. 11//===----------------------------------------------------------------------===// 40 std::forward_as_tuple(
T.getArch(),
T.getOS(),
T.getEnvironment());
43if (
I != Container.end() && *
I ==
T)
45return Container.emplace(
I,
T);
50auto getOSVersionStr = [](
uint32_t V) {
59return getOSVersionStr(Vers.version);
67 std::string OSVersion;
69case MachO::LC_VERSION_MIN_MACOSX:
70 OSVersion = getOSVersion(cmd);
71emplace(Triples, {Arch,
"apple",
"macos" + OSVersion});
73case MachO::LC_VERSION_MIN_IPHONEOS:
74 OSVersion = getOSVersion(cmd);
76emplace(Triples, {Arch,
"apple",
"ios" + OSVersion,
"simulator"});
78emplace(Triples, {Arch,
"apple",
"ios" + OSVersion});
80case MachO::LC_VERSION_MIN_TVOS:
81 OSVersion = getOSVersion(cmd);
83emplace(Triples, {Arch,
"apple",
"tvos" + OSVersion,
"simulator"});
85emplace(Triples, {Arch,
"apple",
"tvos" + OSVersion});
87case MachO::LC_VERSION_MIN_WATCHOS:
88 OSVersion = getOSVersion(cmd);
90emplace(Triples, {Arch,
"apple",
"watchos" + OSVersion,
"simulator"});
92emplace(Triples, {Arch,
"apple",
"watchos" + OSVersion});
94case MachO::LC_BUILD_VERSION: {
97case MachO::PLATFORM_MACOS:
98emplace(Triples, {Arch,
"apple",
"macos" + OSVersion});
100case MachO::PLATFORM_IOS:
101emplace(Triples, {Arch,
"apple",
"ios" + OSVersion});
103case MachO::PLATFORM_TVOS:
104emplace(Triples, {Arch,
"apple",
"tvos" + OSVersion});
106case MachO::PLATFORM_WATCHOS:
107emplace(Triples, {Arch,
"apple",
"watchos" + OSVersion});
109case MachO::PLATFORM_BRIDGEOS:
110emplace(Triples, {Arch,
"apple",
"bridgeos" + OSVersion});
112case MachO::PLATFORM_MACCATALYST:
113emplace(Triples, {Arch,
"apple",
"ios" + OSVersion,
"macabi"});
115case MachO::PLATFORM_IOSSIMULATOR:
116emplace(Triples, {Arch,
"apple",
"ios" + OSVersion,
"simulator"});
118case MachO::PLATFORM_TVOSSIMULATOR:
119emplace(Triples, {Arch,
"apple",
"tvos" + OSVersion,
"simulator"});
121case MachO::PLATFORM_WATCHOSSIMULATOR:
122emplace(Triples, {Arch,
"apple",
"watchos" + OSVersion,
"simulator"});
124case MachO::PLATFORM_DRIVERKIT:
125emplace(Triples, {Arch,
"apple",
"driverkit" + OSVersion});
128break;
// Skip any others. 137// Record unknown platform for older binaries that don't enforce platform 140emplace(Triples, {Arch,
"apple",
"unknown"});
147auto &BA =
Slice.getBinaryAttrs();
153 BA.File = FileType::MachO_DynamicLibrary;
156 BA.File = FileType::MachO_DynamicLibrary_Stub;
159 BA.File = FileType::MachO_Bundle;
164 BA.TwoLevelNamespace =
true;
166 BA.AppExtensionSafe =
true;
170case MachO::LC_ID_DYLIB: {
172 BA.InstallName =
Slice.copyString(LCI.Ptr + DLLC.dylib.name);
173 BA.CurrentVersion = DLLC.dylib.current_version;
174 BA.CompatVersion = DLLC.dylib.compatibility_version;
177case MachO::LC_REEXPORT_DYLIB: {
179 BA.RexportedLibraries.emplace_back(
180Slice.copyString(LCI.Ptr + DLLC.dylib.name));
183case MachO::LC_SUB_FRAMEWORK: {
185 BA.ParentUmbrella =
Slice.copyString(LCI.Ptr + SFC.umbrella);
188case MachO::LC_SUB_CLIENT: {
190 BA.AllowableClients.emplace_back(
Slice.copyString(LCI.Ptr + SCLC.client));
193case MachO::LC_UUID: {
195 std::stringstream Stream;
196for (
unsignedI = 0;
I < 16; ++
I) {
197if (
I == 4 ||
I == 6 ||
I == 8 ||
I == 10)
199 Stream << std::setfill(
'0') << std::setw(2) << std::uppercase
200 << std::hex << static_cast<int>(UUIDLC.uuid[
I]);
202 BA.UUID =
Slice.copyString(Stream.str());
205case MachO::LC_RPATH: {
207 BA.RPaths.emplace_back(
Slice.copyString(LCI.Ptr + RPLC.path));
210case MachO::LC_SEGMENT_SPLIT_INFO: {
212if (SSILC.datasize == 0)
213 BA.OSLibNotForSharedCache =
true;
222auto SectName = Sect.getName();
224return SectName.takeError();
225if (*SectName !=
"__objc_imageinfo" && *SectName !=
"__image_info")
228autoContent = Sect.getContents();
243 BA.SwiftABI = (Flags >> 8) & 0xFF;
252auto parseExport = [](
constauto ExportFlags,
253autoAddr) -> std::tuple<SymbolFlags, RecordLinkage> {
258 Flags |= SymbolFlags::WeakDefined;
261 Flags |= SymbolFlags::ThreadLocalValue;
266 ? RecordLinkage::Rexported
267 : RecordLinkage::Exported;
268return {Flags, Linkage};
274// Collect symbols from export trie first. Sometimes, there are more exports 275// in the trie than in n-list due to stripping. This is common for swift 278auto [Flags, Linkage] = parseExport(
Sym.flags(),
Sym.address());
279Slice.addRecord(
Sym.name(), Flags, GlobalRecord::Kind::Unknown, Linkage);
280 Exports[
Sym.name()] = {Flags, Linkage};
286return FlagsOrErr.takeError();
287auto Flags = *FlagsOrErr;
291return NameOrErr.takeError();
292autoName = *NameOrErr;
297if (Flags & SymbolRef::SF_Undefined) {
299 Linkage = RecordLinkage::Undefined;
302if (Flags & SymbolRef::SF_Weak)
303 RecordFlags |= SymbolFlags::WeakReferenced;
304 }
elseif (Flags & SymbolRef::SF_Exported) {
306// This should never be possible when binaries are produced with Apple 307// linkers. However it is possible to craft dylibs where the export trie 308// is either malformed or has conflicting symbols compared to n_list. 309if (Exp != Exports.
end())
310 std::tie(RecordFlags, Linkage) = Exp->second;
312 Linkage = RecordLinkage::Exported;
313 }
elseif (Flags & SymbolRef::SF_Hidden) {
314 Linkage = RecordLinkage::Internal;
318auto TypeOrErr =
Sym.getType();
320return TypeOrErr.takeError();
321autoType = *TypeOrErr;
324 ? GlobalRecord::Kind::Function
325 : GlobalRecord::Kind::Variable;
327if (GV == GlobalRecord::Kind::Function)
328 RecordFlags |= SymbolFlags::Text;
330 RecordFlags |= SymbolFlags::Data;
332Slice.addRecord(
Name, RecordFlags, GV, Linkage);
340return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
359return BinOrErr.takeError();
362if (
auto *Obj = dyn_cast<MachOObjectFile>(&
Bin)) {
364 Obj->getHeader().cpusubtype);
366return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
369for (
constauto &
T : Triples) {
371return make_error<TextAPIError>(TextAPIErrorCode::UnsupportedTarget);
374return std::move(Err);
380// Only expect MachO universal binaries at this point. 382"Expected a MachO universal binary.");
383auto *UB = cast<MachOUniversalBinary>(&
Bin);
385for (
auto OI = UB->begin_objects(), OE = UB->end_objects(); OI != OE; ++OI) {
386// Skip architecture if not requested. 392// Skip unknown architectures. 396// This can fail if the object is an archive. 397auto ObjOrErr = OI->getAsObjectFile();
399// Skip the archive and consume the error. 405auto &Obj = *ObjOrErr.get();
406switch (Obj.getHeader().filetype) {
415return std::move(Err);
423return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults);
432return SlicesOrErr.takeError();
441const std::unique_ptr<DWARFContext> &DiCtx) {
450if (!(*FlagsOrErr & SymbolRef::SF_Exported))
460auto TypeOrErr =
Symbol.getType();
467auto *DWARFCU = IsCode ? DiCtx->getCompileUnitForCodeAddress(
Address)
468 : DiCtx->getCompileUnitForDataAddress(
Address);
473 : DWARFCU->getVariableForAddress(
Address);
474const std::string File =
DIE.getDeclFile(
475 llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
483autoName = *NameOrErr;
486if (!File.empty() && Line != 0)
502if (DSYMsOrErr->empty())
505constStringRef Path = DSYMsOrErr->front();
507if (
auto Err = BufOrErr.getError())
515// Handle single arch. 516if (
auto *Single = dyn_cast<MachOObjectFile>(BinOrErr->get())) {
518 *Single, DWARFContext::ProcessDebugRelocations::Process,
nullptr,
"",
523// Handle universal companion file. 524if (
auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) {
530auto MachOOrErr = ObjForArch->getAsObjectFile();
535auto &Obj = **MachOOrErr;
537 Obj, DWARFContext::ProcessDebugRelocations::Process,
nullptr,
"",
AMDGPU Mark last scratch load
Function Alias Analysis Results
static TripleVec::iterator emplace(TripleVec &Container, Triple &&T)
static SymbolToSourceLocMap accumulateLocs(MachOObjectFile &Obj, const std::unique_ptr< DWARFContext > &DiCtx)
static Error readSymbols(MachOObjectFile *Obj, RecordsSlice &Slice, const ParseOption &Opt)
static Error readMachOHeader(MachOObjectFile *Obj, RecordsSlice &Slice)
static TripleVec constructTriples(MachOObjectFile *Obj, const Architecture ArchT)
std::vector< Triple > TripleVec
static void DWARFErrorHandler(Error Err)
IntervalMap< SlotIndex, DbgVariableValue, 4 > LocMap
Map of where a user value is live to that value.
Implements the TAPI Record Collection Type.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
Define TAPI specific error codes.
A structured debug information entry.
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler, bool ThreadSafe=false)
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
const BasicBlock & back() const
void insert(KeyT a, KeyT b, ValT y)
insert - Add a mapping of [a;b] to y, coalesce with adjacent intervals.
bool has(Architecture Arch) const
SymbolFlags getFlags() const
StringRef getName() const
StringRef getBufferIdentifier() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
OSType getOS() const
Get the parsed operating system type of this triple.
ArchType getArch() const
Get the parsed architecture type of this triple.
EnvironmentType getEnvironment() const
Get the parsed environment type of this triple.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isLittleEndian() const
MachO::sub_client_command getSubClientCommand(const LoadCommandInfo &L) const
iterator_range< export_iterator > exports(Error &Err) const
For use iterating over all exported symbols.
MachO::build_version_command getBuildVersionLoadCommand(const LoadCommandInfo &L) const
static Expected< std::vector< std::string > > findDsymObjectMembers(StringRef Path)
If the input path is a .dSYM bundle (as created by the dsymutil tool), return the paths to the object...
MachO::rpath_command getRpathCommand(const LoadCommandInfo &L) const
MachO::sub_framework_command getSubFrameworkCommand(const LoadCommandInfo &L) const
const MachO::mach_header & getHeader() const
iterator_range< load_command_iterator > load_commands() const
MachO::uuid_command getUuidCommand(const LoadCommandInfo &L) const
MachO::version_min_command getVersionMinLoadCommand(const LoadCommandInfo &L) const
MachO::linkedit_data_command getLinkeditDataLoadCommand(const LoadCommandInfo &L) const
MachO::dylib_command getDylibIDLoadCommand(const LoadCommandInfo &L) const
section_iterator_range sections() const
symbol_iterator_range symbols() const
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Defines the MachO Dynamic Library Reader.
Expected< Records > readFile(MemoryBufferRef Buffer, const ParseOption &Opt)
Parse Mach-O dynamic libraries to extract TAPI attributes.
SymbolToSourceLocMap accumulateSourceLocFromDSYM(const StringRef DSYM, const Target &T)
Get the source location for each symbol from dylib.
llvm::StringMap< RecordLoc > SymbolToSourceLocMap
Expected< std::unique_ptr< InterfaceFile > > get(MemoryBufferRef Buffer)
Get TAPI file representation of binary dylib.
@ EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
@ EXPORT_SYMBOL_FLAGS_KIND_REGULAR
StringRef getArchitectureName(Architecture Arch)
Convert an architecture slice to a string.
Architecture
Defines the architecture slices that are supported by Text-based Stub files.
PlatformType mapToPlatformType(PlatformType Platform, bool WantSim)
@ EXPORT_SYMBOL_FLAGS_REEXPORT
@ EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
@ EXPORT_SYMBOL_FLAGS_KIND_MASK
std::unique_ptr< InterfaceFile > convertToInterfaceFile(const Records &Slices)
SimpleSymbol parseSymbol(StringRef SymName)
Get symbol classification by parsing the name of a symbol.
Architecture getArchitectureFromCpuType(uint32_t CPUType, uint32_t CPUSubType)
Convert a CPU Type and Subtype pair to an architecture slice.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
This is an optimization pass for GlobalISel generic memory operations.
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
void consumeError(Error Err)
Consume a Error without doing anything.
bool Undefineds
Capture undefined symbols too.
bool MachOHeader
Capture Mach-O header from binary, primarily load commands.
bool SymbolTable
Capture defined symbols out of export trie and n-list.
ArchitectureSet Archs
Determines arch slice to parse.