10b57cec5SDimitry Andric //===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This program is a utility that works like traditional Unix "nm", that is, it
100b57cec5SDimitry Andric // prints out the names of symbols in a bitcode or object file, along with some
110b57cec5SDimitry Andric // information about each symbol.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // This "nm" supports many of the features of GNU "nm", including its different
140b57cec5SDimitry Andric // output formats.
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
190b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
205f757f3fSDimitry Andric #include "llvm/BinaryFormat/MachO.h"
2181ad6265SDimitry Andric #include "llvm/BinaryFormat/XCOFF.h"
225f757f3fSDimitry Andric #include "llvm/DebugInfo/Symbolize/Symbolize.h"
230b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h"
240b57cec5SDimitry Andric #include "llvm/IR/Function.h"
250b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
260b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
270b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
280b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h"
290b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
300b57cec5SDimitry Andric #include "llvm/Object/IRObjectFile.h"
310b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
320b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
330b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
345f757f3fSDimitry Andric #include "llvm/Object/SymbolicFile.h"
355ffd83dbSDimitry Andric #include "llvm/Object/TapiFile.h"
365ffd83dbSDimitry Andric #include "llvm/Object/TapiUniversal.h"
370b57cec5SDimitry Andric #include "llvm/Object/Wasm.h"
3804eeddc0SDimitry Andric #include "llvm/Object/XCOFFObjectFile.h"
39fe6060f1SDimitry Andric #include "llvm/Option/Arg.h"
40fe6060f1SDimitry Andric #include "llvm/Option/ArgList.h"
41fe6060f1SDimitry Andric #include "llvm/Option/Option.h"
420b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
430b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
440b57cec5SDimitry Andric #include "llvm/Support/Format.h"
4506c3fb27SDimitry Andric #include "llvm/Support/LLVMDriver.h"
460b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
470b57cec5SDimitry Andric #include "llvm/Support/Program.h"
480b57cec5SDimitry Andric #include "llvm/Support/Signals.h"
490b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
500b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
510b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
5206c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
5306c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
540b57cec5SDimitry Andric #include <vector>
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric using namespace llvm;
570b57cec5SDimitry Andric using namespace object;
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric namespace {
60fe6060f1SDimitry Andric using namespace llvm::opt; // for HelpHidden in Opts.inc
61fe6060f1SDimitry Andric enum ID {
62fe6060f1SDimitry Andric OPT_INVALID = 0, // This is not an option ID.
635f757f3fSDimitry Andric #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
64fe6060f1SDimitry Andric #include "Opts.inc"
65fe6060f1SDimitry Andric #undef OPTION
66fe6060f1SDimitry Andric };
670b57cec5SDimitry Andric
68bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE) \
69bdd1243dSDimitry Andric static constexpr StringLiteral NAME##_init[] = VALUE; \
70bdd1243dSDimitry Andric static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
71bdd1243dSDimitry Andric std::size(NAME##_init) - 1);
72fe6060f1SDimitry Andric #include "Opts.inc"
73fe6060f1SDimitry Andric #undef PREFIX
740b57cec5SDimitry Andric
75bdd1243dSDimitry Andric static constexpr opt::OptTable::Info InfoTable[] = {
765f757f3fSDimitry Andric #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
77fe6060f1SDimitry Andric #include "Opts.inc"
78fe6060f1SDimitry Andric #undef OPTION
79fe6060f1SDimitry Andric };
800b57cec5SDimitry Andric
81bdd1243dSDimitry Andric class NmOptTable : public opt::GenericOptTable {
82fe6060f1SDimitry Andric public:
NmOptTable()83bdd1243dSDimitry Andric NmOptTable() : opt::GenericOptTable(InfoTable) {
84bdd1243dSDimitry Andric setGroupedShortOptions(true);
85bdd1243dSDimitry Andric }
86fe6060f1SDimitry Andric };
870b57cec5SDimitry Andric
88fe6060f1SDimitry Andric enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
8981ad6265SDimitry Andric enum class BitModeTy { Bit32, Bit64, Bit32_64, Any };
90fe6060f1SDimitry Andric } // namespace
910b57cec5SDimitry Andric
92fe6060f1SDimitry Andric static bool ArchiveMap;
9381ad6265SDimitry Andric static BitModeTy BitMode;
94fe6060f1SDimitry Andric static bool DebugSyms;
95fe6060f1SDimitry Andric static bool DefinedOnly;
96fe6060f1SDimitry Andric static bool Demangle;
97fe6060f1SDimitry Andric static bool DynamicSyms;
9881ad6265SDimitry Andric static bool ExportSymbols;
99fe6060f1SDimitry Andric static bool ExternalOnly;
1005f757f3fSDimitry Andric static bool LineNumbers;
101fe6060f1SDimitry Andric static OutputFormatTy OutputFormat;
102fe6060f1SDimitry Andric static bool NoLLVMBitcode;
103fe6060f1SDimitry Andric static bool NoSort;
104fe6060f1SDimitry Andric static bool NoWeakSymbols;
105fe6060f1SDimitry Andric static bool NumericSort;
106fe6060f1SDimitry Andric static bool PrintFileName;
107fe6060f1SDimitry Andric static bool PrintSize;
108fe6060f1SDimitry Andric static bool Quiet;
109fe6060f1SDimitry Andric static bool ReverseSort;
110fe6060f1SDimitry Andric static bool SpecialSyms;
111fe6060f1SDimitry Andric static bool SizeSort;
112fe6060f1SDimitry Andric static bool UndefinedOnly;
113fe6060f1SDimitry Andric static bool WithoutAliases;
1140b57cec5SDimitry Andric
11581ad6265SDimitry Andric // XCOFF-specific options.
11681ad6265SDimitry Andric static bool NoRsrc;
11781ad6265SDimitry Andric
118fe6060f1SDimitry Andric namespace {
1190b57cec5SDimitry Andric enum Radix { d, o, x };
120fe6060f1SDimitry Andric } // namespace
121fe6060f1SDimitry Andric static Radix AddressRadix;
1220b57cec5SDimitry Andric
123fe6060f1SDimitry Andric // Mach-O specific options.
124fe6060f1SDimitry Andric static bool ArchAll = false;
125fe6060f1SDimitry Andric static std::vector<StringRef> ArchFlags;
126fe6060f1SDimitry Andric static bool AddDyldInfo;
127fe6060f1SDimitry Andric static bool AddInlinedInfo;
128fe6060f1SDimitry Andric static bool DyldInfoOnly;
129fe6060f1SDimitry Andric static bool FormatMachOasHex;
130fe6060f1SDimitry Andric static bool NoDyldInfo;
131fe6060f1SDimitry Andric static std::vector<StringRef> SegSect;
132fe6060f1SDimitry Andric static bool MachOPrintSizeWarning = false;
1330b57cec5SDimitry Andric
134fe6060f1SDimitry Andric // Miscellaneous states.
135fe6060f1SDimitry Andric static bool PrintAddress = true;
136fe6060f1SDimitry Andric static bool MultipleFiles = false;
137fe6060f1SDimitry Andric static bool HadError = false;
1380b57cec5SDimitry Andric
139fe6060f1SDimitry Andric static StringRef ToolName;
1400b57cec5SDimitry Andric
warn(Error Err,Twine FileName,Twine Context=Twine (),Twine Archive=Twine ())14181ad6265SDimitry Andric static void warn(Error Err, Twine FileName, Twine Context = Twine(),
14281ad6265SDimitry Andric Twine Archive = Twine()) {
14304eeddc0SDimitry Andric assert(Err);
14404eeddc0SDimitry Andric
14504eeddc0SDimitry Andric // Flush the standard output so that the warning isn't interleaved with other
14604eeddc0SDimitry Andric // output if stdout and stderr are writing to the same place.
14704eeddc0SDimitry Andric outs().flush();
14804eeddc0SDimitry Andric
14904eeddc0SDimitry Andric handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
15004eeddc0SDimitry Andric WithColor::warning(errs(), ToolName)
15181ad6265SDimitry Andric << (Archive.str().empty() ? FileName : Archive + "(" + FileName + ")")
15281ad6265SDimitry Andric << ": " << (Context.str().empty() ? "" : Context + ": ") << EI.message()
15381ad6265SDimitry Andric << "\n";
15404eeddc0SDimitry Andric });
15504eeddc0SDimitry Andric }
15604eeddc0SDimitry Andric
error(Twine Message,Twine Path=Twine ())1570b57cec5SDimitry Andric static void error(Twine Message, Twine Path = Twine()) {
1580b57cec5SDimitry Andric HadError = true;
159fe6060f1SDimitry Andric WithColor::error(errs(), ToolName) << Path << ": " << Message << "\n";
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
error(std::error_code EC,Twine Path=Twine ())1620b57cec5SDimitry Andric static bool error(std::error_code EC, Twine Path = Twine()) {
1630b57cec5SDimitry Andric if (EC) {
1640b57cec5SDimitry Andric error(EC.message(), Path);
1650b57cec5SDimitry Andric return true;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric return false;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric // This version of error() prints the archive name and member name, for example:
1710b57cec5SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message. It sets
1720b57cec5SDimitry Andric // HadError but returns allowing the code to move on to other archive members.
error(llvm::Error E,StringRef FileName,const Archive::Child & C,StringRef ArchitectureName=StringRef ())1730b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
1740b57cec5SDimitry Andric StringRef ArchitectureName = StringRef()) {
1750b57cec5SDimitry Andric HadError = true;
1760b57cec5SDimitry Andric WithColor::error(errs(), ToolName) << FileName;
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric Expected<StringRef> NameOrErr = C.getName();
1790b57cec5SDimitry Andric // TODO: if we have a error getting the name then it would be nice to print
1800b57cec5SDimitry Andric // the index of which archive member this is and or its offset in the
1810b57cec5SDimitry Andric // archive instead of "???" as the name.
1820b57cec5SDimitry Andric if (!NameOrErr) {
1830b57cec5SDimitry Andric consumeError(NameOrErr.takeError());
1840b57cec5SDimitry Andric errs() << "(" << "???" << ")";
1850b57cec5SDimitry Andric } else
1860b57cec5SDimitry Andric errs() << "(" << NameOrErr.get() << ")";
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric if (!ArchitectureName.empty())
1890b57cec5SDimitry Andric errs() << " (for architecture " << ArchitectureName << ")";
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric std::string Buf;
1920b57cec5SDimitry Andric raw_string_ostream OS(Buf);
1930b57cec5SDimitry Andric logAllUnhandledErrors(std::move(E), OS);
1940b57cec5SDimitry Andric OS.flush();
195fe6060f1SDimitry Andric errs() << ": " << Buf << "\n";
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric // This version of error() prints the file name and which architecture slice it
1990b57cec5SDimitry Andric // is from, for example: "foo.o (for architecture i386)" after the ToolName
2000b57cec5SDimitry Andric // before the error message. It sets HadError but returns allowing the code to
2010b57cec5SDimitry Andric // move on to other architecture slices.
error(llvm::Error E,StringRef FileName,StringRef ArchitectureName=StringRef ())2020b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName,
2030b57cec5SDimitry Andric StringRef ArchitectureName = StringRef()) {
2040b57cec5SDimitry Andric HadError = true;
2050b57cec5SDimitry Andric WithColor::error(errs(), ToolName) << FileName;
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric if (!ArchitectureName.empty())
2080b57cec5SDimitry Andric errs() << " (for architecture " << ArchitectureName << ")";
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric std::string Buf;
2110b57cec5SDimitry Andric raw_string_ostream OS(Buf);
2120b57cec5SDimitry Andric logAllUnhandledErrors(std::move(E), OS);
2130b57cec5SDimitry Andric OS.flush();
214fe6060f1SDimitry Andric errs() << ": " << Buf << "\n";
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric namespace {
2180b57cec5SDimitry Andric struct NMSymbol {
2190b57cec5SDimitry Andric uint64_t Address;
2200b57cec5SDimitry Andric uint64_t Size;
2210b57cec5SDimitry Andric char TypeChar;
222e8d8bef9SDimitry Andric std::string Name;
2230b57cec5SDimitry Andric StringRef SectionName;
2240b57cec5SDimitry Andric StringRef TypeName;
2250b57cec5SDimitry Andric BasicSymbolRef Sym;
22681ad6265SDimitry Andric StringRef Visibility;
22781ad6265SDimitry Andric
2280b57cec5SDimitry Andric // The Sym field above points to the native symbol in the object file,
2290b57cec5SDimitry Andric // for Mach-O when we are creating symbols from the dyld info the above
2300b57cec5SDimitry Andric // pointer is null as there is no native symbol. In these cases the fields
2310b57cec5SDimitry Andric // below are filled in to represent what would have been a Mach-O nlist
2320b57cec5SDimitry Andric // native symbol.
2330b57cec5SDimitry Andric uint32_t SymFlags;
2340b57cec5SDimitry Andric SectionRef Section;
2350b57cec5SDimitry Andric uint8_t NType;
2360b57cec5SDimitry Andric uint8_t NSect;
2370b57cec5SDimitry Andric uint16_t NDesc;
238e8d8bef9SDimitry Andric std::string IndirectName;
23981ad6265SDimitry Andric
isDefined__anondb275fe70411::NMSymbol24081ad6265SDimitry Andric bool isDefined() const {
2415f757f3fSDimitry Andric if (Sym.getRawDataRefImpl().p)
2425f757f3fSDimitry Andric return !(SymFlags & SymbolRef::SF_Undefined);
24381ad6265SDimitry Andric return TypeChar != 'U';
24481ad6265SDimitry Andric }
24581ad6265SDimitry Andric
initializeFlags__anondb275fe70411::NMSymbol24681ad6265SDimitry Andric bool initializeFlags(const SymbolicFile &Obj) {
24781ad6265SDimitry Andric Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
24881ad6265SDimitry Andric if (!SymFlagsOrErr) {
24981ad6265SDimitry Andric // TODO: Test this error.
25081ad6265SDimitry Andric error(SymFlagsOrErr.takeError(), Obj.getFileName());
25181ad6265SDimitry Andric return false;
25281ad6265SDimitry Andric }
25381ad6265SDimitry Andric SymFlags = *SymFlagsOrErr;
25481ad6265SDimitry Andric return true;
25581ad6265SDimitry Andric }
25681ad6265SDimitry Andric
shouldPrint__anondb275fe70411::NMSymbol25781ad6265SDimitry Andric bool shouldPrint() const {
25881ad6265SDimitry Andric bool Undefined = SymFlags & SymbolRef::SF_Undefined;
25981ad6265SDimitry Andric bool Global = SymFlags & SymbolRef::SF_Global;
26081ad6265SDimitry Andric bool Weak = SymFlags & SymbolRef::SF_Weak;
26181ad6265SDimitry Andric bool FormatSpecific = SymFlags & SymbolRef::SF_FormatSpecific;
26281ad6265SDimitry Andric if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
26381ad6265SDimitry Andric (!Global && ExternalOnly) || (Weak && NoWeakSymbols) ||
26481ad6265SDimitry Andric (FormatSpecific && !(SpecialSyms || DebugSyms)))
26581ad6265SDimitry Andric return false;
26681ad6265SDimitry Andric return true;
26781ad6265SDimitry Andric }
2680b57cec5SDimitry Andric };
2690b57cec5SDimitry Andric
operator <(const NMSymbol & A,const NMSymbol & B)27081ad6265SDimitry Andric bool operator<(const NMSymbol &A, const NMSymbol &B) {
27181ad6265SDimitry Andric if (NumericSort)
27281ad6265SDimitry Andric return std::make_tuple(A.isDefined(), A.Address, A.Name, A.Size) <
27381ad6265SDimitry Andric std::make_tuple(B.isDefined(), B.Address, B.Name, B.Size);
27481ad6265SDimitry Andric if (SizeSort)
2750b57cec5SDimitry Andric return std::make_tuple(A.Size, A.Name, A.Address) <
2760b57cec5SDimitry Andric std::make_tuple(B.Size, B.Name, B.Address);
27781ad6265SDimitry Andric if (ExportSymbols)
27881ad6265SDimitry Andric return std::make_tuple(A.Name, A.Visibility) <
27981ad6265SDimitry Andric std::make_tuple(B.Name, B.Visibility);
2800b57cec5SDimitry Andric return std::make_tuple(A.Name, A.Size, A.Address) <
2810b57cec5SDimitry Andric std::make_tuple(B.Name, B.Size, B.Address);
2820b57cec5SDimitry Andric }
2830b57cec5SDimitry Andric
operator >(const NMSymbol & A,const NMSymbol & B)28481ad6265SDimitry Andric bool operator>(const NMSymbol &A, const NMSymbol &B) { return B < A; }
operator ==(const NMSymbol & A,const NMSymbol & B)28581ad6265SDimitry Andric bool operator==(const NMSymbol &A, const NMSymbol &B) {
28681ad6265SDimitry Andric return !(A < B) && !(B < A);
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric } // anonymous namespace
28981ad6265SDimitry Andric
2900b57cec5SDimitry Andric static StringRef CurrentFilename;
2910b57cec5SDimitry Andric
2920b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
2950b57cec5SDimitry Andric // the OutputFormat is darwin or we are printing Mach-O symbols in hex. For
2960b57cec5SDimitry Andric // the darwin format it produces the same output as darwin's nm(1) -m output
2970b57cec5SDimitry Andric // and when printing Mach-O symbols in hex it produces the same output as
2980b57cec5SDimitry Andric // darwin's nm(1) -x format.
darwinPrintSymbol(SymbolicFile & Obj,const NMSymbol & S,char * SymbolAddrStr,const char * printBlanks,const char * printDashes,const char * printFormat)2990b57cec5SDimitry Andric static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
3000b57cec5SDimitry Andric char *SymbolAddrStr, const char *printBlanks,
3010b57cec5SDimitry Andric const char *printDashes,
3020b57cec5SDimitry Andric const char *printFormat) {
3030b57cec5SDimitry Andric MachO::mach_header H;
3040b57cec5SDimitry Andric MachO::mach_header_64 H_64;
3050b57cec5SDimitry Andric uint32_t Filetype = MachO::MH_OBJECT;
3060b57cec5SDimitry Andric uint32_t Flags = 0;
3070b57cec5SDimitry Andric uint8_t NType = 0;
3080b57cec5SDimitry Andric uint8_t NSect = 0;
3090b57cec5SDimitry Andric uint16_t NDesc = 0;
3100b57cec5SDimitry Andric uint32_t NStrx = 0;
3110b57cec5SDimitry Andric uint64_t NValue = 0;
3120b57cec5SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
3130b57cec5SDimitry Andric if (Obj.isIR()) {
3145ffd83dbSDimitry Andric uint32_t SymFlags = cantFail(S.Sym.getFlags());
3150b57cec5SDimitry Andric if (SymFlags & SymbolRef::SF_Global)
3160b57cec5SDimitry Andric NType |= MachO::N_EXT;
3170b57cec5SDimitry Andric if (SymFlags & SymbolRef::SF_Hidden)
3180b57cec5SDimitry Andric NType |= MachO::N_PEXT;
3190b57cec5SDimitry Andric if (SymFlags & SymbolRef::SF_Undefined)
3200b57cec5SDimitry Andric NType |= MachO::N_EXT | MachO::N_UNDF;
3210b57cec5SDimitry Andric else {
3220b57cec5SDimitry Andric // Here we have a symbol definition. So to fake out a section name we
3230b57cec5SDimitry Andric // use 1, 2 and 3 for section numbers. See below where they are used to
3240b57cec5SDimitry Andric // print out fake section names.
3250b57cec5SDimitry Andric NType |= MachO::N_SECT;
3260b57cec5SDimitry Andric if (SymFlags & SymbolRef::SF_Const)
3270b57cec5SDimitry Andric NSect = 3;
3280b57cec5SDimitry Andric else if (SymFlags & SymbolRef::SF_Executable)
3290b57cec5SDimitry Andric NSect = 1;
3300b57cec5SDimitry Andric else
3310b57cec5SDimitry Andric NSect = 2;
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric if (SymFlags & SymbolRef::SF_Weak)
3340b57cec5SDimitry Andric NDesc |= MachO::N_WEAK_DEF;
3350b57cec5SDimitry Andric } else {
3360b57cec5SDimitry Andric DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
3370b57cec5SDimitry Andric if (MachO->is64Bit()) {
3380b57cec5SDimitry Andric H_64 = MachO->MachOObjectFile::getHeader64();
3390b57cec5SDimitry Andric Filetype = H_64.filetype;
3400b57cec5SDimitry Andric Flags = H_64.flags;
3410b57cec5SDimitry Andric if (SymDRI.p){
3420b57cec5SDimitry Andric MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
3430b57cec5SDimitry Andric NType = STE_64.n_type;
3440b57cec5SDimitry Andric NSect = STE_64.n_sect;
3450b57cec5SDimitry Andric NDesc = STE_64.n_desc;
3460b57cec5SDimitry Andric NStrx = STE_64.n_strx;
3470b57cec5SDimitry Andric NValue = STE_64.n_value;
3480b57cec5SDimitry Andric } else {
3490b57cec5SDimitry Andric NType = S.NType;
3500b57cec5SDimitry Andric NSect = S.NSect;
3510b57cec5SDimitry Andric NDesc = S.NDesc;
3520b57cec5SDimitry Andric NStrx = 0;
3530b57cec5SDimitry Andric NValue = S.Address;
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric } else {
3560b57cec5SDimitry Andric H = MachO->MachOObjectFile::getHeader();
3570b57cec5SDimitry Andric Filetype = H.filetype;
3580b57cec5SDimitry Andric Flags = H.flags;
3590b57cec5SDimitry Andric if (SymDRI.p){
3600b57cec5SDimitry Andric MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
3610b57cec5SDimitry Andric NType = STE.n_type;
3620b57cec5SDimitry Andric NSect = STE.n_sect;
3630b57cec5SDimitry Andric NDesc = STE.n_desc;
3640b57cec5SDimitry Andric NStrx = STE.n_strx;
3650b57cec5SDimitry Andric NValue = STE.n_value;
3660b57cec5SDimitry Andric } else {
3670b57cec5SDimitry Andric NType = S.NType;
3680b57cec5SDimitry Andric NSect = S.NSect;
3690b57cec5SDimitry Andric NDesc = S.NDesc;
3700b57cec5SDimitry Andric NStrx = 0;
3710b57cec5SDimitry Andric NValue = S.Address;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric }
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric
3760b57cec5SDimitry Andric // If we are printing Mach-O symbols in hex do that and return.
3770b57cec5SDimitry Andric if (FormatMachOasHex) {
3780b57cec5SDimitry Andric outs() << format(printFormat, NValue) << ' '
3790b57cec5SDimitry Andric << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
3800b57cec5SDimitry Andric << S.Name;
3810b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
3820b57cec5SDimitry Andric outs() << " (indirect for ";
3830b57cec5SDimitry Andric outs() << format(printFormat, NValue) << ' ';
3840b57cec5SDimitry Andric StringRef IndirectName;
3850b57cec5SDimitry Andric if (S.Sym.getRawDataRefImpl().p) {
3860b57cec5SDimitry Andric if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
3870b57cec5SDimitry Andric outs() << "?)";
3880b57cec5SDimitry Andric else
3890b57cec5SDimitry Andric outs() << IndirectName << ")";
3900b57cec5SDimitry Andric } else
3910b57cec5SDimitry Andric outs() << S.IndirectName << ")";
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric outs() << "\n";
3940b57cec5SDimitry Andric return;
3950b57cec5SDimitry Andric }
3960b57cec5SDimitry Andric
3970b57cec5SDimitry Andric if (PrintAddress) {
3980b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) == MachO::N_INDR)
3990b57cec5SDimitry Andric strcpy(SymbolAddrStr, printBlanks);
4000b57cec5SDimitry Andric if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE)
4010b57cec5SDimitry Andric strcpy(SymbolAddrStr, printDashes);
4020b57cec5SDimitry Andric outs() << SymbolAddrStr << ' ';
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric switch (NType & MachO::N_TYPE) {
4060b57cec5SDimitry Andric case MachO::N_UNDF:
4070b57cec5SDimitry Andric if (NValue != 0) {
4080b57cec5SDimitry Andric outs() << "(common) ";
4090b57cec5SDimitry Andric if (MachO::GET_COMM_ALIGN(NDesc) != 0)
4100b57cec5SDimitry Andric outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") ";
4110b57cec5SDimitry Andric } else {
4120b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) == MachO::N_PBUD)
4130b57cec5SDimitry Andric outs() << "(prebound ";
4140b57cec5SDimitry Andric else
4150b57cec5SDimitry Andric outs() << "(";
4160b57cec5SDimitry Andric if ((NDesc & MachO::REFERENCE_TYPE) ==
4170b57cec5SDimitry Andric MachO::REFERENCE_FLAG_UNDEFINED_LAZY)
4180b57cec5SDimitry Andric outs() << "undefined [lazy bound]) ";
4190b57cec5SDimitry Andric else if ((NDesc & MachO::REFERENCE_TYPE) ==
4200b57cec5SDimitry Andric MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
4210b57cec5SDimitry Andric outs() << "undefined [private lazy bound]) ";
4220b57cec5SDimitry Andric else if ((NDesc & MachO::REFERENCE_TYPE) ==
4230b57cec5SDimitry Andric MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
4240b57cec5SDimitry Andric outs() << "undefined [private]) ";
4250b57cec5SDimitry Andric else
4260b57cec5SDimitry Andric outs() << "undefined) ";
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric break;
4290b57cec5SDimitry Andric case MachO::N_ABS:
4300b57cec5SDimitry Andric outs() << "(absolute) ";
4310b57cec5SDimitry Andric break;
4320b57cec5SDimitry Andric case MachO::N_INDR:
4330b57cec5SDimitry Andric outs() << "(indirect) ";
4340b57cec5SDimitry Andric break;
4350b57cec5SDimitry Andric case MachO::N_SECT: {
4360b57cec5SDimitry Andric if (Obj.isIR()) {
4370b57cec5SDimitry Andric // For llvm bitcode files print out a fake section name using the values
4380b57cec5SDimitry Andric // use 1, 2 and 3 for section numbers as set above.
4390b57cec5SDimitry Andric if (NSect == 1)
4400b57cec5SDimitry Andric outs() << "(LTO,CODE) ";
4410b57cec5SDimitry Andric else if (NSect == 2)
4420b57cec5SDimitry Andric outs() << "(LTO,DATA) ";
4430b57cec5SDimitry Andric else if (NSect == 3)
4440b57cec5SDimitry Andric outs() << "(LTO,RODATA) ";
4450b57cec5SDimitry Andric else
4460b57cec5SDimitry Andric outs() << "(?,?) ";
4470b57cec5SDimitry Andric break;
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric section_iterator Sec = SectionRef();
4500b57cec5SDimitry Andric if (S.Sym.getRawDataRefImpl().p) {
4510b57cec5SDimitry Andric Expected<section_iterator> SecOrErr =
4520b57cec5SDimitry Andric MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
4530b57cec5SDimitry Andric if (!SecOrErr) {
4540b57cec5SDimitry Andric consumeError(SecOrErr.takeError());
4550b57cec5SDimitry Andric outs() << "(?,?) ";
4560b57cec5SDimitry Andric break;
4570b57cec5SDimitry Andric }
4580b57cec5SDimitry Andric Sec = *SecOrErr;
4590b57cec5SDimitry Andric if (Sec == MachO->section_end()) {
4600b57cec5SDimitry Andric outs() << "(?,?) ";
4610b57cec5SDimitry Andric break;
4620b57cec5SDimitry Andric }
4630b57cec5SDimitry Andric } else {
4640b57cec5SDimitry Andric Sec = S.Section;
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric DataRefImpl Ref = Sec->getRawDataRefImpl();
4670b57cec5SDimitry Andric StringRef SectionName;
4680b57cec5SDimitry Andric if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
4690b57cec5SDimitry Andric SectionName = *NameOrErr;
4700b57cec5SDimitry Andric StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
4710b57cec5SDimitry Andric outs() << "(" << SegmentName << "," << SectionName << ") ";
4720b57cec5SDimitry Andric break;
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric default:
4750b57cec5SDimitry Andric outs() << "(?) ";
4760b57cec5SDimitry Andric break;
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andric if (NType & MachO::N_EXT) {
4800b57cec5SDimitry Andric if (NDesc & MachO::REFERENCED_DYNAMICALLY)
4810b57cec5SDimitry Andric outs() << "[referenced dynamically] ";
4820b57cec5SDimitry Andric if (NType & MachO::N_PEXT) {
4830b57cec5SDimitry Andric if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF)
4840b57cec5SDimitry Andric outs() << "weak private external ";
4850b57cec5SDimitry Andric else
4860b57cec5SDimitry Andric outs() << "private external ";
4870b57cec5SDimitry Andric } else {
4880b57cec5SDimitry Andric if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF ||
4890b57cec5SDimitry Andric (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) {
4900b57cec5SDimitry Andric if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) ==
4910b57cec5SDimitry Andric (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
4920b57cec5SDimitry Andric outs() << "weak external automatically hidden ";
4930b57cec5SDimitry Andric else
4940b57cec5SDimitry Andric outs() << "weak external ";
4950b57cec5SDimitry Andric } else
4960b57cec5SDimitry Andric outs() << "external ";
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric } else {
4990b57cec5SDimitry Andric if (NType & MachO::N_PEXT)
5000b57cec5SDimitry Andric outs() << "non-external (was a private external) ";
5010b57cec5SDimitry Andric else
5020b57cec5SDimitry Andric outs() << "non-external ";
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric if (Filetype == MachO::MH_OBJECT) {
5060b57cec5SDimitry Andric if (NDesc & MachO::N_NO_DEAD_STRIP)
5070b57cec5SDimitry Andric outs() << "[no dead strip] ";
5080b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
5090b57cec5SDimitry Andric NDesc & MachO::N_SYMBOL_RESOLVER)
5100b57cec5SDimitry Andric outs() << "[symbol resolver] ";
5110b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
5120b57cec5SDimitry Andric outs() << "[alt entry] ";
5130b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
5140b57cec5SDimitry Andric outs() << "[cold func] ";
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric
5170b57cec5SDimitry Andric if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
5180b57cec5SDimitry Andric outs() << "[Thumb] ";
5190b57cec5SDimitry Andric
5200b57cec5SDimitry Andric if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
5210b57cec5SDimitry Andric outs() << S.Name << " (for ";
5220b57cec5SDimitry Andric StringRef IndirectName;
5230b57cec5SDimitry Andric if (MachO) {
5240b57cec5SDimitry Andric if (S.Sym.getRawDataRefImpl().p) {
5250b57cec5SDimitry Andric if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
5260b57cec5SDimitry Andric outs() << "?)";
5270b57cec5SDimitry Andric else
5280b57cec5SDimitry Andric outs() << IndirectName << ")";
5290b57cec5SDimitry Andric } else
5300b57cec5SDimitry Andric outs() << S.IndirectName << ")";
5310b57cec5SDimitry Andric } else
5320b57cec5SDimitry Andric outs() << "?)";
5330b57cec5SDimitry Andric } else
5340b57cec5SDimitry Andric outs() << S.Name;
5350b57cec5SDimitry Andric
5360b57cec5SDimitry Andric if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
5370b57cec5SDimitry Andric (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
5380b57cec5SDimitry Andric (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
5390b57cec5SDimitry Andric uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
5400b57cec5SDimitry Andric if (LibraryOrdinal != 0) {
5410b57cec5SDimitry Andric if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL)
5420b57cec5SDimitry Andric outs() << " (from executable)";
5430b57cec5SDimitry Andric else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL)
5440b57cec5SDimitry Andric outs() << " (dynamically looked up)";
5450b57cec5SDimitry Andric else {
5460b57cec5SDimitry Andric StringRef LibraryName;
5470b57cec5SDimitry Andric if (!MachO ||
5480b57cec5SDimitry Andric MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName))
5490b57cec5SDimitry Andric outs() << " (from bad library ordinal " << LibraryOrdinal << ")";
5500b57cec5SDimitry Andric else
5510b57cec5SDimitry Andric outs() << " (from " << LibraryName << ")";
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
5570b57cec5SDimitry Andric // Table that maps Darwin's Mach-O stab constants to strings to allow printing.
5580b57cec5SDimitry Andric struct DarwinStabName {
5590b57cec5SDimitry Andric uint8_t NType;
5600b57cec5SDimitry Andric const char *Name;
5610b57cec5SDimitry Andric };
562349cc55cSDimitry Andric const struct DarwinStabName DarwinStabNames[] = {
5635f757f3fSDimitry Andric {MachO::N_GSYM, "GSYM"}, {MachO::N_FNAME, "FNAME"},
5645f757f3fSDimitry Andric {MachO::N_FUN, "FUN"}, {MachO::N_STSYM, "STSYM"},
5655f757f3fSDimitry Andric {MachO::N_LCSYM, "LCSYM"}, {MachO::N_BNSYM, "BNSYM"},
5665f757f3fSDimitry Andric {MachO::N_PC, "PC"}, {MachO::N_AST, "AST"},
5675f757f3fSDimitry Andric {MachO::N_OPT, "OPT"}, {MachO::N_RSYM, "RSYM"},
5685f757f3fSDimitry Andric {MachO::N_SLINE, "SLINE"}, {MachO::N_ENSYM, "ENSYM"},
5695f757f3fSDimitry Andric {MachO::N_SSYM, "SSYM"}, {MachO::N_SO, "SO"},
5705f757f3fSDimitry Andric {MachO::N_OSO, "OSO"}, {MachO::N_LIB, "LIB"},
5715f757f3fSDimitry Andric {MachO::N_LSYM, "LSYM"}, {MachO::N_BINCL, "BINCL"},
5725f757f3fSDimitry Andric {MachO::N_SOL, "SOL"}, {MachO::N_PARAMS, "PARAM"},
5735f757f3fSDimitry Andric {MachO::N_VERSION, "VERS"}, {MachO::N_OLEVEL, "OLEV"},
5745f757f3fSDimitry Andric {MachO::N_PSYM, "PSYM"}, {MachO::N_EINCL, "EINCL"},
5755f757f3fSDimitry Andric {MachO::N_ENTRY, "ENTRY"}, {MachO::N_LBRAC, "LBRAC"},
5765f757f3fSDimitry Andric {MachO::N_EXCL, "EXCL"}, {MachO::N_RBRAC, "RBRAC"},
5775f757f3fSDimitry Andric {MachO::N_BCOMM, "BCOMM"}, {MachO::N_ECOMM, "ECOMM"},
5785f757f3fSDimitry Andric {MachO::N_ECOML, "ECOML"}, {MachO::N_LENG, "LENG"},
5790b57cec5SDimitry Andric };
5800b57cec5SDimitry Andric
getDarwinStabString(uint8_t NType)5810b57cec5SDimitry Andric static const char *getDarwinStabString(uint8_t NType) {
582bdd1243dSDimitry Andric for (auto I : ArrayRef(DarwinStabNames))
5830b57cec5SDimitry Andric if (I.NType == NType)
5840b57cec5SDimitry Andric return I.Name;
5850b57cec5SDimitry Andric return nullptr;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
5890b57cec5SDimitry Andric // a stab n_type value in a Mach-O file.
darwinPrintStab(MachOObjectFile * MachO,const NMSymbol & S)5900b57cec5SDimitry Andric static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
5910b57cec5SDimitry Andric MachO::nlist_64 STE_64;
5920b57cec5SDimitry Andric MachO::nlist STE;
5930b57cec5SDimitry Andric uint8_t NType;
5940b57cec5SDimitry Andric uint8_t NSect;
5950b57cec5SDimitry Andric uint16_t NDesc;
5960b57cec5SDimitry Andric DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
5970b57cec5SDimitry Andric if (MachO->is64Bit()) {
5980b57cec5SDimitry Andric STE_64 = MachO->getSymbol64TableEntry(SymDRI);
5990b57cec5SDimitry Andric NType = STE_64.n_type;
6000b57cec5SDimitry Andric NSect = STE_64.n_sect;
6010b57cec5SDimitry Andric NDesc = STE_64.n_desc;
6020b57cec5SDimitry Andric } else {
6030b57cec5SDimitry Andric STE = MachO->getSymbolTableEntry(SymDRI);
6040b57cec5SDimitry Andric NType = STE.n_type;
6050b57cec5SDimitry Andric NSect = STE.n_sect;
6060b57cec5SDimitry Andric NDesc = STE.n_desc;
6070b57cec5SDimitry Andric }
6080b57cec5SDimitry Andric
6090b57cec5SDimitry Andric outs() << format(" %02x %04x ", NSect, NDesc);
6100b57cec5SDimitry Andric if (const char *stabString = getDarwinStabString(NType))
6110b57cec5SDimitry Andric outs() << format("%5.5s", stabString);
6120b57cec5SDimitry Andric else
6130b57cec5SDimitry Andric outs() << format(" %02x", NType);
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric
symbolIsDefined(const NMSymbol & Sym)6160b57cec5SDimitry Andric static bool symbolIsDefined(const NMSymbol &Sym) {
6170b57cec5SDimitry Andric return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric
writeFileName(raw_ostream & S,StringRef ArchiveName,StringRef ArchitectureName)6205ffd83dbSDimitry Andric static void writeFileName(raw_ostream &S, StringRef ArchiveName,
6215ffd83dbSDimitry Andric StringRef ArchitectureName) {
6225ffd83dbSDimitry Andric if (!ArchitectureName.empty())
6235ffd83dbSDimitry Andric S << "(for architecture " << ArchitectureName << "):";
6245ffd83dbSDimitry Andric if (OutputFormat == posix && !ArchiveName.empty())
6255ffd83dbSDimitry Andric S << ArchiveName << "[" << CurrentFilename << "]: ";
6265ffd83dbSDimitry Andric else {
6275ffd83dbSDimitry Andric if (!ArchiveName.empty())
6285ffd83dbSDimitry Andric S << ArchiveName << ":";
6295ffd83dbSDimitry Andric S << CurrentFilename << ": ";
6305ffd83dbSDimitry Andric }
6315ffd83dbSDimitry Andric }
6325ffd83dbSDimitry Andric
sortSymbolList(std::vector<NMSymbol> & SymbolList)63381ad6265SDimitry Andric static void sortSymbolList(std::vector<NMSymbol> &SymbolList) {
63481ad6265SDimitry Andric if (NoSort)
63581ad6265SDimitry Andric return;
6360b57cec5SDimitry Andric
6370b57cec5SDimitry Andric if (ReverseSort)
63881ad6265SDimitry Andric llvm::sort(SymbolList, std::greater<>());
6398bcb0991SDimitry Andric else
64081ad6265SDimitry Andric llvm::sort(SymbolList);
6410b57cec5SDimitry Andric }
6420b57cec5SDimitry Andric
printExportSymbolList(const std::vector<NMSymbol> & SymbolList)64381ad6265SDimitry Andric static void printExportSymbolList(const std::vector<NMSymbol> &SymbolList) {
64481ad6265SDimitry Andric for (const NMSymbol &Sym : SymbolList) {
64581ad6265SDimitry Andric outs() << Sym.Name;
64681ad6265SDimitry Andric if (!Sym.Visibility.empty())
64781ad6265SDimitry Andric outs() << ' ' << Sym.Visibility;
64881ad6265SDimitry Andric outs() << '\n';
64981ad6265SDimitry Andric }
65081ad6265SDimitry Andric }
65181ad6265SDimitry Andric
printLineNumbers(symbolize::LLVMSymbolizer & Symbolizer,const NMSymbol & S)6525f757f3fSDimitry Andric static void printLineNumbers(symbolize::LLVMSymbolizer &Symbolizer,
6535f757f3fSDimitry Andric const NMSymbol &S) {
6545f757f3fSDimitry Andric const auto *Obj = dyn_cast<ObjectFile>(S.Sym.getObject());
6555f757f3fSDimitry Andric if (!Obj)
6565f757f3fSDimitry Andric return;
6575f757f3fSDimitry Andric const SymbolRef Sym(S.Sym);
6585f757f3fSDimitry Andric uint64_t SectionIndex = object::SectionedAddress::UndefSection;
6595f757f3fSDimitry Andric section_iterator Sec = cantFail(Sym.getSection());
6605f757f3fSDimitry Andric if (Sec != Obj->section_end())
6615f757f3fSDimitry Andric SectionIndex = Sec->getIndex();
6625f757f3fSDimitry Andric object::SectionedAddress Address = {cantFail(Sym.getAddress()), SectionIndex};
6635f757f3fSDimitry Andric
6645f757f3fSDimitry Andric std::string FileName;
6655f757f3fSDimitry Andric uint32_t Line;
6665f757f3fSDimitry Andric switch (S.TypeChar) {
6675f757f3fSDimitry Andric // For undefined symbols, find the first relocation for that symbol with a
6685f757f3fSDimitry Andric // line number.
6695f757f3fSDimitry Andric case 'U': {
6705f757f3fSDimitry Andric for (const SectionRef RelocsSec : Obj->sections()) {
6715f757f3fSDimitry Andric if (RelocsSec.relocations().empty())
6725f757f3fSDimitry Andric continue;
6735f757f3fSDimitry Andric SectionRef TextSec = *cantFail(RelocsSec.getRelocatedSection());
6745f757f3fSDimitry Andric if (!TextSec.isText())
6755f757f3fSDimitry Andric continue;
6765f757f3fSDimitry Andric for (const RelocationRef R : RelocsSec.relocations()) {
6775f757f3fSDimitry Andric if (R.getSymbol() != Sym)
6785f757f3fSDimitry Andric continue;
6795f757f3fSDimitry Andric Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(
6805f757f3fSDimitry Andric *Obj, {TextSec.getAddress() + R.getOffset(), SectionIndex});
6815f757f3fSDimitry Andric if (!ResOrErr) {
6825f757f3fSDimitry Andric error(ResOrErr.takeError(), Obj->getFileName());
6835f757f3fSDimitry Andric return;
6845f757f3fSDimitry Andric }
6855f757f3fSDimitry Andric if (ResOrErr->FileName == DILineInfo::BadString)
6865f757f3fSDimitry Andric return;
6875f757f3fSDimitry Andric FileName = std::move(ResOrErr->FileName);
6885f757f3fSDimitry Andric Line = ResOrErr->Line;
6895f757f3fSDimitry Andric break;
6905f757f3fSDimitry Andric }
6915f757f3fSDimitry Andric if (!FileName.empty())
6925f757f3fSDimitry Andric break;
6935f757f3fSDimitry Andric }
6945f757f3fSDimitry Andric if (FileName.empty())
6955f757f3fSDimitry Andric return;
6965f757f3fSDimitry Andric break;
6975f757f3fSDimitry Andric }
6985f757f3fSDimitry Andric case 't':
6995f757f3fSDimitry Andric case 'T': {
7005f757f3fSDimitry Andric Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(*Obj, Address);
7015f757f3fSDimitry Andric if (!ResOrErr) {
7025f757f3fSDimitry Andric error(ResOrErr.takeError(), Obj->getFileName());
7035f757f3fSDimitry Andric return;
7045f757f3fSDimitry Andric }
7055f757f3fSDimitry Andric if (ResOrErr->FileName == DILineInfo::BadString)
7065f757f3fSDimitry Andric return;
7075f757f3fSDimitry Andric FileName = std::move(ResOrErr->FileName);
7085f757f3fSDimitry Andric Line = ResOrErr->Line;
7095f757f3fSDimitry Andric break;
7105f757f3fSDimitry Andric }
7115f757f3fSDimitry Andric default: {
7125f757f3fSDimitry Andric Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(*Obj, Address);
7135f757f3fSDimitry Andric if (!ResOrErr) {
7145f757f3fSDimitry Andric error(ResOrErr.takeError(), Obj->getFileName());
7155f757f3fSDimitry Andric return;
7165f757f3fSDimitry Andric }
7175f757f3fSDimitry Andric if (ResOrErr->DeclFile.empty())
7185f757f3fSDimitry Andric return;
7195f757f3fSDimitry Andric FileName = std::move(ResOrErr->DeclFile);
7205f757f3fSDimitry Andric Line = ResOrErr->DeclLine;
7215f757f3fSDimitry Andric break;
7225f757f3fSDimitry Andric }
7235f757f3fSDimitry Andric }
7245f757f3fSDimitry Andric outs() << '\t' << FileName << ':' << Line;
7255f757f3fSDimitry Andric }
7265f757f3fSDimitry Andric
printSymbolList(SymbolicFile & Obj,std::vector<NMSymbol> & SymbolList,bool printName,StringRef ArchiveName,StringRef ArchitectureName)72781ad6265SDimitry Andric static void printSymbolList(SymbolicFile &Obj,
72881ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList, bool printName,
72981ad6265SDimitry Andric StringRef ArchiveName, StringRef ArchitectureName) {
7305f757f3fSDimitry Andric std::optional<symbolize::LLVMSymbolizer> Symbolizer;
7315f757f3fSDimitry Andric if (LineNumbers)
7325f757f3fSDimitry Andric Symbolizer.emplace();
7335f757f3fSDimitry Andric
7340b57cec5SDimitry Andric if (!PrintFileName) {
735fe6060f1SDimitry Andric if ((OutputFormat == bsd || OutputFormat == posix ||
736fe6060f1SDimitry Andric OutputFormat == just_symbols) &&
737fe6060f1SDimitry Andric MultipleFiles && printName) {
7380b57cec5SDimitry Andric outs() << '\n' << CurrentFilename << ":\n";
7390b57cec5SDimitry Andric } else if (OutputFormat == sysv) {
7400b57cec5SDimitry Andric outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n";
74106c3fb27SDimitry Andric if (Obj.is64Bit())
7420b57cec5SDimitry Andric outs() << "Name Value Class Type"
7430b57cec5SDimitry Andric << " Size Line Section\n";
7440b57cec5SDimitry Andric else
7450b57cec5SDimitry Andric outs() << "Name Value Class Type"
7460b57cec5SDimitry Andric << " Size Line Section\n";
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric }
7490b57cec5SDimitry Andric
7500b57cec5SDimitry Andric const char *printBlanks, *printDashes, *printFormat;
75106c3fb27SDimitry Andric if (Obj.is64Bit()) {
7520b57cec5SDimitry Andric printBlanks = " ";
7530b57cec5SDimitry Andric printDashes = "----------------";
7540b57cec5SDimitry Andric switch (AddressRadix) {
7550b57cec5SDimitry Andric case Radix::o:
7560b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64;
7570b57cec5SDimitry Andric break;
7580b57cec5SDimitry Andric case Radix::x:
7590b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64;
7600b57cec5SDimitry Andric break;
7610b57cec5SDimitry Andric default:
7620b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64;
7630b57cec5SDimitry Andric }
7640b57cec5SDimitry Andric } else {
7650b57cec5SDimitry Andric printBlanks = " ";
7660b57cec5SDimitry Andric printDashes = "--------";
7670b57cec5SDimitry Andric switch (AddressRadix) {
7680b57cec5SDimitry Andric case Radix::o:
7690b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64;
7700b57cec5SDimitry Andric break;
7710b57cec5SDimitry Andric case Radix::x:
7720b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64;
7730b57cec5SDimitry Andric break;
7740b57cec5SDimitry Andric default:
7750b57cec5SDimitry Andric printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64;
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric for (const NMSymbol &S : SymbolList) {
78081ad6265SDimitry Andric if (!S.shouldPrint())
78181ad6265SDimitry Andric continue;
78281ad6265SDimitry Andric
783e8d8bef9SDimitry Andric std::string Name = S.Name;
7840b57cec5SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
7855f757f3fSDimitry Andric if (Demangle)
7865f757f3fSDimitry Andric Name = demangle(Name);
7870b57cec5SDimitry Andric
7880b57cec5SDimitry Andric if (PrintFileName)
7895ffd83dbSDimitry Andric writeFileName(outs(), ArchiveName, ArchitectureName);
790fe6060f1SDimitry Andric if ((OutputFormat == just_symbols ||
7910b57cec5SDimitry Andric (UndefinedOnly && MachO && OutputFormat != darwin)) &&
7920b57cec5SDimitry Andric OutputFormat != posix) {
7930b57cec5SDimitry Andric outs() << Name << "\n";
7940b57cec5SDimitry Andric continue;
7950b57cec5SDimitry Andric }
7960b57cec5SDimitry Andric
7970b57cec5SDimitry Andric char SymbolAddrStr[23], SymbolSizeStr[23];
7980b57cec5SDimitry Andric
7990b57cec5SDimitry Andric // If the format is SysV or the symbol isn't defined, then print spaces.
8000b57cec5SDimitry Andric if (OutputFormat == sysv || !symbolIsDefined(S)) {
8010b57cec5SDimitry Andric if (OutputFormat == posix) {
8020b57cec5SDimitry Andric format(printFormat, S.Address)
8030b57cec5SDimitry Andric .print(SymbolAddrStr, sizeof(SymbolAddrStr));
8040b57cec5SDimitry Andric format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
8050b57cec5SDimitry Andric } else {
8060b57cec5SDimitry Andric strcpy(SymbolAddrStr, printBlanks);
8070b57cec5SDimitry Andric strcpy(SymbolSizeStr, printBlanks);
8080b57cec5SDimitry Andric }
8090b57cec5SDimitry Andric }
8100b57cec5SDimitry Andric
8110b57cec5SDimitry Andric if (symbolIsDefined(S)) {
8120b57cec5SDimitry Andric // Otherwise, print the symbol address and size.
8130b57cec5SDimitry Andric if (Obj.isIR())
8140b57cec5SDimitry Andric strcpy(SymbolAddrStr, printDashes);
8150b57cec5SDimitry Andric else if (MachO && S.TypeChar == 'I')
8160b57cec5SDimitry Andric strcpy(SymbolAddrStr, printBlanks);
8170b57cec5SDimitry Andric else
8180b57cec5SDimitry Andric format(printFormat, S.Address)
8190b57cec5SDimitry Andric .print(SymbolAddrStr, sizeof(SymbolAddrStr));
8200b57cec5SDimitry Andric format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric
8230b57cec5SDimitry Andric // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
8240b57cec5SDimitry Andric // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
8250b57cec5SDimitry Andric // nm(1) -m output or hex, else if OutputFormat is darwin or we are
8260b57cec5SDimitry Andric // printing Mach-O symbols in hex and not a Mach-O object fall back to
8270b57cec5SDimitry Andric // OutputFormat bsd (see below).
8280b57cec5SDimitry Andric if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
8290b57cec5SDimitry Andric darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
8300b57cec5SDimitry Andric printFormat);
8310b57cec5SDimitry Andric } else if (OutputFormat == posix) {
8320b57cec5SDimitry Andric outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
8335f757f3fSDimitry Andric << (MachO ? "0" : SymbolSizeStr);
8340b57cec5SDimitry Andric } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
8350b57cec5SDimitry Andric if (PrintAddress)
8360b57cec5SDimitry Andric outs() << SymbolAddrStr << ' ';
8370b57cec5SDimitry Andric if (PrintSize)
8380b57cec5SDimitry Andric outs() << SymbolSizeStr << ' ';
8390b57cec5SDimitry Andric outs() << S.TypeChar;
8400b57cec5SDimitry Andric if (S.TypeChar == '-' && MachO)
8410b57cec5SDimitry Andric darwinPrintStab(MachO, S);
8420b57cec5SDimitry Andric outs() << " " << Name;
8430b57cec5SDimitry Andric if (S.TypeChar == 'I' && MachO) {
8440b57cec5SDimitry Andric outs() << " (indirect for ";
8450b57cec5SDimitry Andric if (S.Sym.getRawDataRefImpl().p) {
8460b57cec5SDimitry Andric StringRef IndirectName;
8470b57cec5SDimitry Andric if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
8480b57cec5SDimitry Andric outs() << "?)";
8490b57cec5SDimitry Andric else
8500b57cec5SDimitry Andric outs() << IndirectName << ")";
8510b57cec5SDimitry Andric } else
8520b57cec5SDimitry Andric outs() << S.IndirectName << ")";
8530b57cec5SDimitry Andric }
8540b57cec5SDimitry Andric } else if (OutputFormat == sysv) {
8550b57cec5SDimitry Andric outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
8560b57cec5SDimitry Andric << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
8575f757f3fSDimitry Andric << SymbolSizeStr << "| |" << S.SectionName;
8580b57cec5SDimitry Andric }
8595f757f3fSDimitry Andric if (LineNumbers)
8605f757f3fSDimitry Andric printLineNumbers(*Symbolizer, S);
8615f757f3fSDimitry Andric outs() << '\n';
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric
8640b57cec5SDimitry Andric SymbolList.clear();
8650b57cec5SDimitry Andric }
8660b57cec5SDimitry Andric
getSymbolNMTypeChar(ELFObjectFileBase & Obj,basic_symbol_iterator I)8670b57cec5SDimitry Andric static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
8680b57cec5SDimitry Andric basic_symbol_iterator I) {
8690b57cec5SDimitry Andric // OK, this is ELF
8700b57cec5SDimitry Andric elf_symbol_iterator SymI(I);
8710b57cec5SDimitry Andric
8720b57cec5SDimitry Andric Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
8730b57cec5SDimitry Andric if (!SecIOrErr) {
8740b57cec5SDimitry Andric consumeError(SecIOrErr.takeError());
8750b57cec5SDimitry Andric return '?';
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric
8780b57cec5SDimitry Andric uint8_t Binding = SymI->getBinding();
8790b57cec5SDimitry Andric if (Binding == ELF::STB_GNU_UNIQUE)
8800b57cec5SDimitry Andric return 'u';
8810b57cec5SDimitry Andric
8820b57cec5SDimitry Andric assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
8830b57cec5SDimitry Andric if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
8840b57cec5SDimitry Andric return '?';
8850b57cec5SDimitry Andric
8860b57cec5SDimitry Andric elf_section_iterator SecI = *SecIOrErr;
8870b57cec5SDimitry Andric if (SecI != Obj.section_end()) {
8880b57cec5SDimitry Andric uint32_t Type = SecI->getType();
8890b57cec5SDimitry Andric uint64_t Flags = SecI->getFlags();
8900b57cec5SDimitry Andric if (Flags & ELF::SHF_EXECINSTR)
8910b57cec5SDimitry Andric return 't';
8920b57cec5SDimitry Andric if (Type == ELF::SHT_NOBITS)
8930b57cec5SDimitry Andric return 'b';
8940b57cec5SDimitry Andric if (Flags & ELF::SHF_ALLOC)
8950b57cec5SDimitry Andric return Flags & ELF::SHF_WRITE ? 'd' : 'r';
8960b57cec5SDimitry Andric
8978bcb0991SDimitry Andric auto NameOrErr = SecI->getName();
8988bcb0991SDimitry Andric if (!NameOrErr) {
8998bcb0991SDimitry Andric consumeError(NameOrErr.takeError());
9000b57cec5SDimitry Andric return '?';
9018bcb0991SDimitry Andric }
9025f757f3fSDimitry Andric if ((*NameOrErr).starts_with(".debug"))
9030b57cec5SDimitry Andric return 'N';
9040b57cec5SDimitry Andric if (!(Flags & ELF::SHF_WRITE))
9050b57cec5SDimitry Andric return 'n';
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric
9080b57cec5SDimitry Andric return '?';
9090b57cec5SDimitry Andric }
9100b57cec5SDimitry Andric
getSymbolNMTypeChar(COFFObjectFile & Obj,symbol_iterator I)9110b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
9120b57cec5SDimitry Andric COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
9130b57cec5SDimitry Andric // OK, this is COFF.
9140b57cec5SDimitry Andric symbol_iterator SymI(I);
9150b57cec5SDimitry Andric
9160b57cec5SDimitry Andric Expected<StringRef> Name = SymI->getName();
9170b57cec5SDimitry Andric if (!Name) {
9180b57cec5SDimitry Andric consumeError(Name.takeError());
9190b57cec5SDimitry Andric return '?';
9200b57cec5SDimitry Andric }
9210b57cec5SDimitry Andric
9220b57cec5SDimitry Andric char Ret = StringSwitch<char>(*Name)
9230b57cec5SDimitry Andric .StartsWith(".debug", 'N')
9240b57cec5SDimitry Andric .StartsWith(".sxdata", 'N')
9250b57cec5SDimitry Andric .Default('?');
9260b57cec5SDimitry Andric
9270b57cec5SDimitry Andric if (Ret != '?')
9280b57cec5SDimitry Andric return Ret;
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric uint32_t Characteristics = 0;
9310b57cec5SDimitry Andric if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
9320b57cec5SDimitry Andric Expected<section_iterator> SecIOrErr = SymI->getSection();
9330b57cec5SDimitry Andric if (!SecIOrErr) {
9340b57cec5SDimitry Andric consumeError(SecIOrErr.takeError());
9350b57cec5SDimitry Andric return '?';
9360b57cec5SDimitry Andric }
9370b57cec5SDimitry Andric section_iterator SecI = *SecIOrErr;
9380b57cec5SDimitry Andric const coff_section *Section = Obj.getCOFFSection(*SecI);
9390b57cec5SDimitry Andric Characteristics = Section->Characteristics;
9400b57cec5SDimitry Andric if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
9415f757f3fSDimitry Andric if (NameOrErr->starts_with(".idata"))
9420b57cec5SDimitry Andric return 'i';
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric
9450b57cec5SDimitry Andric switch (Symb.getSectionNumber()) {
9460b57cec5SDimitry Andric case COFF::IMAGE_SYM_DEBUG:
9470b57cec5SDimitry Andric return 'n';
9480b57cec5SDimitry Andric default:
9490b57cec5SDimitry Andric // Check section type.
9500b57cec5SDimitry Andric if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
9510b57cec5SDimitry Andric return 't';
9520b57cec5SDimitry Andric if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
9530b57cec5SDimitry Andric return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
9540b57cec5SDimitry Andric if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
9550b57cec5SDimitry Andric return 'b';
9560b57cec5SDimitry Andric if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
9570b57cec5SDimitry Andric return 'i';
9580b57cec5SDimitry Andric // Check for section symbol.
9590b57cec5SDimitry Andric if (Symb.isSectionDefinition())
9600b57cec5SDimitry Andric return 's';
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric
9630b57cec5SDimitry Andric return '?';
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric
getSymbolNMTypeChar(XCOFFObjectFile & Obj,symbol_iterator I)96604eeddc0SDimitry Andric static char getSymbolNMTypeChar(XCOFFObjectFile &Obj, symbol_iterator I) {
96704eeddc0SDimitry Andric Expected<uint32_t> TypeOrErr = I->getType();
96804eeddc0SDimitry Andric if (!TypeOrErr) {
96904eeddc0SDimitry Andric warn(TypeOrErr.takeError(), Obj.getFileName(),
97004eeddc0SDimitry Andric "for symbol with index " +
97104eeddc0SDimitry Andric Twine(Obj.getSymbolIndex(I->getRawDataRefImpl().p)));
97204eeddc0SDimitry Andric return '?';
97304eeddc0SDimitry Andric }
97404eeddc0SDimitry Andric
97504eeddc0SDimitry Andric uint32_t SymType = *TypeOrErr;
97604eeddc0SDimitry Andric
97704eeddc0SDimitry Andric if (SymType == SymbolRef::ST_File)
97804eeddc0SDimitry Andric return 'f';
97904eeddc0SDimitry Andric
98004eeddc0SDimitry Andric // If the I->getSection() call would return an error, the earlier I->getType()
98104eeddc0SDimitry Andric // call will already have returned the same error first.
98204eeddc0SDimitry Andric section_iterator SecIter = cantFail(I->getSection());
98304eeddc0SDimitry Andric
98404eeddc0SDimitry Andric if (SecIter == Obj.section_end())
98504eeddc0SDimitry Andric return '?';
98604eeddc0SDimitry Andric
98704eeddc0SDimitry Andric if (Obj.isDebugSection(SecIter->getRawDataRefImpl()))
98804eeddc0SDimitry Andric return 'N';
98904eeddc0SDimitry Andric
99004eeddc0SDimitry Andric if (SecIter->isText())
99104eeddc0SDimitry Andric return 't';
99204eeddc0SDimitry Andric
99304eeddc0SDimitry Andric if (SecIter->isData())
99404eeddc0SDimitry Andric return 'd';
99504eeddc0SDimitry Andric
99604eeddc0SDimitry Andric if (SecIter->isBSS())
99704eeddc0SDimitry Andric return 'b';
99804eeddc0SDimitry Andric
99904eeddc0SDimitry Andric return '?';
100004eeddc0SDimitry Andric }
100104eeddc0SDimitry Andric
getSymbolNMTypeChar(COFFImportFile & Obj)10020b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFImportFile &Obj) {
10030b57cec5SDimitry Andric switch (Obj.getCOFFImportHeader()->getType()) {
10040b57cec5SDimitry Andric case COFF::IMPORT_CODE:
10050b57cec5SDimitry Andric return 't';
10060b57cec5SDimitry Andric case COFF::IMPORT_DATA:
10070b57cec5SDimitry Andric return 'd';
10080b57cec5SDimitry Andric case COFF::IMPORT_CONST:
10090b57cec5SDimitry Andric return 'r';
10100b57cec5SDimitry Andric }
10110b57cec5SDimitry Andric return '?';
10120b57cec5SDimitry Andric }
10130b57cec5SDimitry Andric
getSymbolNMTypeChar(MachOObjectFile & Obj,basic_symbol_iterator I)10140b57cec5SDimitry Andric static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
10150b57cec5SDimitry Andric DataRefImpl Symb = I->getRawDataRefImpl();
10160b57cec5SDimitry Andric uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
10170b57cec5SDimitry Andric : Obj.getSymbolTableEntry(Symb).n_type;
10180b57cec5SDimitry Andric
10190b57cec5SDimitry Andric if (NType & MachO::N_STAB)
10200b57cec5SDimitry Andric return '-';
10210b57cec5SDimitry Andric
10220b57cec5SDimitry Andric switch (NType & MachO::N_TYPE) {
10230b57cec5SDimitry Andric case MachO::N_ABS:
10240b57cec5SDimitry Andric return 's';
10250b57cec5SDimitry Andric case MachO::N_INDR:
10260b57cec5SDimitry Andric return 'i';
10270b57cec5SDimitry Andric case MachO::N_SECT: {
10280b57cec5SDimitry Andric Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb);
10290b57cec5SDimitry Andric if (!SecOrErr) {
10300b57cec5SDimitry Andric consumeError(SecOrErr.takeError());
10310b57cec5SDimitry Andric return 's';
10320b57cec5SDimitry Andric }
10330b57cec5SDimitry Andric section_iterator Sec = *SecOrErr;
10340b57cec5SDimitry Andric if (Sec == Obj.section_end())
10350b57cec5SDimitry Andric return 's';
10360b57cec5SDimitry Andric DataRefImpl Ref = Sec->getRawDataRefImpl();
10370b57cec5SDimitry Andric StringRef SectionName;
10380b57cec5SDimitry Andric if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
10390b57cec5SDimitry Andric SectionName = *NameOrErr;
10400b57cec5SDimitry Andric StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
10410b57cec5SDimitry Andric if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
10420b57cec5SDimitry Andric SegmentName == "__TEXT_EXEC" && SectionName == "__text")
10430b57cec5SDimitry Andric return 't';
10440b57cec5SDimitry Andric if (SegmentName == "__TEXT" && SectionName == "__text")
10450b57cec5SDimitry Andric return 't';
10460b57cec5SDimitry Andric if (SegmentName == "__DATA" && SectionName == "__data")
10470b57cec5SDimitry Andric return 'd';
10480b57cec5SDimitry Andric if (SegmentName == "__DATA" && SectionName == "__bss")
10490b57cec5SDimitry Andric return 'b';
10500b57cec5SDimitry Andric return 's';
10510b57cec5SDimitry Andric }
10520b57cec5SDimitry Andric }
10530b57cec5SDimitry Andric
10540b57cec5SDimitry Andric return '?';
10550b57cec5SDimitry Andric }
10560b57cec5SDimitry Andric
getSymbolNMTypeChar(TapiFile & Obj,basic_symbol_iterator I)10575ffd83dbSDimitry Andric static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
105806c3fb27SDimitry Andric auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl()));
105906c3fb27SDimitry Andric switch (Type) {
106006c3fb27SDimitry Andric case SymbolRef::ST_Function:
106106c3fb27SDimitry Andric return 't';
10625f757f3fSDimitry Andric case SymbolRef::ST_Data:
10635f757f3fSDimitry Andric if (Obj.hasSegmentInfo())
10645f757f3fSDimitry Andric return 'd';
10655f757f3fSDimitry Andric [[fallthrough]];
106606c3fb27SDimitry Andric default:
10675ffd83dbSDimitry Andric return 's';
10685ffd83dbSDimitry Andric }
106906c3fb27SDimitry Andric }
10705ffd83dbSDimitry Andric
getSymbolNMTypeChar(WasmObjectFile & Obj,basic_symbol_iterator I)10710b57cec5SDimitry Andric static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
10725ffd83dbSDimitry Andric uint32_t Flags = cantFail(I->getFlags());
10730b57cec5SDimitry Andric if (Flags & SymbolRef::SF_Executable)
10740b57cec5SDimitry Andric return 't';
10750b57cec5SDimitry Andric return 'd';
10760b57cec5SDimitry Andric }
10770b57cec5SDimitry Andric
getSymbolNMTypeChar(IRObjectFile & Obj,basic_symbol_iterator I)10780b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
10795ffd83dbSDimitry Andric uint32_t Flags = cantFail(I->getFlags());
10800b57cec5SDimitry Andric // FIXME: should we print 'b'? At the IR level we cannot be sure if this
10810b57cec5SDimitry Andric // will be in bss or not, but we could approximate.
10820b57cec5SDimitry Andric if (Flags & SymbolRef::SF_Executable)
10830b57cec5SDimitry Andric return 't';
10840b57cec5SDimitry Andric else if (Triple(Obj.getTargetTriple()).isOSDarwin() &&
10850b57cec5SDimitry Andric (Flags & SymbolRef::SF_Const))
10860b57cec5SDimitry Andric return 's';
10870b57cec5SDimitry Andric else
10880b57cec5SDimitry Andric return 'd';
10890b57cec5SDimitry Andric }
10900b57cec5SDimitry Andric
isObject(SymbolicFile & Obj,basic_symbol_iterator I)10910b57cec5SDimitry Andric static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
1092e8d8bef9SDimitry Andric return isa<ELFObjectFileBase>(&Obj) &&
1093e8d8bef9SDimitry Andric elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
10940b57cec5SDimitry Andric }
10950b57cec5SDimitry Andric
10960b57cec5SDimitry Andric // For ELF object files, Set TypeName to the symbol typename, to be printed
10970b57cec5SDimitry Andric // in the 'Type' column of the SYSV format output.
getNMTypeName(SymbolicFile & Obj,basic_symbol_iterator I)10980b57cec5SDimitry Andric static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
10990b57cec5SDimitry Andric if (isa<ELFObjectFileBase>(&Obj)) {
11000b57cec5SDimitry Andric elf_symbol_iterator SymI(I);
11010b57cec5SDimitry Andric return SymI->getELFTypeName();
11020b57cec5SDimitry Andric }
11030b57cec5SDimitry Andric return "";
11040b57cec5SDimitry Andric }
11050b57cec5SDimitry Andric
11060b57cec5SDimitry Andric // Return Posix nm class type tag (single letter), but also set SecName and
11070b57cec5SDimitry Andric // section and name, to be used in format=sysv output.
getNMSectionTagAndName(SymbolicFile & Obj,basic_symbol_iterator I,StringRef & SecName)11080b57cec5SDimitry Andric static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
11090b57cec5SDimitry Andric StringRef &SecName) {
11105ffd83dbSDimitry Andric // Symbol Flags have been checked in the caller.
11115ffd83dbSDimitry Andric uint32_t Symflags = cantFail(I->getFlags());
11128bcb0991SDimitry Andric if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {
11130b57cec5SDimitry Andric if (Symflags & object::SymbolRef::SF_Absolute)
11140b57cec5SDimitry Andric SecName = "*ABS*";
11150b57cec5SDimitry Andric else if (Symflags & object::SymbolRef::SF_Common)
11160b57cec5SDimitry Andric SecName = "*COM*";
11170b57cec5SDimitry Andric else if (Symflags & object::SymbolRef::SF_Undefined)
11180b57cec5SDimitry Andric SecName = "*UND*";
11190b57cec5SDimitry Andric else {
11200b57cec5SDimitry Andric elf_symbol_iterator SymI(I);
11210b57cec5SDimitry Andric Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
11220b57cec5SDimitry Andric if (!SecIOrErr) {
11230b57cec5SDimitry Andric consumeError(SecIOrErr.takeError());
11240b57cec5SDimitry Andric return '?';
11250b57cec5SDimitry Andric }
11268bcb0991SDimitry Andric
11278bcb0991SDimitry Andric if (*SecIOrErr == ELFObj->section_end())
11288bcb0991SDimitry Andric return '?';
11298bcb0991SDimitry Andric
11308bcb0991SDimitry Andric Expected<StringRef> NameOrErr = (*SecIOrErr)->getName();
11318bcb0991SDimitry Andric if (!NameOrErr) {
11328bcb0991SDimitry Andric consumeError(NameOrErr.takeError());
11338bcb0991SDimitry Andric return '?';
11348bcb0991SDimitry Andric }
11358bcb0991SDimitry Andric SecName = *NameOrErr;
11360b57cec5SDimitry Andric }
11370b57cec5SDimitry Andric }
11380b57cec5SDimitry Andric
1139fe6060f1SDimitry Andric if (Symflags & object::SymbolRef::SF_Undefined) {
1140fe6060f1SDimitry Andric if (isa<MachOObjectFile>(Obj) || !(Symflags & object::SymbolRef::SF_Weak))
11410b57cec5SDimitry Andric return 'U';
1142fe6060f1SDimitry Andric return isObject(Obj, I) ? 'v' : 'w';
1143fe6060f1SDimitry Andric }
1144fe6060f1SDimitry Andric if (isa<ELFObjectFileBase>(&Obj))
1145fe6060f1SDimitry Andric if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC)
1146fe6060f1SDimitry Andric return 'i';
1147fe6060f1SDimitry Andric if (!isa<MachOObjectFile>(Obj) && (Symflags & object::SymbolRef::SF_Weak))
1148fe6060f1SDimitry Andric return isObject(Obj, I) ? 'V' : 'W';
11490b57cec5SDimitry Andric
11500b57cec5SDimitry Andric if (Symflags & object::SymbolRef::SF_Common)
11510b57cec5SDimitry Andric return 'C';
11520b57cec5SDimitry Andric
11530b57cec5SDimitry Andric char Ret = '?';
11540b57cec5SDimitry Andric if (Symflags & object::SymbolRef::SF_Absolute)
11550b57cec5SDimitry Andric Ret = 'a';
11560b57cec5SDimitry Andric else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
11570b57cec5SDimitry Andric Ret = getSymbolNMTypeChar(*IR, I);
11580b57cec5SDimitry Andric else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
11590b57cec5SDimitry Andric Ret = getSymbolNMTypeChar(*COFF, I);
116004eeddc0SDimitry Andric else if (XCOFFObjectFile *XCOFF = dyn_cast<XCOFFObjectFile>(&Obj))
116104eeddc0SDimitry Andric Ret = getSymbolNMTypeChar(*XCOFF, I);
11620b57cec5SDimitry Andric else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
11630b57cec5SDimitry Andric Ret = getSymbolNMTypeChar(*COFFImport);
11640b57cec5SDimitry Andric else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
11650b57cec5SDimitry Andric Ret = getSymbolNMTypeChar(*MachO, I);
11660b57cec5SDimitry Andric else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
11670b57cec5SDimitry Andric Ret = getSymbolNMTypeChar(*Wasm, I);
11685ffd83dbSDimitry Andric else if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
11695ffd83dbSDimitry Andric Ret = getSymbolNMTypeChar(*Tapi, I);
1170480093f4SDimitry Andric else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) {
1171480093f4SDimitry Andric Ret = getSymbolNMTypeChar(*ELF, I);
1172480093f4SDimitry Andric if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
1173480093f4SDimitry Andric return Ret;
1174480093f4SDimitry Andric } else
1175480093f4SDimitry Andric llvm_unreachable("unknown binary format");
11760b57cec5SDimitry Andric
11770b57cec5SDimitry Andric if (!(Symflags & object::SymbolRef::SF_Global))
11780b57cec5SDimitry Andric return Ret;
11790b57cec5SDimitry Andric
11800b57cec5SDimitry Andric return toupper(Ret);
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric
11830b57cec5SDimitry Andric // getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
11840b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
118581ad6265SDimitry Andric // It is called once for each Mach-O file from getSymbolNamesFromObject()
11860b57cec5SDimitry Andric // to get the section number for that named section from the command line
11870b57cec5SDimitry Andric // arguments. It returns the section number for that section in the Mach-O
11880b57cec5SDimitry Andric // file or zero it is not present.
getNsectForSegSect(MachOObjectFile * Obj)11890b57cec5SDimitry Andric static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
11900b57cec5SDimitry Andric unsigned Nsect = 1;
11910b57cec5SDimitry Andric for (auto &S : Obj->sections()) {
11920b57cec5SDimitry Andric DataRefImpl Ref = S.getRawDataRefImpl();
11930b57cec5SDimitry Andric StringRef SectionName;
11940b57cec5SDimitry Andric if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
11950b57cec5SDimitry Andric SectionName = *NameOrErr;
11960b57cec5SDimitry Andric StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
11970b57cec5SDimitry Andric if (SegmentName == SegSect[0] && SectionName == SegSect[1])
11980b57cec5SDimitry Andric return Nsect;
11990b57cec5SDimitry Andric Nsect++;
12000b57cec5SDimitry Andric }
12010b57cec5SDimitry Andric return 0;
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric
12040b57cec5SDimitry Andric // getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
12050b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
12060b57cec5SDimitry Andric // It is called once for each symbol in a Mach-O file from
120781ad6265SDimitry Andric // getSymbolNamesFromObject() and returns the section number for that symbol
12080b57cec5SDimitry Andric // if it is in a section, else it returns 0.
getNsectInMachO(MachOObjectFile & Obj,BasicSymbolRef Sym)12090b57cec5SDimitry Andric static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
12100b57cec5SDimitry Andric DataRefImpl Symb = Sym.getRawDataRefImpl();
12110b57cec5SDimitry Andric if (Obj.is64Bit()) {
12120b57cec5SDimitry Andric MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
12130b57cec5SDimitry Andric return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
12140b57cec5SDimitry Andric }
12150b57cec5SDimitry Andric MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
12160b57cec5SDimitry Andric return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
12170b57cec5SDimitry Andric }
12180b57cec5SDimitry Andric
dumpSymbolsFromDLInfoMachO(MachOObjectFile & MachO,std::vector<NMSymbol> & SymbolList)121981ad6265SDimitry Andric static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO,
122081ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList) {
1221e8d8bef9SDimitry Andric size_t I = SymbolList.size();
12220b57cec5SDimitry Andric std::string ExportsNameBuffer;
12230b57cec5SDimitry Andric raw_string_ostream EOS(ExportsNameBuffer);
12240b57cec5SDimitry Andric std::string BindsNameBuffer;
12250b57cec5SDimitry Andric raw_string_ostream BOS(BindsNameBuffer);
12260b57cec5SDimitry Andric std::string LazysNameBuffer;
12270b57cec5SDimitry Andric raw_string_ostream LOS(LazysNameBuffer);
12280b57cec5SDimitry Andric std::string WeaksNameBuffer;
12290b57cec5SDimitry Andric raw_string_ostream WOS(WeaksNameBuffer);
12300b57cec5SDimitry Andric std::string FunctionStartsNameBuffer;
12310b57cec5SDimitry Andric raw_string_ostream FOS(FunctionStartsNameBuffer);
1232e8d8bef9SDimitry Andric
12330b57cec5SDimitry Andric MachO::mach_header H;
12340b57cec5SDimitry Andric MachO::mach_header_64 H_64;
12350b57cec5SDimitry Andric uint32_t HFlags = 0;
1236e8d8bef9SDimitry Andric if (MachO.is64Bit()) {
1237e8d8bef9SDimitry Andric H_64 = MachO.MachOObjectFile::getHeader64();
12380b57cec5SDimitry Andric HFlags = H_64.flags;
12390b57cec5SDimitry Andric } else {
1240e8d8bef9SDimitry Andric H = MachO.MachOObjectFile::getHeader();
12410b57cec5SDimitry Andric HFlags = H.flags;
12420b57cec5SDimitry Andric }
12430b57cec5SDimitry Andric uint64_t BaseSegmentAddress = 0;
1244e8d8bef9SDimitry Andric for (const auto &Command : MachO.load_commands()) {
12450b57cec5SDimitry Andric if (Command.C.cmd == MachO::LC_SEGMENT) {
1246e8d8bef9SDimitry Andric MachO::segment_command Seg = MachO.getSegmentLoadCommand(Command);
12470b57cec5SDimitry Andric if (Seg.fileoff == 0 && Seg.filesize != 0) {
12480b57cec5SDimitry Andric BaseSegmentAddress = Seg.vmaddr;
12490b57cec5SDimitry Andric break;
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1252e8d8bef9SDimitry Andric MachO::segment_command_64 Seg = MachO.getSegment64LoadCommand(Command);
12530b57cec5SDimitry Andric if (Seg.fileoff == 0 && Seg.filesize != 0) {
12540b57cec5SDimitry Andric BaseSegmentAddress = Seg.vmaddr;
12550b57cec5SDimitry Andric break;
12560b57cec5SDimitry Andric }
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric if (DyldInfoOnly || AddDyldInfo ||
12600b57cec5SDimitry Andric HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
12610b57cec5SDimitry Andric unsigned ExportsAdded = 0;
12620b57cec5SDimitry Andric Error Err = Error::success();
1263e8d8bef9SDimitry Andric for (const llvm::object::ExportEntry &Entry : MachO.exports(Err)) {
12640b57cec5SDimitry Andric bool found = false;
12650b57cec5SDimitry Andric bool ReExport = false;
12660b57cec5SDimitry Andric if (!DyldInfoOnly) {
12670b57cec5SDimitry Andric for (const NMSymbol &S : SymbolList)
12680b57cec5SDimitry Andric if (S.Address == Entry.address() + BaseSegmentAddress &&
12690b57cec5SDimitry Andric S.Name == Entry.name()) {
12700b57cec5SDimitry Andric found = true;
12710b57cec5SDimitry Andric break;
12720b57cec5SDimitry Andric }
12730b57cec5SDimitry Andric }
12740b57cec5SDimitry Andric if (!found) {
12750b57cec5SDimitry Andric NMSymbol S = {};
12760b57cec5SDimitry Andric S.Address = Entry.address() + BaseSegmentAddress;
12770b57cec5SDimitry Andric S.Size = 0;
12780b57cec5SDimitry Andric S.TypeChar = '\0';
1279e8d8bef9SDimitry Andric S.Name = Entry.name().str();
12800b57cec5SDimitry Andric // There is no symbol in the nlist symbol table for this so we set
12810b57cec5SDimitry Andric // Sym effectivly to null and the rest of code in here must test for
12820b57cec5SDimitry Andric // it and not do things like Sym.getFlags() for it.
12830b57cec5SDimitry Andric S.Sym = BasicSymbolRef();
12840b57cec5SDimitry Andric S.SymFlags = SymbolRef::SF_Global;
12850b57cec5SDimitry Andric S.Section = SectionRef();
12860b57cec5SDimitry Andric S.NType = 0;
12870b57cec5SDimitry Andric S.NSect = 0;
12880b57cec5SDimitry Andric S.NDesc = 0;
12890b57cec5SDimitry Andric
12900b57cec5SDimitry Andric uint64_t EFlags = Entry.flags();
12910b57cec5SDimitry Andric bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
12920b57cec5SDimitry Andric MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
1293e8d8bef9SDimitry Andric bool Resolver = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
12940b57cec5SDimitry Andric ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
12950b57cec5SDimitry Andric bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
12960b57cec5SDimitry Andric if (WeakDef)
12970b57cec5SDimitry Andric S.NDesc |= MachO::N_WEAK_DEF;
12980b57cec5SDimitry Andric if (Abs) {
12990b57cec5SDimitry Andric S.NType = MachO::N_EXT | MachO::N_ABS;
13000b57cec5SDimitry Andric S.TypeChar = 'A';
13010b57cec5SDimitry Andric } else if (ReExport) {
13020b57cec5SDimitry Andric S.NType = MachO::N_EXT | MachO::N_INDR;
13030b57cec5SDimitry Andric S.TypeChar = 'I';
13040b57cec5SDimitry Andric } else {
13050b57cec5SDimitry Andric S.NType = MachO::N_EXT | MachO::N_SECT;
13060b57cec5SDimitry Andric if (Resolver) {
13070b57cec5SDimitry Andric S.Address = Entry.other() + BaseSegmentAddress;
1308e8d8bef9SDimitry Andric if ((S.Address & 1) != 0 && !MachO.is64Bit() &&
1309e8d8bef9SDimitry Andric H.cputype == MachO::CPU_TYPE_ARM) {
13100b57cec5SDimitry Andric S.Address &= ~1LL;
13110b57cec5SDimitry Andric S.NDesc |= MachO::N_ARM_THUMB_DEF;
13120b57cec5SDimitry Andric }
13130b57cec5SDimitry Andric } else {
13140b57cec5SDimitry Andric S.Address = Entry.address() + BaseSegmentAddress;
13150b57cec5SDimitry Andric }
13160b57cec5SDimitry Andric StringRef SegmentName = StringRef();
13170b57cec5SDimitry Andric StringRef SectionName = StringRef();
1318e8d8bef9SDimitry Andric for (const SectionRef &Section : MachO.sections()) {
13190b57cec5SDimitry Andric S.NSect++;
13208bcb0991SDimitry Andric
13218bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Section.getName())
13228bcb0991SDimitry Andric SectionName = *NameOrErr;
13238bcb0991SDimitry Andric else
13248bcb0991SDimitry Andric consumeError(NameOrErr.takeError());
13258bcb0991SDimitry Andric
1326e8d8bef9SDimitry Andric SegmentName =
1327e8d8bef9SDimitry Andric MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
13280b57cec5SDimitry Andric if (S.Address >= Section.getAddress() &&
13290b57cec5SDimitry Andric S.Address < Section.getAddress() + Section.getSize()) {
13300b57cec5SDimitry Andric S.Section = Section;
13310b57cec5SDimitry Andric break;
13320b57cec5SDimitry Andric } else if (Entry.name() == "__mh_execute_header" &&
13330b57cec5SDimitry Andric SegmentName == "__TEXT" && SectionName == "__text") {
13340b57cec5SDimitry Andric S.Section = Section;
13350b57cec5SDimitry Andric S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
13360b57cec5SDimitry Andric break;
13370b57cec5SDimitry Andric }
13380b57cec5SDimitry Andric }
13390b57cec5SDimitry Andric if (SegmentName == "__TEXT" && SectionName == "__text")
13400b57cec5SDimitry Andric S.TypeChar = 'T';
13410b57cec5SDimitry Andric else if (SegmentName == "__DATA" && SectionName == "__data")
13420b57cec5SDimitry Andric S.TypeChar = 'D';
13430b57cec5SDimitry Andric else if (SegmentName == "__DATA" && SectionName == "__bss")
13440b57cec5SDimitry Andric S.TypeChar = 'B';
13450b57cec5SDimitry Andric else
13460b57cec5SDimitry Andric S.TypeChar = 'S';
13470b57cec5SDimitry Andric }
13480b57cec5SDimitry Andric SymbolList.push_back(S);
13490b57cec5SDimitry Andric
13500b57cec5SDimitry Andric EOS << Entry.name();
13510b57cec5SDimitry Andric EOS << '\0';
13520b57cec5SDimitry Andric ExportsAdded++;
13530b57cec5SDimitry Andric
13540b57cec5SDimitry Andric // For ReExports there are a two more things to do, first add the
13550b57cec5SDimitry Andric // indirect name and second create the undefined symbol using the
13560b57cec5SDimitry Andric // referened dynamic library.
13570b57cec5SDimitry Andric if (ReExport) {
13580b57cec5SDimitry Andric
13590b57cec5SDimitry Andric // Add the indirect name.
13600b57cec5SDimitry Andric if (Entry.otherName().empty())
13610b57cec5SDimitry Andric EOS << Entry.name();
13620b57cec5SDimitry Andric else
13630b57cec5SDimitry Andric EOS << Entry.otherName();
13640b57cec5SDimitry Andric EOS << '\0';
13650b57cec5SDimitry Andric
13660b57cec5SDimitry Andric // Now create the undefined symbol using the referened dynamic
13670b57cec5SDimitry Andric // library.
13680b57cec5SDimitry Andric NMSymbol U = {};
13690b57cec5SDimitry Andric U.Address = 0;
13700b57cec5SDimitry Andric U.Size = 0;
13710b57cec5SDimitry Andric U.TypeChar = 'U';
13720b57cec5SDimitry Andric if (Entry.otherName().empty())
1373e8d8bef9SDimitry Andric U.Name = Entry.name().str();
13740b57cec5SDimitry Andric else
1375e8d8bef9SDimitry Andric U.Name = Entry.otherName().str();
13760b57cec5SDimitry Andric // Again there is no symbol in the nlist symbol table for this so
13770b57cec5SDimitry Andric // we set Sym effectivly to null and the rest of code in here must
13780b57cec5SDimitry Andric // test for it and not do things like Sym.getFlags() for it.
13790b57cec5SDimitry Andric U.Sym = BasicSymbolRef();
13800b57cec5SDimitry Andric U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
13810b57cec5SDimitry Andric U.Section = SectionRef();
13820b57cec5SDimitry Andric U.NType = MachO::N_EXT | MachO::N_UNDF;
13830b57cec5SDimitry Andric U.NSect = 0;
13840b57cec5SDimitry Andric U.NDesc = 0;
13850b57cec5SDimitry Andric // The library ordinal for this undefined symbol is in the export
13860b57cec5SDimitry Andric // trie Entry.other().
13870b57cec5SDimitry Andric MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
13880b57cec5SDimitry Andric SymbolList.push_back(U);
13890b57cec5SDimitry Andric
13900b57cec5SDimitry Andric // Finally add the undefined symbol's name.
13910b57cec5SDimitry Andric if (Entry.otherName().empty())
13920b57cec5SDimitry Andric EOS << Entry.name();
13930b57cec5SDimitry Andric else
13940b57cec5SDimitry Andric EOS << Entry.otherName();
13950b57cec5SDimitry Andric EOS << '\0';
13960b57cec5SDimitry Andric ExportsAdded++;
13970b57cec5SDimitry Andric }
13980b57cec5SDimitry Andric }
13990b57cec5SDimitry Andric }
14000b57cec5SDimitry Andric if (Err)
1401e8d8bef9SDimitry Andric error(std::move(Err), MachO.getFileName());
14020b57cec5SDimitry Andric // Set the symbol names and indirect names for the added symbols.
14030b57cec5SDimitry Andric if (ExportsAdded) {
14040b57cec5SDimitry Andric EOS.flush();
14050b57cec5SDimitry Andric const char *Q = ExportsNameBuffer.c_str();
14060b57cec5SDimitry Andric for (unsigned K = 0; K < ExportsAdded; K++) {
14070b57cec5SDimitry Andric SymbolList[I].Name = Q;
14080b57cec5SDimitry Andric Q += strlen(Q) + 1;
14090b57cec5SDimitry Andric if (SymbolList[I].TypeChar == 'I') {
14100b57cec5SDimitry Andric SymbolList[I].IndirectName = Q;
14110b57cec5SDimitry Andric Q += strlen(Q) + 1;
14120b57cec5SDimitry Andric }
14130b57cec5SDimitry Andric I++;
14140b57cec5SDimitry Andric }
14150b57cec5SDimitry Andric }
14160b57cec5SDimitry Andric
14170b57cec5SDimitry Andric // Add the undefined symbols from the bind entries.
14180b57cec5SDimitry Andric unsigned BindsAdded = 0;
14190b57cec5SDimitry Andric Error BErr = Error::success();
14200b57cec5SDimitry Andric StringRef LastSymbolName = StringRef();
1421e8d8bef9SDimitry Andric for (const llvm::object::MachOBindEntry &Entry : MachO.bindTable(BErr)) {
14220b57cec5SDimitry Andric bool found = false;
14230b57cec5SDimitry Andric if (LastSymbolName == Entry.symbolName())
14240b57cec5SDimitry Andric found = true;
14250b57cec5SDimitry Andric else if (!DyldInfoOnly) {
14260b57cec5SDimitry Andric for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
14270b57cec5SDimitry Andric if (SymbolList[J].Name == Entry.symbolName())
14280b57cec5SDimitry Andric found = true;
14290b57cec5SDimitry Andric }
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric if (!found) {
14320b57cec5SDimitry Andric LastSymbolName = Entry.symbolName();
14330b57cec5SDimitry Andric NMSymbol B = {};
14340b57cec5SDimitry Andric B.Address = 0;
14350b57cec5SDimitry Andric B.Size = 0;
14360b57cec5SDimitry Andric B.TypeChar = 'U';
14370b57cec5SDimitry Andric // There is no symbol in the nlist symbol table for this so we set
14380b57cec5SDimitry Andric // Sym effectivly to null and the rest of code in here must test for
14390b57cec5SDimitry Andric // it and not do things like Sym.getFlags() for it.
14400b57cec5SDimitry Andric B.Sym = BasicSymbolRef();
14410b57cec5SDimitry Andric B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
14420b57cec5SDimitry Andric B.NType = MachO::N_EXT | MachO::N_UNDF;
14430b57cec5SDimitry Andric B.NSect = 0;
14440b57cec5SDimitry Andric B.NDesc = 0;
14450b57cec5SDimitry Andric MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
1446e8d8bef9SDimitry Andric B.Name = Entry.symbolName().str();
14470b57cec5SDimitry Andric SymbolList.push_back(B);
14480b57cec5SDimitry Andric BOS << Entry.symbolName();
14490b57cec5SDimitry Andric BOS << '\0';
14500b57cec5SDimitry Andric BindsAdded++;
14510b57cec5SDimitry Andric }
14520b57cec5SDimitry Andric }
14530b57cec5SDimitry Andric if (BErr)
1454e8d8bef9SDimitry Andric error(std::move(BErr), MachO.getFileName());
14550b57cec5SDimitry Andric // Set the symbol names and indirect names for the added symbols.
14560b57cec5SDimitry Andric if (BindsAdded) {
14570b57cec5SDimitry Andric BOS.flush();
14580b57cec5SDimitry Andric const char *Q = BindsNameBuffer.c_str();
14590b57cec5SDimitry Andric for (unsigned K = 0; K < BindsAdded; K++) {
14600b57cec5SDimitry Andric SymbolList[I].Name = Q;
14610b57cec5SDimitry Andric Q += strlen(Q) + 1;
14620b57cec5SDimitry Andric if (SymbolList[I].TypeChar == 'I') {
14630b57cec5SDimitry Andric SymbolList[I].IndirectName = Q;
14640b57cec5SDimitry Andric Q += strlen(Q) + 1;
14650b57cec5SDimitry Andric }
14660b57cec5SDimitry Andric I++;
14670b57cec5SDimitry Andric }
14680b57cec5SDimitry Andric }
14690b57cec5SDimitry Andric
14700b57cec5SDimitry Andric // Add the undefined symbols from the lazy bind entries.
14710b57cec5SDimitry Andric unsigned LazysAdded = 0;
14720b57cec5SDimitry Andric Error LErr = Error::success();
14730b57cec5SDimitry Andric LastSymbolName = StringRef();
14740b57cec5SDimitry Andric for (const llvm::object::MachOBindEntry &Entry :
1475e8d8bef9SDimitry Andric MachO.lazyBindTable(LErr)) {
14760b57cec5SDimitry Andric bool found = false;
14770b57cec5SDimitry Andric if (LastSymbolName == Entry.symbolName())
14780b57cec5SDimitry Andric found = true;
14790b57cec5SDimitry Andric else {
14800b57cec5SDimitry Andric // Here we must check to see it this symbol is already in the
14810b57cec5SDimitry Andric // SymbolList as it might have already have been added above via a
14820b57cec5SDimitry Andric // non-lazy (bind) entry.
14830b57cec5SDimitry Andric for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
14840b57cec5SDimitry Andric if (SymbolList[J].Name == Entry.symbolName())
14850b57cec5SDimitry Andric found = true;
14860b57cec5SDimitry Andric }
14870b57cec5SDimitry Andric }
14880b57cec5SDimitry Andric if (!found) {
14890b57cec5SDimitry Andric LastSymbolName = Entry.symbolName();
14900b57cec5SDimitry Andric NMSymbol L = {};
1491e8d8bef9SDimitry Andric L.Name = Entry.symbolName().str();
14920b57cec5SDimitry Andric L.Address = 0;
14930b57cec5SDimitry Andric L.Size = 0;
14940b57cec5SDimitry Andric L.TypeChar = 'U';
14950b57cec5SDimitry Andric // There is no symbol in the nlist symbol table for this so we set
14960b57cec5SDimitry Andric // Sym effectivly to null and the rest of code in here must test for
14970b57cec5SDimitry Andric // it and not do things like Sym.getFlags() for it.
14980b57cec5SDimitry Andric L.Sym = BasicSymbolRef();
14990b57cec5SDimitry Andric L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
15000b57cec5SDimitry Andric L.NType = MachO::N_EXT | MachO::N_UNDF;
15010b57cec5SDimitry Andric L.NSect = 0;
15020b57cec5SDimitry Andric // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
15030b57cec5SDimitry Andric // makes sence since we are creating this from a lazy bind entry.
15040b57cec5SDimitry Andric L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
15050b57cec5SDimitry Andric MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
15060b57cec5SDimitry Andric SymbolList.push_back(L);
15070b57cec5SDimitry Andric LOS << Entry.symbolName();
15080b57cec5SDimitry Andric LOS << '\0';
15090b57cec5SDimitry Andric LazysAdded++;
15100b57cec5SDimitry Andric }
15110b57cec5SDimitry Andric }
15120b57cec5SDimitry Andric if (LErr)
1513e8d8bef9SDimitry Andric error(std::move(LErr), MachO.getFileName());
15140b57cec5SDimitry Andric // Set the symbol names and indirect names for the added symbols.
15150b57cec5SDimitry Andric if (LazysAdded) {
15160b57cec5SDimitry Andric LOS.flush();
15170b57cec5SDimitry Andric const char *Q = LazysNameBuffer.c_str();
15180b57cec5SDimitry Andric for (unsigned K = 0; K < LazysAdded; K++) {
15190b57cec5SDimitry Andric SymbolList[I].Name = Q;
15200b57cec5SDimitry Andric Q += strlen(Q) + 1;
15210b57cec5SDimitry Andric if (SymbolList[I].TypeChar == 'I') {
15220b57cec5SDimitry Andric SymbolList[I].IndirectName = Q;
15230b57cec5SDimitry Andric Q += strlen(Q) + 1;
15240b57cec5SDimitry Andric }
15250b57cec5SDimitry Andric I++;
15260b57cec5SDimitry Andric }
15270b57cec5SDimitry Andric }
15280b57cec5SDimitry Andric
15290b57cec5SDimitry Andric // Add the undefineds symbol from the weak bind entries which are not
15300b57cec5SDimitry Andric // strong symbols.
15310b57cec5SDimitry Andric unsigned WeaksAdded = 0;
15320b57cec5SDimitry Andric Error WErr = Error::success();
15330b57cec5SDimitry Andric LastSymbolName = StringRef();
15340b57cec5SDimitry Andric for (const llvm::object::MachOBindEntry &Entry :
1535e8d8bef9SDimitry Andric MachO.weakBindTable(WErr)) {
15360b57cec5SDimitry Andric bool found = false;
15370b57cec5SDimitry Andric unsigned J = 0;
15380b57cec5SDimitry Andric if (LastSymbolName == Entry.symbolName() ||
15390b57cec5SDimitry Andric Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
15400b57cec5SDimitry Andric found = true;
15410b57cec5SDimitry Andric } else {
15420b57cec5SDimitry Andric for (J = 0; J < SymbolList.size() && !found; ++J) {
15430b57cec5SDimitry Andric if (SymbolList[J].Name == Entry.symbolName()) {
15440b57cec5SDimitry Andric found = true;
15450b57cec5SDimitry Andric break;
15460b57cec5SDimitry Andric }
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric }
15490b57cec5SDimitry Andric if (!found) {
15500b57cec5SDimitry Andric LastSymbolName = Entry.symbolName();
1551e8d8bef9SDimitry Andric NMSymbol W = {};
1552e8d8bef9SDimitry Andric W.Name = Entry.symbolName().str();
15530b57cec5SDimitry Andric W.Address = 0;
15540b57cec5SDimitry Andric W.Size = 0;
15550b57cec5SDimitry Andric W.TypeChar = 'U';
15560b57cec5SDimitry Andric // There is no symbol in the nlist symbol table for this so we set
15570b57cec5SDimitry Andric // Sym effectivly to null and the rest of code in here must test for
15580b57cec5SDimitry Andric // it and not do things like Sym.getFlags() for it.
15590b57cec5SDimitry Andric W.Sym = BasicSymbolRef();
15600b57cec5SDimitry Andric W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
15610b57cec5SDimitry Andric W.NType = MachO::N_EXT | MachO::N_UNDF;
15620b57cec5SDimitry Andric W.NSect = 0;
15630b57cec5SDimitry Andric // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
15640b57cec5SDimitry Andric // what is created in this case by the linker when there are real
15650b57cec5SDimitry Andric // symbols in the nlist structs.
15660b57cec5SDimitry Andric W.NDesc = MachO::N_WEAK_DEF;
15670b57cec5SDimitry Andric SymbolList.push_back(W);
15680b57cec5SDimitry Andric WOS << Entry.symbolName();
15690b57cec5SDimitry Andric WOS << '\0';
15700b57cec5SDimitry Andric WeaksAdded++;
15710b57cec5SDimitry Andric } else {
15720b57cec5SDimitry Andric // This is the case the symbol was previously been found and it could
15730b57cec5SDimitry Andric // have been added from a bind or lazy bind symbol. If so and not
15740b57cec5SDimitry Andric // a definition also mark it as weak.
15750b57cec5SDimitry Andric if (SymbolList[J].TypeChar == 'U')
15760b57cec5SDimitry Andric // See comment above about N_WEAK_DEF.
15770b57cec5SDimitry Andric SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
15780b57cec5SDimitry Andric }
15790b57cec5SDimitry Andric }
15800b57cec5SDimitry Andric if (WErr)
1581e8d8bef9SDimitry Andric error(std::move(WErr), MachO.getFileName());
15820b57cec5SDimitry Andric // Set the symbol names and indirect names for the added symbols.
15830b57cec5SDimitry Andric if (WeaksAdded) {
15840b57cec5SDimitry Andric WOS.flush();
15850b57cec5SDimitry Andric const char *Q = WeaksNameBuffer.c_str();
15860b57cec5SDimitry Andric for (unsigned K = 0; K < WeaksAdded; K++) {
15870b57cec5SDimitry Andric SymbolList[I].Name = Q;
15880b57cec5SDimitry Andric Q += strlen(Q) + 1;
15890b57cec5SDimitry Andric if (SymbolList[I].TypeChar == 'I') {
15900b57cec5SDimitry Andric SymbolList[I].IndirectName = Q;
15910b57cec5SDimitry Andric Q += strlen(Q) + 1;
15920b57cec5SDimitry Andric }
15930b57cec5SDimitry Andric I++;
15940b57cec5SDimitry Andric }
15950b57cec5SDimitry Andric }
15960b57cec5SDimitry Andric
15970b57cec5SDimitry Andric // Trying adding symbol from the function starts table and LC_MAIN entry
15980b57cec5SDimitry Andric // point.
15990b57cec5SDimitry Andric SmallVector<uint64_t, 8> FoundFns;
16000b57cec5SDimitry Andric uint64_t lc_main_offset = UINT64_MAX;
1601e8d8bef9SDimitry Andric for (const auto &Command : MachO.load_commands()) {
16020b57cec5SDimitry Andric if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
16030b57cec5SDimitry Andric // We found a function starts segment, parse the addresses for
16040b57cec5SDimitry Andric // consumption.
16050b57cec5SDimitry Andric MachO::linkedit_data_command LLC =
1606e8d8bef9SDimitry Andric MachO.getLinkeditDataLoadCommand(Command);
16070b57cec5SDimitry Andric
1608e8d8bef9SDimitry Andric MachO.ReadULEB128s(LLC.dataoff, FoundFns);
16090b57cec5SDimitry Andric } else if (Command.C.cmd == MachO::LC_MAIN) {
1610e8d8bef9SDimitry Andric MachO::entry_point_command LCmain = MachO.getEntryPointCommand(Command);
16110b57cec5SDimitry Andric lc_main_offset = LCmain.entryoff;
16120b57cec5SDimitry Andric }
16130b57cec5SDimitry Andric }
16140b57cec5SDimitry Andric // See if these addresses are already in the symbol table.
16150b57cec5SDimitry Andric unsigned FunctionStartsAdded = 0;
16160b57cec5SDimitry Andric for (uint64_t f = 0; f < FoundFns.size(); f++) {
16170b57cec5SDimitry Andric bool found = false;
16180b57cec5SDimitry Andric for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
16190b57cec5SDimitry Andric if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
16200b57cec5SDimitry Andric found = true;
16210b57cec5SDimitry Andric }
16220b57cec5SDimitry Andric // See this address is not already in the symbol table fake up an
16230b57cec5SDimitry Andric // nlist for it.
16240b57cec5SDimitry Andric if (!found) {
16250b57cec5SDimitry Andric NMSymbol F = {};
16260b57cec5SDimitry Andric F.Name = "<redacted function X>";
16270b57cec5SDimitry Andric F.Address = FoundFns[f] + BaseSegmentAddress;
16280b57cec5SDimitry Andric F.Size = 0;
16290b57cec5SDimitry Andric // There is no symbol in the nlist symbol table for this so we set
16300b57cec5SDimitry Andric // Sym effectivly to null and the rest of code in here must test for
16310b57cec5SDimitry Andric // it and not do things like Sym.getFlags() for it.
16320b57cec5SDimitry Andric F.Sym = BasicSymbolRef();
16330b57cec5SDimitry Andric F.SymFlags = 0;
16340b57cec5SDimitry Andric F.NType = MachO::N_SECT;
16350b57cec5SDimitry Andric F.NSect = 0;
16360b57cec5SDimitry Andric StringRef SegmentName = StringRef();
16370b57cec5SDimitry Andric StringRef SectionName = StringRef();
1638e8d8bef9SDimitry Andric for (const SectionRef &Section : MachO.sections()) {
16398bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Section.getName())
16408bcb0991SDimitry Andric SectionName = *NameOrErr;
16418bcb0991SDimitry Andric else
16428bcb0991SDimitry Andric consumeError(NameOrErr.takeError());
16438bcb0991SDimitry Andric
1644e8d8bef9SDimitry Andric SegmentName =
1645e8d8bef9SDimitry Andric MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
16460b57cec5SDimitry Andric F.NSect++;
16470b57cec5SDimitry Andric if (F.Address >= Section.getAddress() &&
16480b57cec5SDimitry Andric F.Address < Section.getAddress() + Section.getSize()) {
16490b57cec5SDimitry Andric F.Section = Section;
16500b57cec5SDimitry Andric break;
16510b57cec5SDimitry Andric }
16520b57cec5SDimitry Andric }
16530b57cec5SDimitry Andric if (SegmentName == "__TEXT" && SectionName == "__text")
16540b57cec5SDimitry Andric F.TypeChar = 't';
16550b57cec5SDimitry Andric else if (SegmentName == "__DATA" && SectionName == "__data")
16560b57cec5SDimitry Andric F.TypeChar = 'd';
16570b57cec5SDimitry Andric else if (SegmentName == "__DATA" && SectionName == "__bss")
16580b57cec5SDimitry Andric F.TypeChar = 'b';
16590b57cec5SDimitry Andric else
16600b57cec5SDimitry Andric F.TypeChar = 's';
16610b57cec5SDimitry Andric F.NDesc = 0;
16620b57cec5SDimitry Andric SymbolList.push_back(F);
16630b57cec5SDimitry Andric if (FoundFns[f] == lc_main_offset)
16640b57cec5SDimitry Andric FOS << "<redacted LC_MAIN>";
16650b57cec5SDimitry Andric else
16660b57cec5SDimitry Andric FOS << "<redacted function " << f << ">";
16670b57cec5SDimitry Andric FOS << '\0';
16680b57cec5SDimitry Andric FunctionStartsAdded++;
16690b57cec5SDimitry Andric }
16700b57cec5SDimitry Andric }
16710b57cec5SDimitry Andric if (FunctionStartsAdded) {
16720b57cec5SDimitry Andric FOS.flush();
16730b57cec5SDimitry Andric const char *Q = FunctionStartsNameBuffer.c_str();
16740b57cec5SDimitry Andric for (unsigned K = 0; K < FunctionStartsAdded; K++) {
16750b57cec5SDimitry Andric SymbolList[I].Name = Q;
16760b57cec5SDimitry Andric Q += strlen(Q) + 1;
16770b57cec5SDimitry Andric if (SymbolList[I].TypeChar == 'I') {
16780b57cec5SDimitry Andric SymbolList[I].IndirectName = Q;
16790b57cec5SDimitry Andric Q += strlen(Q) + 1;
16800b57cec5SDimitry Andric }
16810b57cec5SDimitry Andric I++;
16820b57cec5SDimitry Andric }
16830b57cec5SDimitry Andric }
16840b57cec5SDimitry Andric }
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric
shouldDump(SymbolicFile & Obj)168781ad6265SDimitry Andric static bool shouldDump(SymbolicFile &Obj) {
168881ad6265SDimitry Andric // The -X option is currently only implemented for XCOFF, ELF, and IR object
168981ad6265SDimitry Andric // files. The option isn't fundamentally impossible with other formats, just
169081ad6265SDimitry Andric // isn't implemented.
169181ad6265SDimitry Andric if (!isa<XCOFFObjectFile>(Obj) && !isa<ELFObjectFileBase>(Obj) &&
169281ad6265SDimitry Andric !isa<IRObjectFile>(Obj))
169381ad6265SDimitry Andric return true;
169481ad6265SDimitry Andric
169506c3fb27SDimitry Andric return Obj.is64Bit() ? BitMode != BitModeTy::Bit32
169681ad6265SDimitry Andric : BitMode != BitModeTy::Bit64;
169781ad6265SDimitry Andric }
169881ad6265SDimitry Andric
getXCOFFExports(XCOFFObjectFile * XCOFFObj,std::vector<NMSymbol> & SymbolList,StringRef ArchiveName)169981ad6265SDimitry Andric static void getXCOFFExports(XCOFFObjectFile *XCOFFObj,
170081ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList,
170181ad6265SDimitry Andric StringRef ArchiveName) {
170281ad6265SDimitry Andric // Skip Shared object file.
170381ad6265SDimitry Andric if (XCOFFObj->getFlags() & XCOFF::F_SHROBJ)
170481ad6265SDimitry Andric return;
170581ad6265SDimitry Andric
170681ad6265SDimitry Andric for (SymbolRef Sym : XCOFFObj->symbols()) {
170781ad6265SDimitry Andric // There is no visibility in old 32 bit XCOFF object file interpret.
170881ad6265SDimitry Andric bool HasVisibilityAttr =
170981ad6265SDimitry Andric XCOFFObj->is64Bit() || (XCOFFObj->auxiliaryHeader32() &&
171081ad6265SDimitry Andric (XCOFFObj->auxiliaryHeader32()->getVersion() ==
171181ad6265SDimitry Andric XCOFF::NEW_XCOFF_INTERPRET));
171281ad6265SDimitry Andric
171381ad6265SDimitry Andric if (HasVisibilityAttr) {
171481ad6265SDimitry Andric XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl());
171581ad6265SDimitry Andric uint16_t SymType = XCOFFSym.getSymbolType();
171681ad6265SDimitry Andric if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_INTERNAL)
171781ad6265SDimitry Andric continue;
171881ad6265SDimitry Andric if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_HIDDEN)
171981ad6265SDimitry Andric continue;
172081ad6265SDimitry Andric }
172181ad6265SDimitry Andric
172281ad6265SDimitry Andric Expected<section_iterator> SymSecOrErr = Sym.getSection();
172381ad6265SDimitry Andric if (!SymSecOrErr) {
172481ad6265SDimitry Andric warn(SymSecOrErr.takeError(), XCOFFObj->getFileName(),
172581ad6265SDimitry Andric "for symbol with index " +
172681ad6265SDimitry Andric Twine(XCOFFObj->getSymbolIndex(Sym.getRawDataRefImpl().p)),
172781ad6265SDimitry Andric ArchiveName);
172881ad6265SDimitry Andric continue;
172981ad6265SDimitry Andric }
173081ad6265SDimitry Andric section_iterator SecIter = *SymSecOrErr;
173181ad6265SDimitry Andric // If the symbol is not in a text or data section, it is not exported.
173281ad6265SDimitry Andric if (SecIter == XCOFFObj->section_end())
173381ad6265SDimitry Andric continue;
173481ad6265SDimitry Andric if (!(SecIter->isText() || SecIter->isData() || SecIter->isBSS()))
173581ad6265SDimitry Andric continue;
173681ad6265SDimitry Andric
173781ad6265SDimitry Andric StringRef SymName = cantFail(Sym.getName());
173881ad6265SDimitry Andric if (SymName.empty())
173981ad6265SDimitry Andric continue;
17405f757f3fSDimitry Andric if (SymName.starts_with("__sinit") || SymName.starts_with("__sterm") ||
174181ad6265SDimitry Andric SymName.front() == '.' || SymName.front() == '(')
174281ad6265SDimitry Andric continue;
174381ad6265SDimitry Andric
174481ad6265SDimitry Andric // Check the SymName regex matching with "^__[0-9]+__".
17455f757f3fSDimitry Andric if (SymName.size() > 4 && SymName.starts_with("__") &&
17465f757f3fSDimitry Andric SymName.ends_with("__")) {
174781ad6265SDimitry Andric if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit))
174881ad6265SDimitry Andric continue;
174981ad6265SDimitry Andric }
175081ad6265SDimitry Andric
175181ad6265SDimitry Andric if (SymName == "__rsrc" && NoRsrc)
175281ad6265SDimitry Andric continue;
175381ad6265SDimitry Andric
17545f757f3fSDimitry Andric if (SymName.starts_with("__tf1"))
175581ad6265SDimitry Andric SymName = SymName.substr(6);
17565f757f3fSDimitry Andric else if (SymName.starts_with("__tf9"))
175781ad6265SDimitry Andric SymName = SymName.substr(14);
175881ad6265SDimitry Andric
175981ad6265SDimitry Andric NMSymbol S = {};
176081ad6265SDimitry Andric S.Name = SymName.str();
176181ad6265SDimitry Andric S.Sym = Sym;
176281ad6265SDimitry Andric
176381ad6265SDimitry Andric if (HasVisibilityAttr) {
176481ad6265SDimitry Andric XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl());
176581ad6265SDimitry Andric uint16_t SymType = XCOFFSym.getSymbolType();
176681ad6265SDimitry Andric if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_PROTECTED)
176781ad6265SDimitry Andric S.Visibility = "protected";
176881ad6265SDimitry Andric else if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_EXPORTED)
176981ad6265SDimitry Andric S.Visibility = "export";
177081ad6265SDimitry Andric }
177181ad6265SDimitry Andric if (S.initializeFlags(*XCOFFObj))
177281ad6265SDimitry Andric SymbolList.push_back(S);
177381ad6265SDimitry Andric }
177481ad6265SDimitry Andric }
177581ad6265SDimitry Andric
177681ad6265SDimitry Andric static Expected<SymbolicFile::basic_symbol_iterator_range>
getDynamicSyms(SymbolicFile & Obj)177781ad6265SDimitry Andric getDynamicSyms(SymbolicFile &Obj) {
177881ad6265SDimitry Andric const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
177981ad6265SDimitry Andric if (!E)
178081ad6265SDimitry Andric return createError("File format has no dynamic symbol table");
178181ad6265SDimitry Andric return E->getDynamicSymbolIterators();
178281ad6265SDimitry Andric }
178381ad6265SDimitry Andric
178481ad6265SDimitry Andric // Returns false if there is error found or true otherwise.
getSymbolNamesFromObject(SymbolicFile & Obj,std::vector<NMSymbol> & SymbolList)178581ad6265SDimitry Andric static bool getSymbolNamesFromObject(SymbolicFile &Obj,
178681ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList) {
1787e8d8bef9SDimitry Andric auto Symbols = Obj.symbols();
1788349cc55cSDimitry Andric std::vector<VersionEntry> SymbolVersions;
1789e8d8bef9SDimitry Andric
179081ad6265SDimitry Andric if (DynamicSyms) {
179181ad6265SDimitry Andric Expected<SymbolicFile::basic_symbol_iterator_range> SymbolsOrErr =
179281ad6265SDimitry Andric getDynamicSyms(Obj);
179381ad6265SDimitry Andric if (!SymbolsOrErr) {
179481ad6265SDimitry Andric error(SymbolsOrErr.takeError(), Obj.getFileName());
179581ad6265SDimitry Andric return false;
179681ad6265SDimitry Andric }
179781ad6265SDimitry Andric Symbols = *SymbolsOrErr;
179881ad6265SDimitry Andric if (const auto *E = dyn_cast<ELFObjectFileBase>(&Obj)) {
1799349cc55cSDimitry Andric if (Expected<std::vector<VersionEntry>> VersionsOrErr =
1800349cc55cSDimitry Andric E->readDynsymVersions())
1801e8d8bef9SDimitry Andric SymbolVersions = std::move(*VersionsOrErr);
1802e8d8bef9SDimitry Andric else
1803e8d8bef9SDimitry Andric WithColor::warning(errs(), ToolName)
1804e8d8bef9SDimitry Andric << "unable to read symbol versions: "
1805e8d8bef9SDimitry Andric << toString(VersionsOrErr.takeError()) << "\n";
1806e8d8bef9SDimitry Andric }
180781ad6265SDimitry Andric }
1808e8d8bef9SDimitry Andric // If a "-s segname sectname" option was specified and this is a Mach-O
1809e8d8bef9SDimitry Andric // file get the section number for that section in this object file.
1810e8d8bef9SDimitry Andric unsigned int Nsect = 0;
1811e8d8bef9SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
1812e8d8bef9SDimitry Andric if (!SegSect.empty() && MachO) {
1813e8d8bef9SDimitry Andric Nsect = getNsectForSegSect(MachO);
1814e8d8bef9SDimitry Andric // If this section is not in the object file no symbols are printed.
1815e8d8bef9SDimitry Andric if (Nsect == 0)
181681ad6265SDimitry Andric return false;
1817e8d8bef9SDimitry Andric }
181881ad6265SDimitry Andric
1819e8d8bef9SDimitry Andric if (!(MachO && DyldInfoOnly)) {
1820e8d8bef9SDimitry Andric size_t I = -1;
1821e8d8bef9SDimitry Andric for (BasicSymbolRef Sym : Symbols) {
1822e8d8bef9SDimitry Andric ++I;
1823e8d8bef9SDimitry Andric Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
1824e8d8bef9SDimitry Andric if (!SymFlagsOrErr) {
1825e8d8bef9SDimitry Andric error(SymFlagsOrErr.takeError(), Obj.getFileName());
182681ad6265SDimitry Andric return false;
1827e8d8bef9SDimitry Andric }
1828fe6060f1SDimitry Andric
1829fe6060f1SDimitry Andric // Don't drop format specifc symbols for ARM and AArch64 ELF targets, they
1830fe6060f1SDimitry Andric // are used to repesent mapping symbols and needed to honor the
1831fe6060f1SDimitry Andric // --special-syms option.
1832fe6060f1SDimitry Andric auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj);
18335f757f3fSDimitry Andric bool HasMappingSymbol =
18345f757f3fSDimitry Andric ELFObj && llvm::is_contained({ELF::EM_ARM, ELF::EM_AARCH64,
18355f757f3fSDimitry Andric ELF::EM_CSKY, ELF::EM_RISCV},
18365f757f3fSDimitry Andric ELFObj->getEMachine());
18375f757f3fSDimitry Andric if (!HasMappingSymbol && !DebugSyms &&
18385f757f3fSDimitry Andric (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific))
1839e8d8bef9SDimitry Andric continue;
1840e8d8bef9SDimitry Andric if (WithoutAliases && (*SymFlagsOrErr & SymbolRef::SF_Indirect))
1841e8d8bef9SDimitry Andric continue;
1842e8d8bef9SDimitry Andric // If a "-s segname sectname" option was specified and this is a Mach-O
1843e8d8bef9SDimitry Andric // file and this section appears in this file, Nsect will be non-zero then
1844e8d8bef9SDimitry Andric // see if this symbol is a symbol from that section and if not skip it.
1845e8d8bef9SDimitry Andric if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
1846e8d8bef9SDimitry Andric continue;
1847e8d8bef9SDimitry Andric NMSymbol S = {};
1848e8d8bef9SDimitry Andric S.Size = 0;
1849e8d8bef9SDimitry Andric S.Address = 0;
1850e8d8bef9SDimitry Andric if (isa<ELFObjectFileBase>(&Obj))
1851e8d8bef9SDimitry Andric S.Size = ELFSymbolRef(Sym).getSize();
185204eeddc0SDimitry Andric
185304eeddc0SDimitry Andric if (const XCOFFObjectFile *XCOFFObj =
185404eeddc0SDimitry Andric dyn_cast<const XCOFFObjectFile>(&Obj))
185504eeddc0SDimitry Andric S.Size = XCOFFObj->getSymbolSize(Sym.getRawDataRefImpl());
185604eeddc0SDimitry Andric
18575f757f3fSDimitry Andric if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj)) {
18585f757f3fSDimitry Andric const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym);
18595f757f3fSDimitry Andric if (WasmSym.isTypeData() && !WasmSym.isUndefined())
18605f757f3fSDimitry Andric S.Size = WasmSym.Info.DataRef.Size;
18615f757f3fSDimitry Andric }
18625f757f3fSDimitry Andric
1863e8d8bef9SDimitry Andric if (PrintAddress && isa<ObjectFile>(Obj)) {
1864e8d8bef9SDimitry Andric SymbolRef SymRef(Sym);
1865e8d8bef9SDimitry Andric Expected<uint64_t> AddressOrErr = SymRef.getAddress();
1866e8d8bef9SDimitry Andric if (!AddressOrErr) {
1867e8d8bef9SDimitry Andric consumeError(AddressOrErr.takeError());
1868e8d8bef9SDimitry Andric break;
1869e8d8bef9SDimitry Andric }
1870e8d8bef9SDimitry Andric S.Address = *AddressOrErr;
1871e8d8bef9SDimitry Andric }
1872e8d8bef9SDimitry Andric S.TypeName = getNMTypeName(Obj, Sym);
1873e8d8bef9SDimitry Andric S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
1874e8d8bef9SDimitry Andric
1875e8d8bef9SDimitry Andric raw_string_ostream OS(S.Name);
1876e8d8bef9SDimitry Andric if (Error E = Sym.printName(OS)) {
1877e8d8bef9SDimitry Andric if (MachO) {
1878e8d8bef9SDimitry Andric OS << "bad string index";
1879e8d8bef9SDimitry Andric consumeError(std::move(E));
1880e8d8bef9SDimitry Andric } else
1881e8d8bef9SDimitry Andric error(std::move(E), Obj.getFileName());
1882e8d8bef9SDimitry Andric }
1883e8d8bef9SDimitry Andric if (!SymbolVersions.empty() && !SymbolVersions[I].Name.empty())
1884e8d8bef9SDimitry Andric S.Name +=
1885349cc55cSDimitry Andric (SymbolVersions[I].IsVerDef ? "@@" : "@") + SymbolVersions[I].Name;
1886e8d8bef9SDimitry Andric
1887e8d8bef9SDimitry Andric S.Sym = Sym;
188881ad6265SDimitry Andric if (S.initializeFlags(Obj))
1889e8d8bef9SDimitry Andric SymbolList.push_back(S);
1890e8d8bef9SDimitry Andric }
1891e8d8bef9SDimitry Andric }
1892e8d8bef9SDimitry Andric
1893e8d8bef9SDimitry Andric // If this is a Mach-O file where the nlist symbol table is out of sync
1894e8d8bef9SDimitry Andric // with the dyld export trie then look through exports and fake up symbols
1895e8d8bef9SDimitry Andric // for the ones that are missing (also done with the -add-dyldinfo flag).
1896e8d8bef9SDimitry Andric // This is needed if strip(1) -T is run on a binary containing swift
1897e8d8bef9SDimitry Andric // language symbols for example. The option -only-dyldinfo will fake up
1898e8d8bef9SDimitry Andric // all symbols from the dyld export trie as well as the bind info.
1899e8d8bef9SDimitry Andric if (MachO && !NoDyldInfo)
190081ad6265SDimitry Andric dumpSymbolsFromDLInfoMachO(*MachO, SymbolList);
1901e8d8bef9SDimitry Andric
190281ad6265SDimitry Andric return true;
190381ad6265SDimitry Andric }
190481ad6265SDimitry Andric
printObjectLabel(bool PrintArchiveName,StringRef ArchiveName,StringRef ArchitectureName,StringRef ObjectFileName)190581ad6265SDimitry Andric static void printObjectLabel(bool PrintArchiveName, StringRef ArchiveName,
190681ad6265SDimitry Andric StringRef ArchitectureName,
190781ad6265SDimitry Andric StringRef ObjectFileName) {
190881ad6265SDimitry Andric outs() << "\n";
190981ad6265SDimitry Andric if (ArchiveName.empty() || !PrintArchiveName)
191081ad6265SDimitry Andric outs() << ObjectFileName;
191181ad6265SDimitry Andric else
191281ad6265SDimitry Andric outs() << ArchiveName << "(" << ObjectFileName << ")";
191381ad6265SDimitry Andric if (!ArchitectureName.empty())
191481ad6265SDimitry Andric outs() << " (for architecture " << ArchitectureName << ")";
191581ad6265SDimitry Andric outs() << ":\n";
191681ad6265SDimitry Andric }
191781ad6265SDimitry Andric
hasSymbols(SymbolicFile & Obj)191881ad6265SDimitry Andric static Expected<bool> hasSymbols(SymbolicFile &Obj) {
191981ad6265SDimitry Andric if (DynamicSyms) {
192081ad6265SDimitry Andric Expected<SymbolicFile::basic_symbol_iterator_range> DynamicSymsOrErr =
192181ad6265SDimitry Andric getDynamicSyms(Obj);
192281ad6265SDimitry Andric if (!DynamicSymsOrErr)
192381ad6265SDimitry Andric return DynamicSymsOrErr.takeError();
192481ad6265SDimitry Andric return !DynamicSymsOrErr->empty();
192581ad6265SDimitry Andric }
192681ad6265SDimitry Andric return !Obj.symbols().empty();
192781ad6265SDimitry Andric }
192881ad6265SDimitry Andric
printSymbolNamesFromObject(SymbolicFile & Obj,std::vector<NMSymbol> & SymbolList,bool PrintSymbolObject,bool PrintObjectLabel,StringRef ArchiveName={},StringRef ArchitectureName={},StringRef ObjectName={},bool PrintArchiveName=true)19295f757f3fSDimitry Andric static void printSymbolNamesFromObject(
19305f757f3fSDimitry Andric SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList,
19315f757f3fSDimitry Andric bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {},
19325f757f3fSDimitry Andric StringRef ArchitectureName = {}, StringRef ObjectName = {},
19335f757f3fSDimitry Andric bool PrintArchiveName = true) {
19345f757f3fSDimitry Andric
19355f757f3fSDimitry Andric if (PrintObjectLabel && !ExportSymbols)
19365f757f3fSDimitry Andric printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName,
19375f757f3fSDimitry Andric ObjectName.empty() ? Obj.getFileName() : ObjectName);
19385f757f3fSDimitry Andric
19395f757f3fSDimitry Andric if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols)
19405f757f3fSDimitry Andric return;
19415f757f3fSDimitry Andric
19425f757f3fSDimitry Andric // If there is an error in hasSymbols(), the error should be encountered in
19435f757f3fSDimitry Andric // function getSymbolNamesFromObject first.
19445f757f3fSDimitry Andric if (!cantFail(hasSymbols(Obj)) && SymbolList.empty() && !Quiet) {
19455f757f3fSDimitry Andric writeFileName(errs(), ArchiveName, ArchitectureName);
19465f757f3fSDimitry Andric errs() << "no symbols\n";
19475f757f3fSDimitry Andric }
19485f757f3fSDimitry Andric
19495f757f3fSDimitry Andric sortSymbolList(SymbolList);
19505f757f3fSDimitry Andric printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName,
19515f757f3fSDimitry Andric ArchitectureName);
19525f757f3fSDimitry Andric }
19535f757f3fSDimitry Andric
dumpSymbolsNameFromMachOFilesetEntry(MachOObjectFile * Obj,std::vector<NMSymbol> & SymbolList,bool PrintSymbolObject,bool PrintObjectLabel)19545f757f3fSDimitry Andric static void dumpSymbolsNameFromMachOFilesetEntry(
19555f757f3fSDimitry Andric MachOObjectFile *Obj, std::vector<NMSymbol> &SymbolList,
19565f757f3fSDimitry Andric bool PrintSymbolObject, bool PrintObjectLabel) {
19575f757f3fSDimitry Andric auto Buf = Obj->getMemoryBufferRef();
19585f757f3fSDimitry Andric const auto *End = Obj->load_commands().end();
19595f757f3fSDimitry Andric for (const auto *It = Obj->load_commands().begin(); It != End; ++It) {
19605f757f3fSDimitry Andric const auto &Command = *It;
19615f757f3fSDimitry Andric if (Command.C.cmd != MachO::LC_FILESET_ENTRY)
19625f757f3fSDimitry Andric continue;
19635f757f3fSDimitry Andric
19645f757f3fSDimitry Andric MachO::fileset_entry_command Entry =
19655f757f3fSDimitry Andric Obj->getFilesetEntryLoadCommand(Command);
19665f757f3fSDimitry Andric auto MaybeMachO =
19675f757f3fSDimitry Andric MachOObjectFile::createMachOObjectFile(Buf, 0, 0, Entry.fileoff);
19685f757f3fSDimitry Andric
19695f757f3fSDimitry Andric if (Error Err = MaybeMachO.takeError())
19705f757f3fSDimitry Andric report_fatal_error(std::move(Err));
19715f757f3fSDimitry Andric
19725f757f3fSDimitry Andric const char *EntryName = Command.Ptr + Entry.entry_id.offset;
19735f757f3fSDimitry Andric if (EntryName)
19745f757f3fSDimitry Andric outs() << "Symbols for " << EntryName << ": \n";
19755f757f3fSDimitry Andric
19765f757f3fSDimitry Andric std::unique_ptr<MachOObjectFile> EntryMachO = std::move(MaybeMachO.get());
19775f757f3fSDimitry Andric printSymbolNamesFromObject(*EntryMachO, SymbolList, PrintSymbolObject,
19785f757f3fSDimitry Andric PrintObjectLabel);
19795f757f3fSDimitry Andric
19805f757f3fSDimitry Andric if (std::next(It) != End)
19815f757f3fSDimitry Andric outs() << "\n";
19825f757f3fSDimitry Andric }
19835f757f3fSDimitry Andric }
19845f757f3fSDimitry Andric
dumpSymbolNamesFromObject(SymbolicFile & Obj,std::vector<NMSymbol> & SymbolList,bool PrintSymbolObject,bool PrintObjectLabel,StringRef ArchiveName={},StringRef ArchitectureName={},StringRef ObjectName={},bool PrintArchiveName=true)198581ad6265SDimitry Andric static void dumpSymbolNamesFromObject(
198681ad6265SDimitry Andric SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList,
198781ad6265SDimitry Andric bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {},
198881ad6265SDimitry Andric StringRef ArchitectureName = {}, StringRef ObjectName = {},
198981ad6265SDimitry Andric bool PrintArchiveName = true) {
199081ad6265SDimitry Andric if (!shouldDump(Obj))
199181ad6265SDimitry Andric return;
199281ad6265SDimitry Andric
199381ad6265SDimitry Andric if (ExportSymbols && Obj.isXCOFF()) {
199481ad6265SDimitry Andric XCOFFObjectFile *XCOFFObj = cast<XCOFFObjectFile>(&Obj);
199581ad6265SDimitry Andric getXCOFFExports(XCOFFObj, SymbolList, ArchiveName);
199681ad6265SDimitry Andric return;
199781ad6265SDimitry Andric }
199881ad6265SDimitry Andric
19990b57cec5SDimitry Andric CurrentFilename = Obj.getFileName();
20005ffd83dbSDimitry Andric
20015f757f3fSDimitry Andric // Are we handling a MachO of type MH_FILESET?
20025f757f3fSDimitry Andric if (Obj.isMachO() && Obj.is64Bit() &&
20035f757f3fSDimitry Andric cast<MachOObjectFile>(&Obj)->getHeader64().filetype ==
20045f757f3fSDimitry Andric MachO::MH_FILESET) {
20055f757f3fSDimitry Andric dumpSymbolsNameFromMachOFilesetEntry(cast<MachOObjectFile>(&Obj),
20065f757f3fSDimitry Andric SymbolList, PrintSymbolObject,
20075f757f3fSDimitry Andric PrintObjectLabel);
20085f757f3fSDimitry Andric return;
20095ffd83dbSDimitry Andric }
20105ffd83dbSDimitry Andric
20115f757f3fSDimitry Andric printSymbolNamesFromObject(Obj, SymbolList, PrintSymbolObject,
20125f757f3fSDimitry Andric PrintObjectLabel, ArchiveName, ArchitectureName,
20135f757f3fSDimitry Andric ObjectName, PrintArchiveName);
20140b57cec5SDimitry Andric }
20150b57cec5SDimitry Andric
20160b57cec5SDimitry Andric // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
20170b57cec5SDimitry Andric // and if it is and there is a list of architecture flags is specified then
20180b57cec5SDimitry Andric // check to make sure this Mach-O file is one of those architectures or all
20190b57cec5SDimitry Andric // architectures was specificed. If not then an error is generated and this
20200b57cec5SDimitry Andric // routine returns false. Else it returns true.
checkMachOAndArchFlags(SymbolicFile * O,StringRef Filename)202181ad6265SDimitry Andric static bool checkMachOAndArchFlags(SymbolicFile *O, StringRef Filename) {
20220b57cec5SDimitry Andric auto *MachO = dyn_cast<MachOObjectFile>(O);
20230b57cec5SDimitry Andric
20240b57cec5SDimitry Andric if (!MachO || ArchAll || ArchFlags.empty())
20250b57cec5SDimitry Andric return true;
20260b57cec5SDimitry Andric
20270b57cec5SDimitry Andric MachO::mach_header H;
20280b57cec5SDimitry Andric MachO::mach_header_64 H_64;
20290b57cec5SDimitry Andric Triple T;
20300b57cec5SDimitry Andric const char *McpuDefault, *ArchFlag;
20310b57cec5SDimitry Andric if (MachO->is64Bit()) {
20320b57cec5SDimitry Andric H_64 = MachO->MachOObjectFile::getHeader64();
20330b57cec5SDimitry Andric T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
20340b57cec5SDimitry Andric &McpuDefault, &ArchFlag);
20350b57cec5SDimitry Andric } else {
20360b57cec5SDimitry Andric H = MachO->MachOObjectFile::getHeader();
20370b57cec5SDimitry Andric T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
20380b57cec5SDimitry Andric &McpuDefault, &ArchFlag);
20390b57cec5SDimitry Andric }
20400b57cec5SDimitry Andric const std::string ArchFlagName(ArchFlag);
2041e8d8bef9SDimitry Andric if (!llvm::is_contained(ArchFlags, ArchFlagName)) {
20420b57cec5SDimitry Andric error("No architecture specified", Filename);
20430b57cec5SDimitry Andric return false;
20440b57cec5SDimitry Andric }
20450b57cec5SDimitry Andric return true;
20460b57cec5SDimitry Andric }
20470b57cec5SDimitry Andric
printArchiveMap(iterator_range<Archive::symbol_iterator> & map,StringRef Filename)204806c3fb27SDimitry Andric static void printArchiveMap(iterator_range<Archive::symbol_iterator> &map,
204906c3fb27SDimitry Andric StringRef Filename) {
205006c3fb27SDimitry Andric for (auto I : map) {
205106c3fb27SDimitry Andric Expected<Archive::Child> C = I.getMember();
20520b57cec5SDimitry Andric if (!C) {
20530b57cec5SDimitry Andric error(C.takeError(), Filename);
20540b57cec5SDimitry Andric break;
20550b57cec5SDimitry Andric }
20560b57cec5SDimitry Andric Expected<StringRef> FileNameOrErr = C->getName();
20570b57cec5SDimitry Andric if (!FileNameOrErr) {
20580b57cec5SDimitry Andric error(FileNameOrErr.takeError(), Filename);
20590b57cec5SDimitry Andric break;
20600b57cec5SDimitry Andric }
206106c3fb27SDimitry Andric StringRef SymName = I.getName();
20620b57cec5SDimitry Andric outs() << SymName << " in " << FileNameOrErr.get() << "\n";
20630b57cec5SDimitry Andric }
206406c3fb27SDimitry Andric
20650b57cec5SDimitry Andric outs() << "\n";
20660b57cec5SDimitry Andric }
206706c3fb27SDimitry Andric
dumpArchiveMap(Archive * A,StringRef Filename)206806c3fb27SDimitry Andric static void dumpArchiveMap(Archive *A, StringRef Filename) {
206906c3fb27SDimitry Andric auto Map = A->symbols();
207006c3fb27SDimitry Andric if (!Map.empty()) {
207106c3fb27SDimitry Andric outs() << "Archive map\n";
207206c3fb27SDimitry Andric printArchiveMap(Map, Filename);
207306c3fb27SDimitry Andric }
207406c3fb27SDimitry Andric
207506c3fb27SDimitry Andric auto ECMap = A->ec_symbols();
207606c3fb27SDimitry Andric if (!ECMap) {
207706c3fb27SDimitry Andric warn(ECMap.takeError(), Filename);
207806c3fb27SDimitry Andric } else if (!ECMap->empty()) {
207906c3fb27SDimitry Andric outs() << "Archive EC map\n";
208006c3fb27SDimitry Andric printArchiveMap(*ECMap, Filename);
208106c3fb27SDimitry Andric }
20820b57cec5SDimitry Andric }
20830b57cec5SDimitry Andric
dumpArchive(Archive * A,std::vector<NMSymbol> & SymbolList,StringRef Filename,LLVMContext * ContextPtr)208481ad6265SDimitry Andric static void dumpArchive(Archive *A, std::vector<NMSymbol> &SymbolList,
208581ad6265SDimitry Andric StringRef Filename, LLVMContext *ContextPtr) {
208681ad6265SDimitry Andric if (ArchiveMap)
208781ad6265SDimitry Andric dumpArchiveMap(A, Filename);
208881ad6265SDimitry Andric
20890b57cec5SDimitry Andric Error Err = Error::success();
20900b57cec5SDimitry Andric for (auto &C : A->children(Err)) {
209181ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(ContextPtr);
20920b57cec5SDimitry Andric if (!ChildOrErr) {
20930b57cec5SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
20940b57cec5SDimitry Andric error(std::move(E), Filename, C);
20950b57cec5SDimitry Andric continue;
20960b57cec5SDimitry Andric }
20970b57cec5SDimitry Andric if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
20980b57cec5SDimitry Andric if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
20990b57cec5SDimitry Andric WithColor::warning(errs(), ToolName)
21000b57cec5SDimitry Andric << "sizes with -print-size for Mach-O files are always zero.\n";
21010b57cec5SDimitry Andric MachOPrintSizeWarning = true;
21020b57cec5SDimitry Andric }
21030b57cec5SDimitry Andric if (!checkMachOAndArchFlags(O, Filename))
21040b57cec5SDimitry Andric return;
210581ad6265SDimitry Andric dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/false,
210681ad6265SDimitry Andric !PrintFileName, Filename,
210781ad6265SDimitry Andric /*ArchitectureName=*/{}, O->getFileName(),
210881ad6265SDimitry Andric /*PrintArchiveName=*/false);
21090b57cec5SDimitry Andric }
21100b57cec5SDimitry Andric }
21110b57cec5SDimitry Andric if (Err)
21120b57cec5SDimitry Andric error(std::move(Err), A->getFileName());
21130b57cec5SDimitry Andric }
211481ad6265SDimitry Andric
dumpMachOUniversalBinaryMatchArchFlags(MachOUniversalBinary * UB,std::vector<NMSymbol> & SymbolList,StringRef Filename,LLVMContext * ContextPtr)211581ad6265SDimitry Andric static void dumpMachOUniversalBinaryMatchArchFlags(
211681ad6265SDimitry Andric MachOUniversalBinary *UB, std::vector<NMSymbol> &SymbolList,
211781ad6265SDimitry Andric StringRef Filename, LLVMContext *ContextPtr) {
21180b57cec5SDimitry Andric // Look for a slice in the universal binary that matches each ArchFlag.
21190b57cec5SDimitry Andric bool ArchFound;
21200b57cec5SDimitry Andric for (unsigned i = 0; i < ArchFlags.size(); ++i) {
21210b57cec5SDimitry Andric ArchFound = false;
21220b57cec5SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
21230b57cec5SDimitry Andric E = UB->end_objects();
21240b57cec5SDimitry Andric I != E; ++I) {
21250b57cec5SDimitry Andric if (ArchFlags[i] == I->getArchFlagName()) {
21260b57cec5SDimitry Andric ArchFound = true;
212781ad6265SDimitry Andric Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
21280b57cec5SDimitry Andric std::string ArchiveName;
21290b57cec5SDimitry Andric std::string ArchitectureName;
21300b57cec5SDimitry Andric ArchiveName.clear();
21310b57cec5SDimitry Andric ArchitectureName.clear();
21320b57cec5SDimitry Andric if (ObjOrErr) {
21330b57cec5SDimitry Andric ObjectFile &Obj = *ObjOrErr.get();
213481ad6265SDimitry Andric if (ArchFlags.size() > 1)
21350b57cec5SDimitry Andric ArchitectureName = I->getArchFlagName();
213681ad6265SDimitry Andric dumpSymbolNamesFromObject(Obj, SymbolList,
213781ad6265SDimitry Andric /*PrintSymbolObject=*/false,
213881ad6265SDimitry Andric (ArchFlags.size() > 1) && !PrintFileName,
213981ad6265SDimitry Andric ArchiveName, ArchitectureName);
214081ad6265SDimitry Andric } else if (auto E =
214181ad6265SDimitry Andric isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
214281ad6265SDimitry Andric error(std::move(E), Filename,
214381ad6265SDimitry Andric ArchFlags.size() > 1 ? StringRef(I->getArchFlagName())
214481ad6265SDimitry Andric : StringRef());
21450b57cec5SDimitry Andric continue;
21460b57cec5SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr =
21470b57cec5SDimitry Andric I->getAsArchive()) {
21480b57cec5SDimitry Andric std::unique_ptr<Archive> &A = *AOrErr;
21490b57cec5SDimitry Andric Error Err = Error::success();
21500b57cec5SDimitry Andric for (auto &C : A->children(Err)) {
21510b57cec5SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr =
21520b57cec5SDimitry Andric C.getAsBinary(ContextPtr);
21530b57cec5SDimitry Andric if (!ChildOrErr) {
215481ad6265SDimitry Andric if (auto E =
215581ad6265SDimitry Andric isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
215681ad6265SDimitry Andric error(std::move(E), Filename, C,
215781ad6265SDimitry Andric ArchFlags.size() > 1 ? StringRef(I->getArchFlagName())
215881ad6265SDimitry Andric : StringRef());
21590b57cec5SDimitry Andric }
21600b57cec5SDimitry Andric continue;
21610b57cec5SDimitry Andric }
216281ad6265SDimitry Andric if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
21635ffd83dbSDimitry Andric ArchiveName = std::string(A->getFileName());
21640b57cec5SDimitry Andric if (ArchFlags.size() > 1)
21650b57cec5SDimitry Andric ArchitectureName = I->getArchFlagName();
216681ad6265SDimitry Andric dumpSymbolNamesFromObject(
216781ad6265SDimitry Andric *O, SymbolList, /*PrintSymbolObject=*/false, !PrintFileName,
216881ad6265SDimitry Andric ArchiveName, ArchitectureName);
21690b57cec5SDimitry Andric }
21700b57cec5SDimitry Andric }
21710b57cec5SDimitry Andric if (Err)
21720b57cec5SDimitry Andric error(std::move(Err), A->getFileName());
21730b57cec5SDimitry Andric } else {
21740b57cec5SDimitry Andric consumeError(AOrErr.takeError());
21750b57cec5SDimitry Andric error(Filename + " for architecture " +
21760b57cec5SDimitry Andric StringRef(I->getArchFlagName()) +
21770b57cec5SDimitry Andric " is not a Mach-O file or an archive file",
21780b57cec5SDimitry Andric "Mach-O universal file");
21790b57cec5SDimitry Andric }
21800b57cec5SDimitry Andric }
21810b57cec5SDimitry Andric }
21820b57cec5SDimitry Andric if (!ArchFound) {
21830b57cec5SDimitry Andric error(ArchFlags[i],
21840b57cec5SDimitry Andric "file: " + Filename + " does not contain architecture");
21850b57cec5SDimitry Andric return;
21860b57cec5SDimitry Andric }
21870b57cec5SDimitry Andric }
21880b57cec5SDimitry Andric }
218981ad6265SDimitry Andric
219081ad6265SDimitry Andric // Returns true If the binary contains a slice that matches the host
219181ad6265SDimitry Andric // architecture, or false otherwise.
dumpMachOUniversalBinaryMatchHost(MachOUniversalBinary * UB,std::vector<NMSymbol> & SymbolList,StringRef Filename,LLVMContext * ContextPtr)219281ad6265SDimitry Andric static bool dumpMachOUniversalBinaryMatchHost(MachOUniversalBinary *UB,
219381ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList,
219481ad6265SDimitry Andric StringRef Filename,
219581ad6265SDimitry Andric LLVMContext *ContextPtr) {
21960b57cec5SDimitry Andric Triple HostTriple = MachOObjectFile::getHostArch();
21970b57cec5SDimitry Andric StringRef HostArchName = HostTriple.getArchName();
21980b57cec5SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
21990b57cec5SDimitry Andric E = UB->end_objects();
22000b57cec5SDimitry Andric I != E; ++I) {
22010b57cec5SDimitry Andric if (HostArchName == I->getArchFlagName()) {
22020b57cec5SDimitry Andric Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
22030b57cec5SDimitry Andric std::string ArchiveName;
22040b57cec5SDimitry Andric if (ObjOrErr) {
22050b57cec5SDimitry Andric ObjectFile &Obj = *ObjOrErr.get();
220681ad6265SDimitry Andric dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false,
220781ad6265SDimitry Andric /*PrintObjectLabel=*/false);
220881ad6265SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
22090b57cec5SDimitry Andric error(std::move(E), Filename);
221081ad6265SDimitry Andric else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
22110b57cec5SDimitry Andric std::unique_ptr<Archive> &A = *AOrErr;
22120b57cec5SDimitry Andric Error Err = Error::success();
22130b57cec5SDimitry Andric for (auto &C : A->children(Err)) {
22140b57cec5SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr =
22150b57cec5SDimitry Andric C.getAsBinary(ContextPtr);
22160b57cec5SDimitry Andric if (!ChildOrErr) {
221781ad6265SDimitry Andric if (auto E =
221881ad6265SDimitry Andric isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
22190b57cec5SDimitry Andric error(std::move(E), Filename, C);
22200b57cec5SDimitry Andric continue;
22210b57cec5SDimitry Andric }
222281ad6265SDimitry Andric if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
22235ffd83dbSDimitry Andric ArchiveName = std::string(A->getFileName());
222481ad6265SDimitry Andric dumpSymbolNamesFromObject(*O, SymbolList,
222581ad6265SDimitry Andric /*PrintSymbolObject=*/false,
222681ad6265SDimitry Andric !PrintFileName, ArchiveName);
22270b57cec5SDimitry Andric }
22280b57cec5SDimitry Andric }
22290b57cec5SDimitry Andric if (Err)
22300b57cec5SDimitry Andric error(std::move(Err), A->getFileName());
22310b57cec5SDimitry Andric } else {
22320b57cec5SDimitry Andric consumeError(AOrErr.takeError());
22330b57cec5SDimitry Andric error(Filename + " for architecture " +
22340b57cec5SDimitry Andric StringRef(I->getArchFlagName()) +
22350b57cec5SDimitry Andric " is not a Mach-O file or an archive file",
22360b57cec5SDimitry Andric "Mach-O universal file");
22370b57cec5SDimitry Andric }
223881ad6265SDimitry Andric return true;
22390b57cec5SDimitry Andric }
22400b57cec5SDimitry Andric }
224181ad6265SDimitry Andric return false;
22420b57cec5SDimitry Andric }
224381ad6265SDimitry Andric
dumpMachOUniversalBinaryArchAll(MachOUniversalBinary * UB,std::vector<NMSymbol> & SymbolList,StringRef Filename,LLVMContext * ContextPtr)224481ad6265SDimitry Andric static void dumpMachOUniversalBinaryArchAll(MachOUniversalBinary *UB,
224581ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList,
224681ad6265SDimitry Andric StringRef Filename,
224781ad6265SDimitry Andric LLVMContext *ContextPtr) {
22480b57cec5SDimitry Andric bool moreThanOneArch = UB->getNumberOfObjects() > 1;
22490b57cec5SDimitry Andric for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
22500b57cec5SDimitry Andric Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
22510b57cec5SDimitry Andric std::string ArchiveName;
22520b57cec5SDimitry Andric std::string ArchitectureName;
22530b57cec5SDimitry Andric ArchiveName.clear();
22540b57cec5SDimitry Andric ArchitectureName.clear();
22550b57cec5SDimitry Andric if (ObjOrErr) {
22560b57cec5SDimitry Andric ObjectFile &Obj = *ObjOrErr.get();
22570b57cec5SDimitry Andric if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
22580b57cec5SDimitry Andric ArchitectureName = O.getArchFlagName();
225981ad6265SDimitry Andric dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false,
226081ad6265SDimitry Andric !PrintFileName, ArchiveName, ArchitectureName);
226181ad6265SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
226281ad6265SDimitry Andric error(std::move(E), Filename,
226381ad6265SDimitry Andric moreThanOneArch ? StringRef(O.getArchFlagName()) : StringRef());
22640b57cec5SDimitry Andric continue;
226581ad6265SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = O.getAsArchive()) {
22660b57cec5SDimitry Andric std::unique_ptr<Archive> &A = *AOrErr;
22670b57cec5SDimitry Andric Error Err = Error::success();
22680b57cec5SDimitry Andric for (auto &C : A->children(Err)) {
22690b57cec5SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr =
22700b57cec5SDimitry Andric C.getAsBinary(ContextPtr);
22710b57cec5SDimitry Andric if (!ChildOrErr) {
227281ad6265SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
227381ad6265SDimitry Andric error(std::move(E), Filename, C,
227481ad6265SDimitry Andric moreThanOneArch ? StringRef(ArchitectureName) : StringRef());
22750b57cec5SDimitry Andric continue;
22760b57cec5SDimitry Andric }
22770b57cec5SDimitry Andric if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
22785ffd83dbSDimitry Andric ArchiveName = std::string(A->getFileName());
22790b57cec5SDimitry Andric if (isa<MachOObjectFile>(F) && moreThanOneArch)
22800b57cec5SDimitry Andric ArchitectureName = O.getArchFlagName();
228181ad6265SDimitry Andric dumpSymbolNamesFromObject(*F, SymbolList, /*PrintSymbolObject=*/false,
228281ad6265SDimitry Andric !PrintFileName, ArchiveName,
228381ad6265SDimitry Andric ArchitectureName);
22840b57cec5SDimitry Andric }
22850b57cec5SDimitry Andric }
22860b57cec5SDimitry Andric if (Err)
22870b57cec5SDimitry Andric error(std::move(Err), A->getFileName());
22880b57cec5SDimitry Andric } else {
22890b57cec5SDimitry Andric consumeError(AOrErr.takeError());
229081ad6265SDimitry Andric error(Filename + " for architecture " + StringRef(O.getArchFlagName()) +
22910b57cec5SDimitry Andric " is not a Mach-O file or an archive file",
22920b57cec5SDimitry Andric "Mach-O universal file");
22930b57cec5SDimitry Andric }
22940b57cec5SDimitry Andric }
229581ad6265SDimitry Andric }
229681ad6265SDimitry Andric
dumpMachOUniversalBinary(MachOUniversalBinary * UB,std::vector<NMSymbol> & SymbolList,StringRef Filename,LLVMContext * ContextPtr)229781ad6265SDimitry Andric static void dumpMachOUniversalBinary(MachOUniversalBinary *UB,
229881ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList,
229981ad6265SDimitry Andric StringRef Filename,
230081ad6265SDimitry Andric LLVMContext *ContextPtr) {
230181ad6265SDimitry Andric // If we have a list of architecture flags specified dump only those.
230281ad6265SDimitry Andric if (!ArchAll && !ArchFlags.empty()) {
230381ad6265SDimitry Andric dumpMachOUniversalBinaryMatchArchFlags(UB, SymbolList, Filename,
230481ad6265SDimitry Andric ContextPtr);
23050b57cec5SDimitry Andric return;
23060b57cec5SDimitry Andric }
23075ffd83dbSDimitry Andric
230881ad6265SDimitry Andric // No architecture flags were specified so if this contains a slice that
230981ad6265SDimitry Andric // matches the host architecture dump only that.
231081ad6265SDimitry Andric if (!ArchAll &&
231181ad6265SDimitry Andric dumpMachOUniversalBinaryMatchHost(UB, SymbolList, Filename, ContextPtr))
231281ad6265SDimitry Andric return;
231381ad6265SDimitry Andric
231481ad6265SDimitry Andric // Either all architectures have been specified or none have been specified
231581ad6265SDimitry Andric // and this does not contain the host architecture so dump all the slices.
231681ad6265SDimitry Andric dumpMachOUniversalBinaryArchAll(UB, SymbolList, Filename, ContextPtr);
231781ad6265SDimitry Andric }
231881ad6265SDimitry Andric
dumpTapiUniversal(TapiUniversal * TU,std::vector<NMSymbol> & SymbolList,StringRef Filename)231981ad6265SDimitry Andric static void dumpTapiUniversal(TapiUniversal *TU,
232081ad6265SDimitry Andric std::vector<NMSymbol> &SymbolList,
232181ad6265SDimitry Andric StringRef Filename) {
23225ffd83dbSDimitry Andric for (const TapiUniversal::ObjectForArch &I : TU->objects()) {
23235ffd83dbSDimitry Andric StringRef ArchName = I.getArchFlagName();
23245ffd83dbSDimitry Andric const bool ShowArch =
2325e8d8bef9SDimitry Andric ArchFlags.empty() || llvm::is_contained(ArchFlags, ArchName);
23265ffd83dbSDimitry Andric if (!ShowArch)
23275ffd83dbSDimitry Andric continue;
23285ffd83dbSDimitry Andric if (!AddInlinedInfo && !I.isTopLevelLib())
23295ffd83dbSDimitry Andric continue;
233081ad6265SDimitry Andric if (auto ObjOrErr = I.getAsObjectFile())
233181ad6265SDimitry Andric dumpSymbolNamesFromObject(
233281ad6265SDimitry Andric *ObjOrErr.get(), SymbolList, /*PrintSymbolObject=*/false,
233381ad6265SDimitry Andric /*PrintObjectLabel=*/true,
233481ad6265SDimitry Andric /*ArchiveName=*/{}, ArchName, I.getInstallName());
233581ad6265SDimitry Andric else if (Error E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
23365ffd83dbSDimitry Andric error(std::move(E), Filename, ArchName);
23375ffd83dbSDimitry Andric }
23385ffd83dbSDimitry Andric }
23395ffd83dbSDimitry Andric }
23405ffd83dbSDimitry Andric
dumpSymbolicFile(SymbolicFile * O,std::vector<NMSymbol> & SymbolList,StringRef Filename)234181ad6265SDimitry Andric static void dumpSymbolicFile(SymbolicFile *O, std::vector<NMSymbol> &SymbolList,
234281ad6265SDimitry Andric StringRef Filename) {
23430b57cec5SDimitry Andric if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
23440b57cec5SDimitry Andric WithColor::warning(errs(), ToolName)
23450b57cec5SDimitry Andric << "sizes with --print-size for Mach-O files are always zero.\n";
23460b57cec5SDimitry Andric MachOPrintSizeWarning = true;
23470b57cec5SDimitry Andric }
23480b57cec5SDimitry Andric if (!checkMachOAndArchFlags(O, Filename))
23490b57cec5SDimitry Andric return;
235081ad6265SDimitry Andric dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/true,
235181ad6265SDimitry Andric /*PrintObjectLabel=*/false);
23520b57cec5SDimitry Andric }
235381ad6265SDimitry Andric
dumpSymbolNamesFromFile(StringRef Filename)235481ad6265SDimitry Andric static std::vector<NMSymbol> dumpSymbolNamesFromFile(StringRef Filename) {
235581ad6265SDimitry Andric std::vector<NMSymbol> SymbolList;
235681ad6265SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
235781ad6265SDimitry Andric MemoryBuffer::getFileOrSTDIN(Filename);
235881ad6265SDimitry Andric if (error(BufferOrErr.getError(), Filename))
235981ad6265SDimitry Andric return SymbolList;
236081ad6265SDimitry Andric
23615f757f3fSDimitry Andric // Ignore AIX linker import files (these files start with "#!"), when
23625f757f3fSDimitry Andric // exporting symbols.
23635f757f3fSDimitry Andric const char *BuffStart = (*BufferOrErr)->getBufferStart();
23645f757f3fSDimitry Andric size_t BufferSize = (*BufferOrErr)->getBufferSize();
23655f757f3fSDimitry Andric if (ExportSymbols && BufferSize >= 2 && BuffStart[0] == '#' &&
23665f757f3fSDimitry Andric BuffStart[1] == '!')
23675f757f3fSDimitry Andric return SymbolList;
23685f757f3fSDimitry Andric
236981ad6265SDimitry Andric LLVMContext Context;
237081ad6265SDimitry Andric LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
237181ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> BinaryOrErr =
237281ad6265SDimitry Andric createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
237381ad6265SDimitry Andric if (!BinaryOrErr) {
237481ad6265SDimitry Andric error(BinaryOrErr.takeError(), Filename);
237581ad6265SDimitry Andric return SymbolList;
237681ad6265SDimitry Andric }
237781ad6265SDimitry Andric Binary &Bin = *BinaryOrErr.get();
237881ad6265SDimitry Andric if (Archive *A = dyn_cast<Archive>(&Bin))
237981ad6265SDimitry Andric dumpArchive(A, SymbolList, Filename, ContextPtr);
238081ad6265SDimitry Andric else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
238181ad6265SDimitry Andric dumpMachOUniversalBinary(UB, SymbolList, Filename, ContextPtr);
238281ad6265SDimitry Andric else if (TapiUniversal *TU = dyn_cast<TapiUniversal>(&Bin))
238381ad6265SDimitry Andric dumpTapiUniversal(TU, SymbolList, Filename);
238481ad6265SDimitry Andric else if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin))
238581ad6265SDimitry Andric dumpSymbolicFile(O, SymbolList, Filename);
238681ad6265SDimitry Andric return SymbolList;
238781ad6265SDimitry Andric }
238881ad6265SDimitry Andric
238981ad6265SDimitry Andric static void
exportSymbolNamesFromFiles(const std::vector<std::string> & InputFilenames)239081ad6265SDimitry Andric exportSymbolNamesFromFiles(const std::vector<std::string> &InputFilenames) {
239181ad6265SDimitry Andric std::vector<NMSymbol> SymbolList;
239281ad6265SDimitry Andric for (const auto &FileName : InputFilenames) {
239381ad6265SDimitry Andric std::vector<NMSymbol> FileSymList = dumpSymbolNamesFromFile(FileName);
239481ad6265SDimitry Andric SymbolList.insert(SymbolList.end(), FileSymList.begin(), FileSymList.end());
239581ad6265SDimitry Andric }
239681ad6265SDimitry Andric
239781ad6265SDimitry Andric // Delete symbols which should not be printed from SymolList.
2398bdd1243dSDimitry Andric llvm::erase_if(SymbolList,
2399bdd1243dSDimitry Andric [](const NMSymbol &s) { return !s.shouldPrint(); });
240081ad6265SDimitry Andric sortSymbolList(SymbolList);
240181ad6265SDimitry Andric SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()),
240281ad6265SDimitry Andric SymbolList.end());
240381ad6265SDimitry Andric printExportSymbolList(SymbolList);
24040b57cec5SDimitry Andric }
24050b57cec5SDimitry Andric
llvm_nm_main(int argc,char ** argv,const llvm::ToolContext &)240606c3fb27SDimitry Andric int llvm_nm_main(int argc, char **argv, const llvm::ToolContext &) {
2407fe6060f1SDimitry Andric BumpPtrAllocator A;
2408fe6060f1SDimitry Andric StringSaver Saver(A);
2409fe6060f1SDimitry Andric NmOptTable Tbl;
2410fe6060f1SDimitry Andric ToolName = argv[0];
2411fe6060f1SDimitry Andric opt::InputArgList Args =
2412fe6060f1SDimitry Andric Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
2413fe6060f1SDimitry Andric error(Msg);
2414fe6060f1SDimitry Andric exit(1);
2415fe6060f1SDimitry Andric });
2416fe6060f1SDimitry Andric if (Args.hasArg(OPT_help)) {
2417fe6060f1SDimitry Andric Tbl.printHelp(
2418fe6060f1SDimitry Andric outs(),
2419fe6060f1SDimitry Andric (Twine(ToolName) + " [options] <input object files>").str().c_str(),
2420fe6060f1SDimitry Andric "LLVM symbol table dumper");
2421fe6060f1SDimitry Andric // TODO Replace this with OptTable API once it adds extrahelp support.
2422fe6060f1SDimitry Andric outs() << "\nPass @FILE as argument to read options from FILE.\n";
2423fe6060f1SDimitry Andric return 0;
2424fe6060f1SDimitry Andric }
2425fe6060f1SDimitry Andric if (Args.hasArg(OPT_version)) {
2426fe6060f1SDimitry Andric // This needs to contain the word "GNU", libtool looks for that string.
2427fe6060f1SDimitry Andric outs() << "llvm-nm, compatible with GNU nm" << '\n';
2428fe6060f1SDimitry Andric cl::PrintVersionMessage();
2429fe6060f1SDimitry Andric return 0;
2430fe6060f1SDimitry Andric }
2431fe6060f1SDimitry Andric
2432fe6060f1SDimitry Andric DebugSyms = Args.hasArg(OPT_debug_syms);
2433fe6060f1SDimitry Andric DefinedOnly = Args.hasArg(OPT_defined_only);
2434fe6060f1SDimitry Andric Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
2435fe6060f1SDimitry Andric DynamicSyms = Args.hasArg(OPT_dynamic);
2436fe6060f1SDimitry Andric ExternalOnly = Args.hasArg(OPT_extern_only);
2437fe6060f1SDimitry Andric StringRef V = Args.getLastArgValue(OPT_format_EQ, "bsd");
2438fe6060f1SDimitry Andric if (V == "bsd")
2439fe6060f1SDimitry Andric OutputFormat = bsd;
2440fe6060f1SDimitry Andric else if (V == "posix")
2441fe6060f1SDimitry Andric OutputFormat = posix;
2442fe6060f1SDimitry Andric else if (V == "sysv")
2443fe6060f1SDimitry Andric OutputFormat = sysv;
2444fe6060f1SDimitry Andric else if (V == "darwin")
2445fe6060f1SDimitry Andric OutputFormat = darwin;
2446fe6060f1SDimitry Andric else if (V == "just-symbols")
2447fe6060f1SDimitry Andric OutputFormat = just_symbols;
2448fe6060f1SDimitry Andric else
2449fe6060f1SDimitry Andric error("--format value should be one of: bsd, posix, sysv, darwin, "
2450fe6060f1SDimitry Andric "just-symbols");
24515f757f3fSDimitry Andric LineNumbers = Args.hasArg(OPT_line_numbers);
2452fe6060f1SDimitry Andric NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc);
2453fe6060f1SDimitry Andric NoSort = Args.hasArg(OPT_no_sort);
2454fe6060f1SDimitry Andric NoWeakSymbols = Args.hasArg(OPT_no_weak);
2455fe6060f1SDimitry Andric NumericSort = Args.hasArg(OPT_numeric_sort);
2456fe6060f1SDimitry Andric ArchiveMap = Args.hasArg(OPT_print_armap);
2457fe6060f1SDimitry Andric PrintFileName = Args.hasArg(OPT_print_file_name);
2458fe6060f1SDimitry Andric PrintSize = Args.hasArg(OPT_print_size);
2459fe6060f1SDimitry Andric ReverseSort = Args.hasArg(OPT_reverse_sort);
246081ad6265SDimitry Andric ExportSymbols = Args.hasArg(OPT_export_symbols);
246181ad6265SDimitry Andric if (ExportSymbols) {
246281ad6265SDimitry Andric ExternalOnly = true;
246381ad6265SDimitry Andric DefinedOnly = true;
246481ad6265SDimitry Andric }
246581ad6265SDimitry Andric
2466fe6060f1SDimitry Andric Quiet = Args.hasArg(OPT_quiet);
2467fe6060f1SDimitry Andric V = Args.getLastArgValue(OPT_radix_EQ, "x");
2468fe6060f1SDimitry Andric if (V == "o")
2469fe6060f1SDimitry Andric AddressRadix = Radix::o;
2470fe6060f1SDimitry Andric else if (V == "d")
2471fe6060f1SDimitry Andric AddressRadix = Radix::d;
2472fe6060f1SDimitry Andric else if (V == "x")
2473fe6060f1SDimitry Andric AddressRadix = Radix::x;
2474fe6060f1SDimitry Andric else
2475fe6060f1SDimitry Andric error("--radix value should be one of: 'o' (octal), 'd' (decimal), 'x' "
2476fe6060f1SDimitry Andric "(hexadecimal)");
2477fe6060f1SDimitry Andric SizeSort = Args.hasArg(OPT_size_sort);
2478fe6060f1SDimitry Andric SpecialSyms = Args.hasArg(OPT_special_syms);
2479fe6060f1SDimitry Andric UndefinedOnly = Args.hasArg(OPT_undefined_only);
2480fe6060f1SDimitry Andric WithoutAliases = Args.hasArg(OPT_without_aliases);
2481fe6060f1SDimitry Andric
2482bdd1243dSDimitry Andric // Get BitMode from enviornment variable "OBJECT_MODE" for AIX OS, if
2483bdd1243dSDimitry Andric // specified.
2484bdd1243dSDimitry Andric Triple HostTriple(sys::getProcessTriple());
2485bdd1243dSDimitry Andric if (HostTriple.isOSAIX()) {
2486bdd1243dSDimitry Andric BitMode = StringSwitch<BitModeTy>(getenv("OBJECT_MODE"))
2487bdd1243dSDimitry Andric .Case("32", BitModeTy::Bit32)
2488bdd1243dSDimitry Andric .Case("64", BitModeTy::Bit64)
2489bdd1243dSDimitry Andric .Case("32_64", BitModeTy::Bit32_64)
2490bdd1243dSDimitry Andric .Case("any", BitModeTy::Any)
2491bdd1243dSDimitry Andric .Default(BitModeTy::Bit32);
2492bdd1243dSDimitry Andric } else
2493bdd1243dSDimitry Andric BitMode = BitModeTy::Any;
2494bdd1243dSDimitry Andric
2495bdd1243dSDimitry Andric if (Arg *A = Args.getLastArg(OPT_X)) {
2496bdd1243dSDimitry Andric StringRef Mode = A->getValue();
249781ad6265SDimitry Andric if (Mode == "32")
249881ad6265SDimitry Andric BitMode = BitModeTy::Bit32;
249981ad6265SDimitry Andric else if (Mode == "64")
250081ad6265SDimitry Andric BitMode = BitModeTy::Bit64;
250181ad6265SDimitry Andric else if (Mode == "32_64")
250281ad6265SDimitry Andric BitMode = BitModeTy::Bit32_64;
250381ad6265SDimitry Andric else if (Mode == "any")
250481ad6265SDimitry Andric BitMode = BitModeTy::Any;
250581ad6265SDimitry Andric else
250681ad6265SDimitry Andric error("-X value should be one of: 32, 64, 32_64, (default) any");
2507bdd1243dSDimitry Andric }
250881ad6265SDimitry Andric
2509fe6060f1SDimitry Andric // Mach-O specific options.
2510fe6060f1SDimitry Andric FormatMachOasHex = Args.hasArg(OPT_x);
2511fe6060f1SDimitry Andric AddDyldInfo = Args.hasArg(OPT_add_dyldinfo);
2512fe6060f1SDimitry Andric AddInlinedInfo = Args.hasArg(OPT_add_inlinedinfo);
2513fe6060f1SDimitry Andric DyldInfoOnly = Args.hasArg(OPT_dyldinfo_only);
2514fe6060f1SDimitry Andric NoDyldInfo = Args.hasArg(OPT_no_dyldinfo);
25150b57cec5SDimitry Andric
251681ad6265SDimitry Andric // XCOFF specific options.
251781ad6265SDimitry Andric NoRsrc = Args.hasArg(OPT_no_rsrc);
251881ad6265SDimitry Andric
25190b57cec5SDimitry Andric // llvm-nm only reads binary files.
25200b57cec5SDimitry Andric if (error(sys::ChangeStdinToBinary()))
25210b57cec5SDimitry Andric return 1;
25220b57cec5SDimitry Andric
25230b57cec5SDimitry Andric // These calls are needed so that we can read bitcode correctly.
25240b57cec5SDimitry Andric llvm::InitializeAllTargetInfos();
25250b57cec5SDimitry Andric llvm::InitializeAllTargetMCs();
25260b57cec5SDimitry Andric llvm::InitializeAllAsmParsers();
25270b57cec5SDimitry Andric
25280b57cec5SDimitry Andric // The relative order of these is important. If you pass --size-sort it should
25290b57cec5SDimitry Andric // only print out the size. However, if you pass -S --size-sort, it should
25300b57cec5SDimitry Andric // print out both the size and address.
25310b57cec5SDimitry Andric if (SizeSort && !PrintSize)
25320b57cec5SDimitry Andric PrintAddress = false;
25330b57cec5SDimitry Andric if (OutputFormat == sysv || SizeSort)
25340b57cec5SDimitry Andric PrintSize = true;
25350b57cec5SDimitry Andric
2536fe6060f1SDimitry Andric for (const auto *A : Args.filtered(OPT_arch_EQ)) {
2537fe6060f1SDimitry Andric SmallVector<StringRef, 2> Values;
2538fe6060f1SDimitry Andric llvm::SplitString(A->getValue(), Values, ",");
2539fe6060f1SDimitry Andric for (StringRef V : Values) {
2540fe6060f1SDimitry Andric if (V == "all")
25410b57cec5SDimitry Andric ArchAll = true;
2542fe6060f1SDimitry Andric else if (MachOObjectFile::isValidArch(V))
2543fe6060f1SDimitry Andric ArchFlags.push_back(V);
2544fe6060f1SDimitry Andric else
2545fe6060f1SDimitry Andric error("Unknown architecture named '" + V + "'",
25460b57cec5SDimitry Andric "for the --arch option");
25470b57cec5SDimitry Andric }
25480b57cec5SDimitry Andric }
25490b57cec5SDimitry Andric
2550fe6060f1SDimitry Andric // Mach-O takes -s to accept two arguments. We emulate this by iterating over
2551fe6060f1SDimitry Andric // both OPT_s and OPT_INPUT.
2552fe6060f1SDimitry Andric std::vector<std::string> InputFilenames;
2553fe6060f1SDimitry Andric int SegSectArgs = 0;
2554fe6060f1SDimitry Andric for (opt::Arg *A : Args.filtered(OPT_s, OPT_INPUT)) {
2555fe6060f1SDimitry Andric if (SegSectArgs > 0) {
2556fe6060f1SDimitry Andric --SegSectArgs;
2557fe6060f1SDimitry Andric SegSect.push_back(A->getValue());
2558fe6060f1SDimitry Andric } else if (A->getOption().matches(OPT_s)) {
2559fe6060f1SDimitry Andric SegSectArgs = 2;
2560fe6060f1SDimitry Andric } else {
2561fe6060f1SDimitry Andric InputFilenames.push_back(A->getValue());
2562fe6060f1SDimitry Andric }
2563fe6060f1SDimitry Andric }
25640b57cec5SDimitry Andric if (!SegSect.empty() && SegSect.size() != 2)
25650b57cec5SDimitry Andric error("bad number of arguments (must be two arguments)",
25660b57cec5SDimitry Andric "for the -s option");
25670b57cec5SDimitry Andric
2568fe6060f1SDimitry Andric if (InputFilenames.empty())
2569fe6060f1SDimitry Andric InputFilenames.push_back("a.out");
2570fe6060f1SDimitry Andric if (InputFilenames.size() > 1)
2571fe6060f1SDimitry Andric MultipleFiles = true;
2572fe6060f1SDimitry Andric
25730b57cec5SDimitry Andric if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
25740b57cec5SDimitry Andric error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
25750b57cec5SDimitry Andric
257681ad6265SDimitry Andric if (ExportSymbols)
257781ad6265SDimitry Andric exportSymbolNamesFromFiles(InputFilenames);
257881ad6265SDimitry Andric else
25790b57cec5SDimitry Andric llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
25800b57cec5SDimitry Andric
25810b57cec5SDimitry Andric if (HadError)
25820b57cec5SDimitry Andric return 1;
2583bdd1243dSDimitry Andric return 0;
25840b57cec5SDimitry Andric }
2585