xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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"
20*81ad6265SDimitry Andric #include "llvm/BinaryFormat/XCOFF.h"
210b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h"
220b57cec5SDimitry Andric #include "llvm/IR/Function.h"
230b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
240b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
250b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
260b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h"
270b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
280b57cec5SDimitry Andric #include "llvm/Object/IRObjectFile.h"
290b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
300b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
310b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
325ffd83dbSDimitry Andric #include "llvm/Object/TapiFile.h"
335ffd83dbSDimitry Andric #include "llvm/Object/TapiUniversal.h"
340b57cec5SDimitry Andric #include "llvm/Object/Wasm.h"
3504eeddc0SDimitry Andric #include "llvm/Object/XCOFFObjectFile.h"
36fe6060f1SDimitry Andric #include "llvm/Option/Arg.h"
37fe6060f1SDimitry Andric #include "llvm/Option/ArgList.h"
38fe6060f1SDimitry Andric #include "llvm/Option/Option.h"
390b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
400b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
410b57cec5SDimitry Andric #include "llvm/Support/Format.h"
420b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
430b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
440b57cec5SDimitry Andric #include "llvm/Support/Program.h"
450b57cec5SDimitry Andric #include "llvm/Support/Signals.h"
460b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
470b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
480b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
490b57cec5SDimitry Andric #include <vector>
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric using namespace llvm;
520b57cec5SDimitry Andric using namespace object;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric namespace {
55fe6060f1SDimitry Andric using namespace llvm::opt; // for HelpHidden in Opts.inc
56fe6060f1SDimitry Andric enum ID {
57fe6060f1SDimitry Andric   OPT_INVALID = 0, // This is not an option ID.
58fe6060f1SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
59fe6060f1SDimitry Andric                HELPTEXT, METAVAR, VALUES)                                      \
60fe6060f1SDimitry Andric   OPT_##ID,
61fe6060f1SDimitry Andric #include "Opts.inc"
62fe6060f1SDimitry Andric #undef OPTION
63fe6060f1SDimitry Andric };
640b57cec5SDimitry Andric 
65fe6060f1SDimitry Andric #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
66fe6060f1SDimitry Andric #include "Opts.inc"
67fe6060f1SDimitry Andric #undef PREFIX
680b57cec5SDimitry Andric 
69349cc55cSDimitry Andric const opt::OptTable::Info InfoTable[] = {
70fe6060f1SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
71fe6060f1SDimitry Andric                HELPTEXT, METAVAR, VALUES)                                      \
72fe6060f1SDimitry Andric   {                                                                            \
73fe6060f1SDimitry Andric       PREFIX,      NAME,      HELPTEXT,                                        \
74fe6060f1SDimitry Andric       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
75fe6060f1SDimitry Andric       PARAM,       FLAGS,     OPT_##GROUP,                                     \
76fe6060f1SDimitry Andric       OPT_##ALIAS, ALIASARGS, VALUES},
77fe6060f1SDimitry Andric #include "Opts.inc"
78fe6060f1SDimitry Andric #undef OPTION
79fe6060f1SDimitry Andric };
800b57cec5SDimitry Andric 
81fe6060f1SDimitry Andric class NmOptTable : public opt::OptTable {
82fe6060f1SDimitry Andric public:
83fe6060f1SDimitry Andric   NmOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
84fe6060f1SDimitry Andric };
850b57cec5SDimitry Andric 
86fe6060f1SDimitry Andric enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
87*81ad6265SDimitry Andric enum class BitModeTy { Bit32, Bit64, Bit32_64, Any };
88fe6060f1SDimitry Andric } // namespace
890b57cec5SDimitry Andric 
90fe6060f1SDimitry Andric static bool ArchiveMap;
91*81ad6265SDimitry Andric static BitModeTy BitMode;
92fe6060f1SDimitry Andric static bool DebugSyms;
93fe6060f1SDimitry Andric static bool DefinedOnly;
94fe6060f1SDimitry Andric static bool Demangle;
95fe6060f1SDimitry Andric static bool DynamicSyms;
96*81ad6265SDimitry Andric static bool ExportSymbols;
97fe6060f1SDimitry Andric static bool ExternalOnly;
98fe6060f1SDimitry Andric static OutputFormatTy OutputFormat;
99fe6060f1SDimitry Andric static bool NoLLVMBitcode;
100fe6060f1SDimitry Andric static bool NoSort;
101fe6060f1SDimitry Andric static bool NoWeakSymbols;
102fe6060f1SDimitry Andric static bool NumericSort;
103fe6060f1SDimitry Andric static bool PrintFileName;
104fe6060f1SDimitry Andric static bool PrintSize;
105fe6060f1SDimitry Andric static bool Quiet;
106fe6060f1SDimitry Andric static bool ReverseSort;
107fe6060f1SDimitry Andric static bool SpecialSyms;
108fe6060f1SDimitry Andric static bool SizeSort;
109fe6060f1SDimitry Andric static bool UndefinedOnly;
110fe6060f1SDimitry Andric static bool WithoutAliases;
1110b57cec5SDimitry Andric 
112*81ad6265SDimitry Andric // XCOFF-specific options.
113*81ad6265SDimitry Andric static bool NoRsrc;
114*81ad6265SDimitry Andric 
115fe6060f1SDimitry Andric namespace {
1160b57cec5SDimitry Andric enum Radix { d, o, x };
117fe6060f1SDimitry Andric } // namespace
118fe6060f1SDimitry Andric static Radix AddressRadix;
1190b57cec5SDimitry Andric 
120fe6060f1SDimitry Andric // Mach-O specific options.
121fe6060f1SDimitry Andric static bool ArchAll = false;
122fe6060f1SDimitry Andric static std::vector<StringRef> ArchFlags;
123fe6060f1SDimitry Andric static bool AddDyldInfo;
124fe6060f1SDimitry Andric static bool AddInlinedInfo;
125fe6060f1SDimitry Andric static bool DyldInfoOnly;
126fe6060f1SDimitry Andric static bool FormatMachOasHex;
127fe6060f1SDimitry Andric static bool NoDyldInfo;
128fe6060f1SDimitry Andric static std::vector<StringRef> SegSect;
129fe6060f1SDimitry Andric static bool MachOPrintSizeWarning = false;
1300b57cec5SDimitry Andric 
131fe6060f1SDimitry Andric // Miscellaneous states.
132fe6060f1SDimitry Andric static bool PrintAddress = true;
133fe6060f1SDimitry Andric static bool MultipleFiles = false;
134fe6060f1SDimitry Andric static bool HadError = false;
1350b57cec5SDimitry Andric 
136fe6060f1SDimitry Andric static StringRef ToolName;
1370b57cec5SDimitry Andric 
138*81ad6265SDimitry Andric static void warn(Error Err, Twine FileName, Twine Context = Twine(),
139*81ad6265SDimitry Andric                  Twine Archive = Twine()) {
14004eeddc0SDimitry Andric   assert(Err);
14104eeddc0SDimitry Andric 
14204eeddc0SDimitry Andric   // Flush the standard output so that the warning isn't interleaved with other
14304eeddc0SDimitry Andric   // output if stdout and stderr are writing to the same place.
14404eeddc0SDimitry Andric   outs().flush();
14504eeddc0SDimitry Andric 
14604eeddc0SDimitry Andric   handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
14704eeddc0SDimitry Andric     WithColor::warning(errs(), ToolName)
148*81ad6265SDimitry Andric         << (Archive.str().empty() ? FileName : Archive + "(" + FileName + ")")
149*81ad6265SDimitry Andric         << ": " << (Context.str().empty() ? "" : Context + ": ") << EI.message()
150*81ad6265SDimitry Andric         << "\n";
15104eeddc0SDimitry Andric   });
15204eeddc0SDimitry Andric }
15304eeddc0SDimitry Andric 
1540b57cec5SDimitry Andric static void error(Twine Message, Twine Path = Twine()) {
1550b57cec5SDimitry Andric   HadError = true;
156fe6060f1SDimitry Andric   WithColor::error(errs(), ToolName) << Path << ": " << Message << "\n";
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric static bool error(std::error_code EC, Twine Path = Twine()) {
1600b57cec5SDimitry Andric   if (EC) {
1610b57cec5SDimitry Andric     error(EC.message(), Path);
1620b57cec5SDimitry Andric     return true;
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric   return false;
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric // This version of error() prints the archive name and member name, for example:
1680b57cec5SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message.  It sets
1690b57cec5SDimitry Andric // HadError but returns allowing the code to move on to other archive members.
1700b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
1710b57cec5SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
1720b57cec5SDimitry Andric   HadError = true;
1730b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << FileName;
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   Expected<StringRef> NameOrErr = C.getName();
1760b57cec5SDimitry Andric   // TODO: if we have a error getting the name then it would be nice to print
1770b57cec5SDimitry Andric   // the index of which archive member this is and or its offset in the
1780b57cec5SDimitry Andric   // archive instead of "???" as the name.
1790b57cec5SDimitry Andric   if (!NameOrErr) {
1800b57cec5SDimitry Andric     consumeError(NameOrErr.takeError());
1810b57cec5SDimitry Andric     errs() << "(" << "???" << ")";
1820b57cec5SDimitry Andric   } else
1830b57cec5SDimitry Andric     errs() << "(" << NameOrErr.get() << ")";
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   if (!ArchitectureName.empty())
1860b57cec5SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ")";
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   std::string Buf;
1890b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
1900b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
1910b57cec5SDimitry Andric   OS.flush();
192fe6060f1SDimitry Andric   errs() << ": " << Buf << "\n";
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric // This version of error() prints the file name and which architecture slice it
1960b57cec5SDimitry Andric // is from, for example: "foo.o (for architecture i386)" after the ToolName
1970b57cec5SDimitry Andric // before the error message.  It sets HadError but returns allowing the code to
1980b57cec5SDimitry Andric // move on to other architecture slices.
1990b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName,
2000b57cec5SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
2010b57cec5SDimitry Andric   HadError = true;
2020b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << FileName;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   if (!ArchitectureName.empty())
2050b57cec5SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ")";
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   std::string Buf;
2080b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
2090b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
2100b57cec5SDimitry Andric   OS.flush();
211fe6060f1SDimitry Andric   errs() << ": " << Buf << "\n";
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric namespace {
2150b57cec5SDimitry Andric struct NMSymbol {
2160b57cec5SDimitry Andric   uint64_t Address;
2170b57cec5SDimitry Andric   uint64_t Size;
2180b57cec5SDimitry Andric   char TypeChar;
219e8d8bef9SDimitry Andric   std::string Name;
2200b57cec5SDimitry Andric   StringRef SectionName;
2210b57cec5SDimitry Andric   StringRef TypeName;
2220b57cec5SDimitry Andric   BasicSymbolRef Sym;
223*81ad6265SDimitry Andric   StringRef Visibility;
224*81ad6265SDimitry Andric 
2250b57cec5SDimitry Andric   // The Sym field above points to the native symbol in the object file,
2260b57cec5SDimitry Andric   // for Mach-O when we are creating symbols from the dyld info the above
2270b57cec5SDimitry Andric   // pointer is null as there is no native symbol.  In these cases the fields
2280b57cec5SDimitry Andric   // below are filled in to represent what would have been a Mach-O nlist
2290b57cec5SDimitry Andric   // native symbol.
2300b57cec5SDimitry Andric   uint32_t SymFlags;
2310b57cec5SDimitry Andric   SectionRef Section;
2320b57cec5SDimitry Andric   uint8_t NType;
2330b57cec5SDimitry Andric   uint8_t NSect;
2340b57cec5SDimitry Andric   uint16_t NDesc;
235e8d8bef9SDimitry Andric   std::string IndirectName;
236*81ad6265SDimitry Andric 
237*81ad6265SDimitry Andric   bool isDefined() const {
238*81ad6265SDimitry Andric     if (Sym.getRawDataRefImpl().p) {
239*81ad6265SDimitry Andric       uint32_t Flags = cantFail(Sym.getFlags());
240*81ad6265SDimitry Andric       return !(Flags & SymbolRef::SF_Undefined);
241*81ad6265SDimitry Andric     }
242*81ad6265SDimitry Andric     return TypeChar != 'U';
243*81ad6265SDimitry Andric   }
244*81ad6265SDimitry Andric 
245*81ad6265SDimitry Andric   bool initializeFlags(const SymbolicFile &Obj) {
246*81ad6265SDimitry Andric     Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
247*81ad6265SDimitry Andric     if (!SymFlagsOrErr) {
248*81ad6265SDimitry Andric       // TODO: Test this error.
249*81ad6265SDimitry Andric       error(SymFlagsOrErr.takeError(), Obj.getFileName());
250*81ad6265SDimitry Andric       return false;
251*81ad6265SDimitry Andric     }
252*81ad6265SDimitry Andric     SymFlags = *SymFlagsOrErr;
253*81ad6265SDimitry Andric     return true;
254*81ad6265SDimitry Andric   }
255*81ad6265SDimitry Andric 
256*81ad6265SDimitry Andric   bool shouldPrint() const {
257*81ad6265SDimitry Andric     bool Undefined = SymFlags & SymbolRef::SF_Undefined;
258*81ad6265SDimitry Andric     bool Global = SymFlags & SymbolRef::SF_Global;
259*81ad6265SDimitry Andric     bool Weak = SymFlags & SymbolRef::SF_Weak;
260*81ad6265SDimitry Andric     bool FormatSpecific = SymFlags & SymbolRef::SF_FormatSpecific;
261*81ad6265SDimitry Andric     if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
262*81ad6265SDimitry Andric         (!Global && ExternalOnly) || (Weak && NoWeakSymbols) ||
263*81ad6265SDimitry Andric         (FormatSpecific && !(SpecialSyms || DebugSyms)))
264*81ad6265SDimitry Andric       return false;
265*81ad6265SDimitry Andric     return true;
266*81ad6265SDimitry Andric   }
2670b57cec5SDimitry Andric };
2680b57cec5SDimitry Andric 
269*81ad6265SDimitry Andric bool operator<(const NMSymbol &A, const NMSymbol &B) {
270*81ad6265SDimitry Andric   if (NumericSort)
271*81ad6265SDimitry Andric     return std::make_tuple(A.isDefined(), A.Address, A.Name, A.Size) <
272*81ad6265SDimitry Andric            std::make_tuple(B.isDefined(), B.Address, B.Name, B.Size);
273*81ad6265SDimitry Andric   if (SizeSort)
2740b57cec5SDimitry Andric     return std::make_tuple(A.Size, A.Name, A.Address) <
2750b57cec5SDimitry Andric            std::make_tuple(B.Size, B.Name, B.Address);
276*81ad6265SDimitry Andric   if (ExportSymbols)
277*81ad6265SDimitry Andric     return std::make_tuple(A.Name, A.Visibility) <
278*81ad6265SDimitry Andric            std::make_tuple(B.Name, B.Visibility);
2790b57cec5SDimitry Andric   return std::make_tuple(A.Name, A.Size, A.Address) <
2800b57cec5SDimitry Andric          std::make_tuple(B.Name, B.Size, B.Address);
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
283*81ad6265SDimitry Andric bool operator>(const NMSymbol &A, const NMSymbol &B) { return B < A; }
284*81ad6265SDimitry Andric bool operator==(const NMSymbol &A, const NMSymbol &B) {
285*81ad6265SDimitry Andric   return !(A < B) && !(B < A);
286*81ad6265SDimitry Andric }
287*81ad6265SDimitry Andric } // anonymous namespace
288*81ad6265SDimitry Andric 
2890b57cec5SDimitry Andric static char isSymbolList64Bit(SymbolicFile &Obj) {
2900b57cec5SDimitry Andric   if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
2910b57cec5SDimitry Andric     return Triple(IRObj->getTargetTriple()).isArch64Bit();
2920b57cec5SDimitry Andric   if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
2930b57cec5SDimitry Andric     return false;
29404eeddc0SDimitry Andric   if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj))
29504eeddc0SDimitry Andric     return XCOFFObj->is64Bit();
2960b57cec5SDimitry Andric   if (isa<WasmObjectFile>(Obj))
2970b57cec5SDimitry Andric     return false;
2985ffd83dbSDimitry Andric   if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
2995ffd83dbSDimitry Andric     return Tapi->is64Bit();
3000b57cec5SDimitry Andric   if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
3010b57cec5SDimitry Andric     return MachO->is64Bit();
3020b57cec5SDimitry Andric   return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric static StringRef CurrentFilename;
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
3100b57cec5SDimitry Andric // the OutputFormat is darwin or we are printing Mach-O symbols in hex.  For
3110b57cec5SDimitry Andric // the darwin format it produces the same output as darwin's nm(1) -m output
3120b57cec5SDimitry Andric // and when printing Mach-O symbols in hex it produces the same output as
3130b57cec5SDimitry Andric // darwin's nm(1) -x format.
3140b57cec5SDimitry Andric static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
3150b57cec5SDimitry Andric                               char *SymbolAddrStr, const char *printBlanks,
3160b57cec5SDimitry Andric                               const char *printDashes,
3170b57cec5SDimitry Andric                               const char *printFormat) {
3180b57cec5SDimitry Andric   MachO::mach_header H;
3190b57cec5SDimitry Andric   MachO::mach_header_64 H_64;
3200b57cec5SDimitry Andric   uint32_t Filetype = MachO::MH_OBJECT;
3210b57cec5SDimitry Andric   uint32_t Flags = 0;
3220b57cec5SDimitry Andric   uint8_t NType = 0;
3230b57cec5SDimitry Andric   uint8_t NSect = 0;
3240b57cec5SDimitry Andric   uint16_t NDesc = 0;
3250b57cec5SDimitry Andric   uint32_t NStrx = 0;
3260b57cec5SDimitry Andric   uint64_t NValue = 0;
3270b57cec5SDimitry Andric   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
3280b57cec5SDimitry Andric   if (Obj.isIR()) {
3295ffd83dbSDimitry Andric     uint32_t SymFlags = cantFail(S.Sym.getFlags());
3300b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Global)
3310b57cec5SDimitry Andric       NType |= MachO::N_EXT;
3320b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Hidden)
3330b57cec5SDimitry Andric       NType |= MachO::N_PEXT;
3340b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Undefined)
3350b57cec5SDimitry Andric       NType |= MachO::N_EXT | MachO::N_UNDF;
3360b57cec5SDimitry Andric     else {
3370b57cec5SDimitry Andric       // Here we have a symbol definition.  So to fake out a section name we
3380b57cec5SDimitry Andric       // use 1, 2 and 3 for section numbers.  See below where they are used to
3390b57cec5SDimitry Andric       // print out fake section names.
3400b57cec5SDimitry Andric       NType |= MachO::N_SECT;
3410b57cec5SDimitry Andric       if (SymFlags & SymbolRef::SF_Const)
3420b57cec5SDimitry Andric         NSect = 3;
3430b57cec5SDimitry Andric       else if (SymFlags & SymbolRef::SF_Executable)
3440b57cec5SDimitry Andric         NSect = 1;
3450b57cec5SDimitry Andric       else
3460b57cec5SDimitry Andric         NSect = 2;
3470b57cec5SDimitry Andric     }
3480b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Weak)
3490b57cec5SDimitry Andric       NDesc |= MachO::N_WEAK_DEF;
3500b57cec5SDimitry Andric   } else {
3510b57cec5SDimitry Andric     DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
3520b57cec5SDimitry Andric     if (MachO->is64Bit()) {
3530b57cec5SDimitry Andric       H_64 = MachO->MachOObjectFile::getHeader64();
3540b57cec5SDimitry Andric       Filetype = H_64.filetype;
3550b57cec5SDimitry Andric       Flags = H_64.flags;
3560b57cec5SDimitry Andric       if (SymDRI.p){
3570b57cec5SDimitry Andric         MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
3580b57cec5SDimitry Andric         NType = STE_64.n_type;
3590b57cec5SDimitry Andric         NSect = STE_64.n_sect;
3600b57cec5SDimitry Andric         NDesc = STE_64.n_desc;
3610b57cec5SDimitry Andric         NStrx = STE_64.n_strx;
3620b57cec5SDimitry Andric         NValue = STE_64.n_value;
3630b57cec5SDimitry Andric       } else {
3640b57cec5SDimitry Andric         NType = S.NType;
3650b57cec5SDimitry Andric         NSect = S.NSect;
3660b57cec5SDimitry Andric         NDesc = S.NDesc;
3670b57cec5SDimitry Andric         NStrx = 0;
3680b57cec5SDimitry Andric         NValue = S.Address;
3690b57cec5SDimitry Andric       }
3700b57cec5SDimitry Andric     } else {
3710b57cec5SDimitry Andric       H = MachO->MachOObjectFile::getHeader();
3720b57cec5SDimitry Andric       Filetype = H.filetype;
3730b57cec5SDimitry Andric       Flags = H.flags;
3740b57cec5SDimitry Andric       if (SymDRI.p){
3750b57cec5SDimitry Andric         MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
3760b57cec5SDimitry Andric         NType = STE.n_type;
3770b57cec5SDimitry Andric         NSect = STE.n_sect;
3780b57cec5SDimitry Andric         NDesc = STE.n_desc;
3790b57cec5SDimitry Andric         NStrx = STE.n_strx;
3800b57cec5SDimitry Andric         NValue = STE.n_value;
3810b57cec5SDimitry Andric       } else {
3820b57cec5SDimitry Andric         NType = S.NType;
3830b57cec5SDimitry Andric         NSect = S.NSect;
3840b57cec5SDimitry Andric         NDesc = S.NDesc;
3850b57cec5SDimitry Andric         NStrx = 0;
3860b57cec5SDimitry Andric         NValue = S.Address;
3870b57cec5SDimitry Andric       }
3880b57cec5SDimitry Andric     }
3890b57cec5SDimitry Andric   }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   // If we are printing Mach-O symbols in hex do that and return.
3920b57cec5SDimitry Andric   if (FormatMachOasHex) {
3930b57cec5SDimitry Andric     outs() << format(printFormat, NValue) << ' '
3940b57cec5SDimitry Andric            << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
3950b57cec5SDimitry Andric            << S.Name;
3960b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
3970b57cec5SDimitry Andric       outs() << " (indirect for ";
3980b57cec5SDimitry Andric       outs() << format(printFormat, NValue) << ' ';
3990b57cec5SDimitry Andric       StringRef IndirectName;
4000b57cec5SDimitry Andric       if (S.Sym.getRawDataRefImpl().p) {
4010b57cec5SDimitry Andric         if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
4020b57cec5SDimitry Andric           outs() << "?)";
4030b57cec5SDimitry Andric         else
4040b57cec5SDimitry Andric           outs() << IndirectName << ")";
4050b57cec5SDimitry Andric       } else
4060b57cec5SDimitry Andric         outs() << S.IndirectName << ")";
4070b57cec5SDimitry Andric     }
4080b57cec5SDimitry Andric     outs() << "\n";
4090b57cec5SDimitry Andric     return;
4100b57cec5SDimitry Andric   }
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   if (PrintAddress) {
4130b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) == MachO::N_INDR)
4140b57cec5SDimitry Andric       strcpy(SymbolAddrStr, printBlanks);
4150b57cec5SDimitry Andric     if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE)
4160b57cec5SDimitry Andric       strcpy(SymbolAddrStr, printDashes);
4170b57cec5SDimitry Andric     outs() << SymbolAddrStr << ' ';
4180b57cec5SDimitry Andric   }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   switch (NType & MachO::N_TYPE) {
4210b57cec5SDimitry Andric   case MachO::N_UNDF:
4220b57cec5SDimitry Andric     if (NValue != 0) {
4230b57cec5SDimitry Andric       outs() << "(common) ";
4240b57cec5SDimitry Andric       if (MachO::GET_COMM_ALIGN(NDesc) != 0)
4250b57cec5SDimitry Andric         outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") ";
4260b57cec5SDimitry Andric     } else {
4270b57cec5SDimitry Andric       if ((NType & MachO::N_TYPE) == MachO::N_PBUD)
4280b57cec5SDimitry Andric         outs() << "(prebound ";
4290b57cec5SDimitry Andric       else
4300b57cec5SDimitry Andric         outs() << "(";
4310b57cec5SDimitry Andric       if ((NDesc & MachO::REFERENCE_TYPE) ==
4320b57cec5SDimitry Andric           MachO::REFERENCE_FLAG_UNDEFINED_LAZY)
4330b57cec5SDimitry Andric         outs() << "undefined [lazy bound]) ";
4340b57cec5SDimitry Andric       else if ((NDesc & MachO::REFERENCE_TYPE) ==
4350b57cec5SDimitry Andric                MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
4360b57cec5SDimitry Andric         outs() << "undefined [private lazy bound]) ";
4370b57cec5SDimitry Andric       else if ((NDesc & MachO::REFERENCE_TYPE) ==
4380b57cec5SDimitry Andric                MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
4390b57cec5SDimitry Andric         outs() << "undefined [private]) ";
4400b57cec5SDimitry Andric       else
4410b57cec5SDimitry Andric         outs() << "undefined) ";
4420b57cec5SDimitry Andric     }
4430b57cec5SDimitry Andric     break;
4440b57cec5SDimitry Andric   case MachO::N_ABS:
4450b57cec5SDimitry Andric     outs() << "(absolute) ";
4460b57cec5SDimitry Andric     break;
4470b57cec5SDimitry Andric   case MachO::N_INDR:
4480b57cec5SDimitry Andric     outs() << "(indirect) ";
4490b57cec5SDimitry Andric     break;
4500b57cec5SDimitry Andric   case MachO::N_SECT: {
4510b57cec5SDimitry Andric     if (Obj.isIR()) {
4520b57cec5SDimitry Andric       // For llvm bitcode files print out a fake section name using the values
4530b57cec5SDimitry Andric       // use 1, 2 and 3 for section numbers as set above.
4540b57cec5SDimitry Andric       if (NSect == 1)
4550b57cec5SDimitry Andric         outs() << "(LTO,CODE) ";
4560b57cec5SDimitry Andric       else if (NSect == 2)
4570b57cec5SDimitry Andric         outs() << "(LTO,DATA) ";
4580b57cec5SDimitry Andric       else if (NSect == 3)
4590b57cec5SDimitry Andric         outs() << "(LTO,RODATA) ";
4600b57cec5SDimitry Andric       else
4610b57cec5SDimitry Andric         outs() << "(?,?) ";
4620b57cec5SDimitry Andric       break;
4630b57cec5SDimitry Andric     }
4640b57cec5SDimitry Andric     section_iterator Sec = SectionRef();
4650b57cec5SDimitry Andric     if (S.Sym.getRawDataRefImpl().p) {
4660b57cec5SDimitry Andric       Expected<section_iterator> SecOrErr =
4670b57cec5SDimitry Andric           MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
4680b57cec5SDimitry Andric       if (!SecOrErr) {
4690b57cec5SDimitry Andric         consumeError(SecOrErr.takeError());
4700b57cec5SDimitry Andric         outs() << "(?,?) ";
4710b57cec5SDimitry Andric         break;
4720b57cec5SDimitry Andric       }
4730b57cec5SDimitry Andric       Sec = *SecOrErr;
4740b57cec5SDimitry Andric       if (Sec == MachO->section_end()) {
4750b57cec5SDimitry Andric         outs() << "(?,?) ";
4760b57cec5SDimitry Andric         break;
4770b57cec5SDimitry Andric       }
4780b57cec5SDimitry Andric     } else {
4790b57cec5SDimitry Andric       Sec = S.Section;
4800b57cec5SDimitry Andric     }
4810b57cec5SDimitry Andric     DataRefImpl Ref = Sec->getRawDataRefImpl();
4820b57cec5SDimitry Andric     StringRef SectionName;
4830b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
4840b57cec5SDimitry Andric       SectionName = *NameOrErr;
4850b57cec5SDimitry Andric     StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
4860b57cec5SDimitry Andric     outs() << "(" << SegmentName << "," << SectionName << ") ";
4870b57cec5SDimitry Andric     break;
4880b57cec5SDimitry Andric   }
4890b57cec5SDimitry Andric   default:
4900b57cec5SDimitry Andric     outs() << "(?) ";
4910b57cec5SDimitry Andric     break;
4920b57cec5SDimitry Andric   }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   if (NType & MachO::N_EXT) {
4950b57cec5SDimitry Andric     if (NDesc & MachO::REFERENCED_DYNAMICALLY)
4960b57cec5SDimitry Andric       outs() << "[referenced dynamically] ";
4970b57cec5SDimitry Andric     if (NType & MachO::N_PEXT) {
4980b57cec5SDimitry Andric       if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF)
4990b57cec5SDimitry Andric         outs() << "weak private external ";
5000b57cec5SDimitry Andric       else
5010b57cec5SDimitry Andric         outs() << "private external ";
5020b57cec5SDimitry Andric     } else {
5030b57cec5SDimitry Andric       if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF ||
5040b57cec5SDimitry Andric           (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) {
5050b57cec5SDimitry Andric         if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) ==
5060b57cec5SDimitry Andric             (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
5070b57cec5SDimitry Andric           outs() << "weak external automatically hidden ";
5080b57cec5SDimitry Andric         else
5090b57cec5SDimitry Andric           outs() << "weak external ";
5100b57cec5SDimitry Andric       } else
5110b57cec5SDimitry Andric         outs() << "external ";
5120b57cec5SDimitry Andric     }
5130b57cec5SDimitry Andric   } else {
5140b57cec5SDimitry Andric     if (NType & MachO::N_PEXT)
5150b57cec5SDimitry Andric       outs() << "non-external (was a private external) ";
5160b57cec5SDimitry Andric     else
5170b57cec5SDimitry Andric       outs() << "non-external ";
5180b57cec5SDimitry Andric   }
5190b57cec5SDimitry Andric 
5200b57cec5SDimitry Andric   if (Filetype == MachO::MH_OBJECT) {
5210b57cec5SDimitry Andric     if (NDesc & MachO::N_NO_DEAD_STRIP)
5220b57cec5SDimitry Andric       outs() << "[no dead strip] ";
5230b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
5240b57cec5SDimitry Andric         NDesc & MachO::N_SYMBOL_RESOLVER)
5250b57cec5SDimitry Andric       outs() << "[symbol resolver] ";
5260b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
5270b57cec5SDimitry Andric       outs() << "[alt entry] ";
5280b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
5290b57cec5SDimitry Andric       outs() << "[cold func] ";
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric   if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
5330b57cec5SDimitry Andric     outs() << "[Thumb] ";
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric   if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
5360b57cec5SDimitry Andric     outs() << S.Name << " (for ";
5370b57cec5SDimitry Andric     StringRef IndirectName;
5380b57cec5SDimitry Andric     if (MachO) {
5390b57cec5SDimitry Andric       if (S.Sym.getRawDataRefImpl().p) {
5400b57cec5SDimitry Andric         if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
5410b57cec5SDimitry Andric           outs() << "?)";
5420b57cec5SDimitry Andric         else
5430b57cec5SDimitry Andric           outs() << IndirectName << ")";
5440b57cec5SDimitry Andric       } else
5450b57cec5SDimitry Andric         outs() << S.IndirectName << ")";
5460b57cec5SDimitry Andric     } else
5470b57cec5SDimitry Andric       outs() << "?)";
5480b57cec5SDimitry Andric   } else
5490b57cec5SDimitry Andric     outs() << S.Name;
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric   if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
5520b57cec5SDimitry Andric       (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
5530b57cec5SDimitry Andric        (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
5540b57cec5SDimitry Andric     uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
5550b57cec5SDimitry Andric     if (LibraryOrdinal != 0) {
5560b57cec5SDimitry Andric       if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL)
5570b57cec5SDimitry Andric         outs() << " (from executable)";
5580b57cec5SDimitry Andric       else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL)
5590b57cec5SDimitry Andric         outs() << " (dynamically looked up)";
5600b57cec5SDimitry Andric       else {
5610b57cec5SDimitry Andric         StringRef LibraryName;
5620b57cec5SDimitry Andric         if (!MachO ||
5630b57cec5SDimitry Andric             MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName))
5640b57cec5SDimitry Andric           outs() << " (from bad library ordinal " << LibraryOrdinal << ")";
5650b57cec5SDimitry Andric         else
5660b57cec5SDimitry Andric           outs() << " (from " << LibraryName << ")";
5670b57cec5SDimitry Andric       }
5680b57cec5SDimitry Andric     }
5690b57cec5SDimitry Andric   }
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   outs() << "\n";
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric // Table that maps Darwin's Mach-O stab constants to strings to allow printing.
5750b57cec5SDimitry Andric struct DarwinStabName {
5760b57cec5SDimitry Andric   uint8_t NType;
5770b57cec5SDimitry Andric   const char *Name;
5780b57cec5SDimitry Andric };
579349cc55cSDimitry Andric const struct DarwinStabName DarwinStabNames[] = {
5800b57cec5SDimitry Andric     {MachO::N_GSYM, "GSYM"},
5810b57cec5SDimitry Andric     {MachO::N_FNAME, "FNAME"},
5820b57cec5SDimitry Andric     {MachO::N_FUN, "FUN"},
5830b57cec5SDimitry Andric     {MachO::N_STSYM, "STSYM"},
5840b57cec5SDimitry Andric     {MachO::N_LCSYM, "LCSYM"},
5850b57cec5SDimitry Andric     {MachO::N_BNSYM, "BNSYM"},
5860b57cec5SDimitry Andric     {MachO::N_PC, "PC"},
5870b57cec5SDimitry Andric     {MachO::N_AST, "AST"},
5880b57cec5SDimitry Andric     {MachO::N_OPT, "OPT"},
5890b57cec5SDimitry Andric     {MachO::N_RSYM, "RSYM"},
5900b57cec5SDimitry Andric     {MachO::N_SLINE, "SLINE"},
5910b57cec5SDimitry Andric     {MachO::N_ENSYM, "ENSYM"},
5920b57cec5SDimitry Andric     {MachO::N_SSYM, "SSYM"},
5930b57cec5SDimitry Andric     {MachO::N_SO, "SO"},
5940b57cec5SDimitry Andric     {MachO::N_OSO, "OSO"},
5950b57cec5SDimitry Andric     {MachO::N_LSYM, "LSYM"},
5960b57cec5SDimitry Andric     {MachO::N_BINCL, "BINCL"},
5970b57cec5SDimitry Andric     {MachO::N_SOL, "SOL"},
5980b57cec5SDimitry Andric     {MachO::N_PARAMS, "PARAM"},
5990b57cec5SDimitry Andric     {MachO::N_VERSION, "VERS"},
6000b57cec5SDimitry Andric     {MachO::N_OLEVEL, "OLEV"},
6010b57cec5SDimitry Andric     {MachO::N_PSYM, "PSYM"},
6020b57cec5SDimitry Andric     {MachO::N_EINCL, "EINCL"},
6030b57cec5SDimitry Andric     {MachO::N_ENTRY, "ENTRY"},
6040b57cec5SDimitry Andric     {MachO::N_LBRAC, "LBRAC"},
6050b57cec5SDimitry Andric     {MachO::N_EXCL, "EXCL"},
6060b57cec5SDimitry Andric     {MachO::N_RBRAC, "RBRAC"},
6070b57cec5SDimitry Andric     {MachO::N_BCOMM, "BCOMM"},
6080b57cec5SDimitry Andric     {MachO::N_ECOMM, "ECOMM"},
6090b57cec5SDimitry Andric     {MachO::N_ECOML, "ECOML"},
6100b57cec5SDimitry Andric     {MachO::N_LENG, "LENG"},
6110b57cec5SDimitry Andric };
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric static const char *getDarwinStabString(uint8_t NType) {
6140b57cec5SDimitry Andric   for (auto I : makeArrayRef(DarwinStabNames))
6150b57cec5SDimitry Andric     if (I.NType == NType)
6160b57cec5SDimitry Andric       return I.Name;
6170b57cec5SDimitry Andric   return nullptr;
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
6210b57cec5SDimitry Andric // a stab n_type value in a Mach-O file.
6220b57cec5SDimitry Andric static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
6230b57cec5SDimitry Andric   MachO::nlist_64 STE_64;
6240b57cec5SDimitry Andric   MachO::nlist STE;
6250b57cec5SDimitry Andric   uint8_t NType;
6260b57cec5SDimitry Andric   uint8_t NSect;
6270b57cec5SDimitry Andric   uint16_t NDesc;
6280b57cec5SDimitry Andric   DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
6290b57cec5SDimitry Andric   if (MachO->is64Bit()) {
6300b57cec5SDimitry Andric     STE_64 = MachO->getSymbol64TableEntry(SymDRI);
6310b57cec5SDimitry Andric     NType = STE_64.n_type;
6320b57cec5SDimitry Andric     NSect = STE_64.n_sect;
6330b57cec5SDimitry Andric     NDesc = STE_64.n_desc;
6340b57cec5SDimitry Andric   } else {
6350b57cec5SDimitry Andric     STE = MachO->getSymbolTableEntry(SymDRI);
6360b57cec5SDimitry Andric     NType = STE.n_type;
6370b57cec5SDimitry Andric     NSect = STE.n_sect;
6380b57cec5SDimitry Andric     NDesc = STE.n_desc;
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric   outs() << format(" %02x %04x ", NSect, NDesc);
6420b57cec5SDimitry Andric   if (const char *stabString = getDarwinStabString(NType))
6430b57cec5SDimitry Andric     outs() << format("%5.5s", stabString);
6440b57cec5SDimitry Andric   else
6450b57cec5SDimitry Andric     outs() << format("   %02x", NType);
6460b57cec5SDimitry Andric }
6470b57cec5SDimitry Andric 
64804eeddc0SDimitry Andric static Optional<std::string> demangle(StringRef Name) {
649349cc55cSDimitry Andric   std::string Demangled;
65004eeddc0SDimitry Andric   if (nonMicrosoftDemangle(Name.str().c_str(), Demangled))
651349cc55cSDimitry Andric     return Demangled;
6520b57cec5SDimitry Andric   return None;
6530b57cec5SDimitry Andric }
6540b57cec5SDimitry Andric 
65504eeddc0SDimitry Andric static Optional<std::string> demangleXCOFF(StringRef Name) {
65604eeddc0SDimitry Andric   if (Name.empty() || Name[0] != '.')
65704eeddc0SDimitry Andric     return demangle(Name);
65804eeddc0SDimitry Andric 
65904eeddc0SDimitry Andric   Name = Name.drop_front();
66004eeddc0SDimitry Andric   Optional<std::string> DemangledName = demangle(Name);
66104eeddc0SDimitry Andric   if (DemangledName)
66204eeddc0SDimitry Andric     return "." + *DemangledName;
66304eeddc0SDimitry Andric   return None;
66404eeddc0SDimitry Andric }
66504eeddc0SDimitry Andric 
66604eeddc0SDimitry Andric static Optional<std::string> demangleMachO(StringRef Name) {
66704eeddc0SDimitry Andric   if (!Name.empty() && Name[0] == '_')
66804eeddc0SDimitry Andric     Name = Name.drop_front();
66904eeddc0SDimitry Andric   return demangle(Name);
67004eeddc0SDimitry Andric }
67104eeddc0SDimitry Andric 
6720b57cec5SDimitry Andric static bool symbolIsDefined(const NMSymbol &Sym) {
6730b57cec5SDimitry Andric   return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric 
6765ffd83dbSDimitry Andric static void writeFileName(raw_ostream &S, StringRef ArchiveName,
6775ffd83dbSDimitry Andric                           StringRef ArchitectureName) {
6785ffd83dbSDimitry Andric   if (!ArchitectureName.empty())
6795ffd83dbSDimitry Andric     S << "(for architecture " << ArchitectureName << "):";
6805ffd83dbSDimitry Andric   if (OutputFormat == posix && !ArchiveName.empty())
6815ffd83dbSDimitry Andric     S << ArchiveName << "[" << CurrentFilename << "]: ";
6825ffd83dbSDimitry Andric   else {
6835ffd83dbSDimitry Andric     if (!ArchiveName.empty())
6845ffd83dbSDimitry Andric       S << ArchiveName << ":";
6855ffd83dbSDimitry Andric     S << CurrentFilename << ": ";
6865ffd83dbSDimitry Andric   }
6875ffd83dbSDimitry Andric }
6885ffd83dbSDimitry Andric 
689*81ad6265SDimitry Andric static void sortSymbolList(std::vector<NMSymbol> &SymbolList) {
690*81ad6265SDimitry Andric   if (NoSort)
691*81ad6265SDimitry Andric     return;
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   if (ReverseSort)
694*81ad6265SDimitry Andric     llvm::sort(SymbolList, std::greater<>());
6958bcb0991SDimitry Andric   else
696*81ad6265SDimitry Andric     llvm::sort(SymbolList);
6970b57cec5SDimitry Andric }
6980b57cec5SDimitry Andric 
699*81ad6265SDimitry Andric static void printExportSymbolList(const std::vector<NMSymbol> &SymbolList) {
700*81ad6265SDimitry Andric   for (const NMSymbol &Sym : SymbolList) {
701*81ad6265SDimitry Andric     outs() << Sym.Name;
702*81ad6265SDimitry Andric     if (!Sym.Visibility.empty())
703*81ad6265SDimitry Andric       outs() << ' ' << Sym.Visibility;
704*81ad6265SDimitry Andric     outs() << '\n';
705*81ad6265SDimitry Andric   }
706*81ad6265SDimitry Andric }
707*81ad6265SDimitry Andric 
708*81ad6265SDimitry Andric static void printSymbolList(SymbolicFile &Obj,
709*81ad6265SDimitry Andric                             std::vector<NMSymbol> &SymbolList, bool printName,
710*81ad6265SDimitry Andric                             StringRef ArchiveName, StringRef ArchitectureName) {
7110b57cec5SDimitry Andric   if (!PrintFileName) {
712fe6060f1SDimitry Andric     if ((OutputFormat == bsd || OutputFormat == posix ||
713fe6060f1SDimitry Andric          OutputFormat == just_symbols) &&
714fe6060f1SDimitry Andric         MultipleFiles && printName) {
7150b57cec5SDimitry Andric       outs() << '\n' << CurrentFilename << ":\n";
7160b57cec5SDimitry Andric     } else if (OutputFormat == sysv) {
7170b57cec5SDimitry Andric       outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n";
7180b57cec5SDimitry Andric       if (isSymbolList64Bit(Obj))
7190b57cec5SDimitry Andric         outs() << "Name                  Value           Class        Type"
7200b57cec5SDimitry Andric                << "         Size             Line  Section\n";
7210b57cec5SDimitry Andric       else
7220b57cec5SDimitry Andric         outs() << "Name                  Value   Class        Type"
7230b57cec5SDimitry Andric                << "         Size     Line  Section\n";
7240b57cec5SDimitry Andric     }
7250b57cec5SDimitry Andric   }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   const char *printBlanks, *printDashes, *printFormat;
7280b57cec5SDimitry Andric   if (isSymbolList64Bit(Obj)) {
7290b57cec5SDimitry Andric     printBlanks = "                ";
7300b57cec5SDimitry Andric     printDashes = "----------------";
7310b57cec5SDimitry Andric     switch (AddressRadix) {
7320b57cec5SDimitry Andric     case Radix::o:
7330b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64;
7340b57cec5SDimitry Andric       break;
7350b57cec5SDimitry Andric     case Radix::x:
7360b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64;
7370b57cec5SDimitry Andric       break;
7380b57cec5SDimitry Andric     default:
7390b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64;
7400b57cec5SDimitry Andric     }
7410b57cec5SDimitry Andric   } else {
7420b57cec5SDimitry Andric     printBlanks = "        ";
7430b57cec5SDimitry Andric     printDashes = "--------";
7440b57cec5SDimitry Andric     switch (AddressRadix) {
7450b57cec5SDimitry Andric     case Radix::o:
7460b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64;
7470b57cec5SDimitry Andric       break;
7480b57cec5SDimitry Andric     case Radix::x:
7490b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64;
7500b57cec5SDimitry Andric       break;
7510b57cec5SDimitry Andric     default:
7520b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64;
7530b57cec5SDimitry Andric     }
7540b57cec5SDimitry Andric   }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric   for (const NMSymbol &S : SymbolList) {
757*81ad6265SDimitry Andric     if (!S.shouldPrint())
758*81ad6265SDimitry Andric       continue;
759*81ad6265SDimitry Andric 
760e8d8bef9SDimitry Andric     std::string Name = S.Name;
7610b57cec5SDimitry Andric     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
7620b57cec5SDimitry Andric     if (Demangle) {
76304eeddc0SDimitry Andric       function_ref<Optional<std::string>(StringRef)> Fn = ::demangle;
76404eeddc0SDimitry Andric       if (Obj.isXCOFF())
76504eeddc0SDimitry Andric         Fn = demangleXCOFF;
76604eeddc0SDimitry Andric       if (Obj.isMachO())
76704eeddc0SDimitry Andric         Fn = demangleMachO;
76804eeddc0SDimitry Andric       if (Optional<std::string> Opt = Fn(S.Name))
7690b57cec5SDimitry Andric         Name = *Opt;
7700b57cec5SDimitry Andric     }
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric     if (PrintFileName)
7735ffd83dbSDimitry Andric       writeFileName(outs(), ArchiveName, ArchitectureName);
774fe6060f1SDimitry Andric     if ((OutputFormat == just_symbols ||
7750b57cec5SDimitry Andric          (UndefinedOnly && MachO && OutputFormat != darwin)) &&
7760b57cec5SDimitry Andric         OutputFormat != posix) {
7770b57cec5SDimitry Andric       outs() << Name << "\n";
7780b57cec5SDimitry Andric       continue;
7790b57cec5SDimitry Andric     }
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric     char SymbolAddrStr[23], SymbolSizeStr[23];
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric     // If the format is SysV or the symbol isn't defined, then print spaces.
7840b57cec5SDimitry Andric     if (OutputFormat == sysv || !symbolIsDefined(S)) {
7850b57cec5SDimitry Andric       if (OutputFormat == posix) {
7860b57cec5SDimitry Andric         format(printFormat, S.Address)
7870b57cec5SDimitry Andric             .print(SymbolAddrStr, sizeof(SymbolAddrStr));
7880b57cec5SDimitry Andric         format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
7890b57cec5SDimitry Andric       } else {
7900b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printBlanks);
7910b57cec5SDimitry Andric         strcpy(SymbolSizeStr, printBlanks);
7920b57cec5SDimitry Andric       }
7930b57cec5SDimitry Andric     }
7940b57cec5SDimitry Andric 
7950b57cec5SDimitry Andric     if (symbolIsDefined(S)) {
7960b57cec5SDimitry Andric       // Otherwise, print the symbol address and size.
7970b57cec5SDimitry Andric       if (Obj.isIR())
7980b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printDashes);
7990b57cec5SDimitry Andric       else if (MachO && S.TypeChar == 'I')
8000b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printBlanks);
8010b57cec5SDimitry Andric       else
8020b57cec5SDimitry Andric         format(printFormat, S.Address)
8030b57cec5SDimitry Andric             .print(SymbolAddrStr, sizeof(SymbolAddrStr));
8040b57cec5SDimitry Andric       format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
8050b57cec5SDimitry Andric     }
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric     // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
8080b57cec5SDimitry Andric     // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
8090b57cec5SDimitry Andric     // nm(1) -m output or hex, else if OutputFormat is darwin or we are
8100b57cec5SDimitry Andric     // printing Mach-O symbols in hex and not a Mach-O object fall back to
8110b57cec5SDimitry Andric     // OutputFormat bsd (see below).
8120b57cec5SDimitry Andric     if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
8130b57cec5SDimitry Andric       darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
8140b57cec5SDimitry Andric                         printFormat);
8150b57cec5SDimitry Andric     } else if (OutputFormat == posix) {
8160b57cec5SDimitry Andric       outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
8170b57cec5SDimitry Andric              << (MachO ? "0" : SymbolSizeStr) << "\n";
8180b57cec5SDimitry Andric     } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
8190b57cec5SDimitry Andric       if (PrintAddress)
8200b57cec5SDimitry Andric         outs() << SymbolAddrStr << ' ';
8210b57cec5SDimitry Andric       if (PrintSize)
8220b57cec5SDimitry Andric         outs() << SymbolSizeStr << ' ';
8230b57cec5SDimitry Andric       outs() << S.TypeChar;
8240b57cec5SDimitry Andric       if (S.TypeChar == '-' && MachO)
8250b57cec5SDimitry Andric         darwinPrintStab(MachO, S);
8260b57cec5SDimitry Andric       outs() << " " << Name;
8270b57cec5SDimitry Andric       if (S.TypeChar == 'I' && MachO) {
8280b57cec5SDimitry Andric         outs() << " (indirect for ";
8290b57cec5SDimitry Andric         if (S.Sym.getRawDataRefImpl().p) {
8300b57cec5SDimitry Andric           StringRef IndirectName;
8310b57cec5SDimitry Andric           if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
8320b57cec5SDimitry Andric             outs() << "?)";
8330b57cec5SDimitry Andric           else
8340b57cec5SDimitry Andric             outs() << IndirectName << ")";
8350b57cec5SDimitry Andric         } else
8360b57cec5SDimitry Andric           outs() << S.IndirectName << ")";
8370b57cec5SDimitry Andric       }
8380b57cec5SDimitry Andric       outs() << "\n";
8390b57cec5SDimitry Andric     } else if (OutputFormat == sysv) {
8400b57cec5SDimitry Andric       outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "|   "
8410b57cec5SDimitry Andric              << S.TypeChar << "  |" << right_justify(S.TypeName, 18) << "|"
8420b57cec5SDimitry Andric              << SymbolSizeStr << "|     |" << S.SectionName << "\n";
8430b57cec5SDimitry Andric     }
8440b57cec5SDimitry Andric   }
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric   SymbolList.clear();
8470b57cec5SDimitry Andric }
8480b57cec5SDimitry Andric 
8490b57cec5SDimitry Andric static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
8500b57cec5SDimitry Andric                                 basic_symbol_iterator I) {
8510b57cec5SDimitry Andric   // OK, this is ELF
8520b57cec5SDimitry Andric   elf_symbol_iterator SymI(I);
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric   Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
8550b57cec5SDimitry Andric   if (!SecIOrErr) {
8560b57cec5SDimitry Andric     consumeError(SecIOrErr.takeError());
8570b57cec5SDimitry Andric     return '?';
8580b57cec5SDimitry Andric   }
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric   uint8_t Binding = SymI->getBinding();
8610b57cec5SDimitry Andric   if (Binding == ELF::STB_GNU_UNIQUE)
8620b57cec5SDimitry Andric     return 'u';
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
8650b57cec5SDimitry Andric   if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
8660b57cec5SDimitry Andric     return '?';
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric   elf_section_iterator SecI = *SecIOrErr;
8690b57cec5SDimitry Andric   if (SecI != Obj.section_end()) {
8700b57cec5SDimitry Andric     uint32_t Type = SecI->getType();
8710b57cec5SDimitry Andric     uint64_t Flags = SecI->getFlags();
8720b57cec5SDimitry Andric     if (Flags & ELF::SHF_EXECINSTR)
8730b57cec5SDimitry Andric       return 't';
8740b57cec5SDimitry Andric     if (Type == ELF::SHT_NOBITS)
8750b57cec5SDimitry Andric       return 'b';
8760b57cec5SDimitry Andric     if (Flags & ELF::SHF_ALLOC)
8770b57cec5SDimitry Andric       return Flags & ELF::SHF_WRITE ? 'd' : 'r';
8780b57cec5SDimitry Andric 
8798bcb0991SDimitry Andric     auto NameOrErr = SecI->getName();
8808bcb0991SDimitry Andric     if (!NameOrErr) {
8818bcb0991SDimitry Andric       consumeError(NameOrErr.takeError());
8820b57cec5SDimitry Andric       return '?';
8838bcb0991SDimitry Andric     }
8848bcb0991SDimitry Andric     if ((*NameOrErr).startswith(".debug"))
8850b57cec5SDimitry Andric       return 'N';
8860b57cec5SDimitry Andric     if (!(Flags & ELF::SHF_WRITE))
8870b57cec5SDimitry Andric       return 'n';
8880b57cec5SDimitry Andric   }
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric   return '?';
8910b57cec5SDimitry Andric }
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
8940b57cec5SDimitry Andric   COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
8950b57cec5SDimitry Andric   // OK, this is COFF.
8960b57cec5SDimitry Andric   symbol_iterator SymI(I);
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   Expected<StringRef> Name = SymI->getName();
8990b57cec5SDimitry Andric   if (!Name) {
9000b57cec5SDimitry Andric     consumeError(Name.takeError());
9010b57cec5SDimitry Andric     return '?';
9020b57cec5SDimitry Andric   }
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric   char Ret = StringSwitch<char>(*Name)
9050b57cec5SDimitry Andric                  .StartsWith(".debug", 'N')
9060b57cec5SDimitry Andric                  .StartsWith(".sxdata", 'N')
9070b57cec5SDimitry Andric                  .Default('?');
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   if (Ret != '?')
9100b57cec5SDimitry Andric     return Ret;
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric   uint32_t Characteristics = 0;
9130b57cec5SDimitry Andric   if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
9140b57cec5SDimitry Andric     Expected<section_iterator> SecIOrErr = SymI->getSection();
9150b57cec5SDimitry Andric     if (!SecIOrErr) {
9160b57cec5SDimitry Andric       consumeError(SecIOrErr.takeError());
9170b57cec5SDimitry Andric       return '?';
9180b57cec5SDimitry Andric     }
9190b57cec5SDimitry Andric     section_iterator SecI = *SecIOrErr;
9200b57cec5SDimitry Andric     const coff_section *Section = Obj.getCOFFSection(*SecI);
9210b57cec5SDimitry Andric     Characteristics = Section->Characteristics;
9220b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
9230b57cec5SDimitry Andric       if (NameOrErr->startswith(".idata"))
9240b57cec5SDimitry Andric         return 'i';
9250b57cec5SDimitry Andric   }
9260b57cec5SDimitry Andric 
9270b57cec5SDimitry Andric   switch (Symb.getSectionNumber()) {
9280b57cec5SDimitry Andric   case COFF::IMAGE_SYM_DEBUG:
9290b57cec5SDimitry Andric     return 'n';
9300b57cec5SDimitry Andric   default:
9310b57cec5SDimitry Andric     // Check section type.
9320b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
9330b57cec5SDimitry Andric       return 't';
9340b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
9350b57cec5SDimitry Andric       return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
9360b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
9370b57cec5SDimitry Andric       return 'b';
9380b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
9390b57cec5SDimitry Andric       return 'i';
9400b57cec5SDimitry Andric     // Check for section symbol.
9410b57cec5SDimitry Andric     if (Symb.isSectionDefinition())
9420b57cec5SDimitry Andric       return 's';
9430b57cec5SDimitry Andric   }
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric   return '?';
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric 
94804eeddc0SDimitry Andric static char getSymbolNMTypeChar(XCOFFObjectFile &Obj, symbol_iterator I) {
94904eeddc0SDimitry Andric   Expected<uint32_t> TypeOrErr = I->getType();
95004eeddc0SDimitry Andric   if (!TypeOrErr) {
95104eeddc0SDimitry Andric     warn(TypeOrErr.takeError(), Obj.getFileName(),
95204eeddc0SDimitry Andric          "for symbol with index " +
95304eeddc0SDimitry Andric              Twine(Obj.getSymbolIndex(I->getRawDataRefImpl().p)));
95404eeddc0SDimitry Andric     return '?';
95504eeddc0SDimitry Andric   }
95604eeddc0SDimitry Andric 
95704eeddc0SDimitry Andric   uint32_t SymType = *TypeOrErr;
95804eeddc0SDimitry Andric 
95904eeddc0SDimitry Andric   if (SymType == SymbolRef::ST_File)
96004eeddc0SDimitry Andric     return 'f';
96104eeddc0SDimitry Andric 
96204eeddc0SDimitry Andric   // If the I->getSection() call would return an error, the earlier I->getType()
96304eeddc0SDimitry Andric   // call will already have returned the same error first.
96404eeddc0SDimitry Andric   section_iterator SecIter = cantFail(I->getSection());
96504eeddc0SDimitry Andric 
96604eeddc0SDimitry Andric   if (SecIter == Obj.section_end())
96704eeddc0SDimitry Andric     return '?';
96804eeddc0SDimitry Andric 
96904eeddc0SDimitry Andric   if (Obj.isDebugSection(SecIter->getRawDataRefImpl()))
97004eeddc0SDimitry Andric     return 'N';
97104eeddc0SDimitry Andric 
97204eeddc0SDimitry Andric   if (SecIter->isText())
97304eeddc0SDimitry Andric     return 't';
97404eeddc0SDimitry Andric 
97504eeddc0SDimitry Andric   if (SecIter->isData())
97604eeddc0SDimitry Andric     return 'd';
97704eeddc0SDimitry Andric 
97804eeddc0SDimitry Andric   if (SecIter->isBSS())
97904eeddc0SDimitry Andric     return 'b';
98004eeddc0SDimitry Andric 
98104eeddc0SDimitry Andric   return '?';
98204eeddc0SDimitry Andric }
98304eeddc0SDimitry Andric 
9840b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFImportFile &Obj) {
9850b57cec5SDimitry Andric   switch (Obj.getCOFFImportHeader()->getType()) {
9860b57cec5SDimitry Andric   case COFF::IMPORT_CODE:
9870b57cec5SDimitry Andric     return 't';
9880b57cec5SDimitry Andric   case COFF::IMPORT_DATA:
9890b57cec5SDimitry Andric     return 'd';
9900b57cec5SDimitry Andric   case COFF::IMPORT_CONST:
9910b57cec5SDimitry Andric     return 'r';
9920b57cec5SDimitry Andric   }
9930b57cec5SDimitry Andric   return '?';
9940b57cec5SDimitry Andric }
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
9970b57cec5SDimitry Andric   DataRefImpl Symb = I->getRawDataRefImpl();
9980b57cec5SDimitry Andric   uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
9990b57cec5SDimitry Andric                                 : Obj.getSymbolTableEntry(Symb).n_type;
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   if (NType & MachO::N_STAB)
10020b57cec5SDimitry Andric     return '-';
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric   switch (NType & MachO::N_TYPE) {
10050b57cec5SDimitry Andric   case MachO::N_ABS:
10060b57cec5SDimitry Andric     return 's';
10070b57cec5SDimitry Andric   case MachO::N_INDR:
10080b57cec5SDimitry Andric     return 'i';
10090b57cec5SDimitry Andric   case MachO::N_SECT: {
10100b57cec5SDimitry Andric     Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb);
10110b57cec5SDimitry Andric     if (!SecOrErr) {
10120b57cec5SDimitry Andric       consumeError(SecOrErr.takeError());
10130b57cec5SDimitry Andric       return 's';
10140b57cec5SDimitry Andric     }
10150b57cec5SDimitry Andric     section_iterator Sec = *SecOrErr;
10160b57cec5SDimitry Andric     if (Sec == Obj.section_end())
10170b57cec5SDimitry Andric       return 's';
10180b57cec5SDimitry Andric     DataRefImpl Ref = Sec->getRawDataRefImpl();
10190b57cec5SDimitry Andric     StringRef SectionName;
10200b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
10210b57cec5SDimitry Andric       SectionName = *NameOrErr;
10220b57cec5SDimitry Andric     StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
10230b57cec5SDimitry Andric     if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
10240b57cec5SDimitry Andric         SegmentName == "__TEXT_EXEC" && SectionName == "__text")
10250b57cec5SDimitry Andric       return 't';
10260b57cec5SDimitry Andric     if (SegmentName == "__TEXT" && SectionName == "__text")
10270b57cec5SDimitry Andric       return 't';
10280b57cec5SDimitry Andric     if (SegmentName == "__DATA" && SectionName == "__data")
10290b57cec5SDimitry Andric       return 'd';
10300b57cec5SDimitry Andric     if (SegmentName == "__DATA" && SectionName == "__bss")
10310b57cec5SDimitry Andric       return 'b';
10320b57cec5SDimitry Andric     return 's';
10330b57cec5SDimitry Andric   }
10340b57cec5SDimitry Andric   }
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric   return '?';
10370b57cec5SDimitry Andric }
10380b57cec5SDimitry Andric 
10395ffd83dbSDimitry Andric static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
10405ffd83dbSDimitry Andric   return 's';
10415ffd83dbSDimitry Andric }
10425ffd83dbSDimitry Andric 
10430b57cec5SDimitry Andric static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
10445ffd83dbSDimitry Andric   uint32_t Flags = cantFail(I->getFlags());
10450b57cec5SDimitry Andric   if (Flags & SymbolRef::SF_Executable)
10460b57cec5SDimitry Andric     return 't';
10470b57cec5SDimitry Andric   return 'd';
10480b57cec5SDimitry Andric }
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
10515ffd83dbSDimitry Andric   uint32_t Flags = cantFail(I->getFlags());
10520b57cec5SDimitry Andric   // FIXME: should we print 'b'? At the IR level we cannot be sure if this
10530b57cec5SDimitry Andric   // will be in bss or not, but we could approximate.
10540b57cec5SDimitry Andric   if (Flags & SymbolRef::SF_Executable)
10550b57cec5SDimitry Andric     return 't';
10560b57cec5SDimitry Andric   else if (Triple(Obj.getTargetTriple()).isOSDarwin() &&
10570b57cec5SDimitry Andric            (Flags & SymbolRef::SF_Const))
10580b57cec5SDimitry Andric     return 's';
10590b57cec5SDimitry Andric   else
10600b57cec5SDimitry Andric     return 'd';
10610b57cec5SDimitry Andric }
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
1064e8d8bef9SDimitry Andric   return isa<ELFObjectFileBase>(&Obj) &&
1065e8d8bef9SDimitry Andric          elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
10660b57cec5SDimitry Andric }
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric // For ELF object files, Set TypeName to the symbol typename, to be printed
10690b57cec5SDimitry Andric // in the 'Type' column of the SYSV format output.
10700b57cec5SDimitry Andric static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
10710b57cec5SDimitry Andric   if (isa<ELFObjectFileBase>(&Obj)) {
10720b57cec5SDimitry Andric     elf_symbol_iterator SymI(I);
10730b57cec5SDimitry Andric     return SymI->getELFTypeName();
10740b57cec5SDimitry Andric   }
10750b57cec5SDimitry Andric   return "";
10760b57cec5SDimitry Andric }
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric // Return Posix nm class type tag (single letter), but also set SecName and
10790b57cec5SDimitry Andric // section and name, to be used in format=sysv output.
10800b57cec5SDimitry Andric static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
10810b57cec5SDimitry Andric                                    StringRef &SecName) {
10825ffd83dbSDimitry Andric   // Symbol Flags have been checked in the caller.
10835ffd83dbSDimitry Andric   uint32_t Symflags = cantFail(I->getFlags());
10848bcb0991SDimitry Andric   if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {
10850b57cec5SDimitry Andric     if (Symflags & object::SymbolRef::SF_Absolute)
10860b57cec5SDimitry Andric       SecName = "*ABS*";
10870b57cec5SDimitry Andric     else if (Symflags & object::SymbolRef::SF_Common)
10880b57cec5SDimitry Andric       SecName = "*COM*";
10890b57cec5SDimitry Andric     else if (Symflags & object::SymbolRef::SF_Undefined)
10900b57cec5SDimitry Andric       SecName = "*UND*";
10910b57cec5SDimitry Andric     else {
10920b57cec5SDimitry Andric       elf_symbol_iterator SymI(I);
10930b57cec5SDimitry Andric       Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
10940b57cec5SDimitry Andric       if (!SecIOrErr) {
10950b57cec5SDimitry Andric         consumeError(SecIOrErr.takeError());
10960b57cec5SDimitry Andric         return '?';
10970b57cec5SDimitry Andric       }
10988bcb0991SDimitry Andric 
10998bcb0991SDimitry Andric       if (*SecIOrErr == ELFObj->section_end())
11008bcb0991SDimitry Andric         return '?';
11018bcb0991SDimitry Andric 
11028bcb0991SDimitry Andric       Expected<StringRef> NameOrErr = (*SecIOrErr)->getName();
11038bcb0991SDimitry Andric       if (!NameOrErr) {
11048bcb0991SDimitry Andric         consumeError(NameOrErr.takeError());
11058bcb0991SDimitry Andric         return '?';
11068bcb0991SDimitry Andric       }
11078bcb0991SDimitry Andric       SecName = *NameOrErr;
11080b57cec5SDimitry Andric     }
11090b57cec5SDimitry Andric   }
11100b57cec5SDimitry Andric 
1111fe6060f1SDimitry Andric   if (Symflags & object::SymbolRef::SF_Undefined) {
1112fe6060f1SDimitry Andric     if (isa<MachOObjectFile>(Obj) || !(Symflags & object::SymbolRef::SF_Weak))
11130b57cec5SDimitry Andric       return 'U';
1114fe6060f1SDimitry Andric     return isObject(Obj, I) ? 'v' : 'w';
1115fe6060f1SDimitry Andric   }
1116fe6060f1SDimitry Andric   if (isa<ELFObjectFileBase>(&Obj))
1117fe6060f1SDimitry Andric     if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC)
1118fe6060f1SDimitry Andric       return 'i';
1119fe6060f1SDimitry Andric   if (!isa<MachOObjectFile>(Obj) && (Symflags & object::SymbolRef::SF_Weak))
1120fe6060f1SDimitry Andric     return isObject(Obj, I) ? 'V' : 'W';
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric   if (Symflags & object::SymbolRef::SF_Common)
11230b57cec5SDimitry Andric     return 'C';
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric   char Ret = '?';
11260b57cec5SDimitry Andric   if (Symflags & object::SymbolRef::SF_Absolute)
11270b57cec5SDimitry Andric     Ret = 'a';
11280b57cec5SDimitry Andric   else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
11290b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*IR, I);
11300b57cec5SDimitry Andric   else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
11310b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*COFF, I);
113204eeddc0SDimitry Andric   else if (XCOFFObjectFile *XCOFF = dyn_cast<XCOFFObjectFile>(&Obj))
113304eeddc0SDimitry Andric     Ret = getSymbolNMTypeChar(*XCOFF, I);
11340b57cec5SDimitry Andric   else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
11350b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*COFFImport);
11360b57cec5SDimitry Andric   else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
11370b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*MachO, I);
11380b57cec5SDimitry Andric   else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
11390b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*Wasm, I);
11405ffd83dbSDimitry Andric   else if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
11415ffd83dbSDimitry Andric     Ret = getSymbolNMTypeChar(*Tapi, I);
1142480093f4SDimitry Andric   else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) {
1143480093f4SDimitry Andric     Ret = getSymbolNMTypeChar(*ELF, I);
1144480093f4SDimitry Andric     if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
1145480093f4SDimitry Andric       return Ret;
1146480093f4SDimitry Andric   } else
1147480093f4SDimitry Andric     llvm_unreachable("unknown binary format");
11480b57cec5SDimitry Andric 
11490b57cec5SDimitry Andric   if (!(Symflags & object::SymbolRef::SF_Global))
11500b57cec5SDimitry Andric     return Ret;
11510b57cec5SDimitry Andric 
11520b57cec5SDimitry Andric   return toupper(Ret);
11530b57cec5SDimitry Andric }
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric // getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
11560b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
1157*81ad6265SDimitry Andric // It is called once for each Mach-O file from getSymbolNamesFromObject()
11580b57cec5SDimitry Andric // to get the section number for that named section from the command line
11590b57cec5SDimitry Andric // arguments. It returns the section number for that section in the Mach-O
11600b57cec5SDimitry Andric // file or zero it is not present.
11610b57cec5SDimitry Andric static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
11620b57cec5SDimitry Andric   unsigned Nsect = 1;
11630b57cec5SDimitry Andric   for (auto &S : Obj->sections()) {
11640b57cec5SDimitry Andric     DataRefImpl Ref = S.getRawDataRefImpl();
11650b57cec5SDimitry Andric     StringRef SectionName;
11660b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
11670b57cec5SDimitry Andric       SectionName = *NameOrErr;
11680b57cec5SDimitry Andric     StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
11690b57cec5SDimitry Andric     if (SegmentName == SegSect[0] && SectionName == SegSect[1])
11700b57cec5SDimitry Andric       return Nsect;
11710b57cec5SDimitry Andric     Nsect++;
11720b57cec5SDimitry Andric   }
11730b57cec5SDimitry Andric   return 0;
11740b57cec5SDimitry Andric }
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric // getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
11770b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
11780b57cec5SDimitry Andric // It is called once for each symbol in a Mach-O file from
1179*81ad6265SDimitry Andric // getSymbolNamesFromObject() and returns the section number for that symbol
11800b57cec5SDimitry Andric // if it is in a section, else it returns 0.
11810b57cec5SDimitry Andric static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
11820b57cec5SDimitry Andric   DataRefImpl Symb = Sym.getRawDataRefImpl();
11830b57cec5SDimitry Andric   if (Obj.is64Bit()) {
11840b57cec5SDimitry Andric     MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
11850b57cec5SDimitry Andric     return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
11860b57cec5SDimitry Andric   }
11870b57cec5SDimitry Andric   MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
11880b57cec5SDimitry Andric   return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
11890b57cec5SDimitry Andric }
11900b57cec5SDimitry Andric 
1191*81ad6265SDimitry Andric static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO,
1192*81ad6265SDimitry Andric                                        std::vector<NMSymbol> &SymbolList) {
1193e8d8bef9SDimitry Andric   size_t I = SymbolList.size();
11940b57cec5SDimitry Andric   std::string ExportsNameBuffer;
11950b57cec5SDimitry Andric   raw_string_ostream EOS(ExportsNameBuffer);
11960b57cec5SDimitry Andric   std::string BindsNameBuffer;
11970b57cec5SDimitry Andric   raw_string_ostream BOS(BindsNameBuffer);
11980b57cec5SDimitry Andric   std::string LazysNameBuffer;
11990b57cec5SDimitry Andric   raw_string_ostream LOS(LazysNameBuffer);
12000b57cec5SDimitry Andric   std::string WeaksNameBuffer;
12010b57cec5SDimitry Andric   raw_string_ostream WOS(WeaksNameBuffer);
12020b57cec5SDimitry Andric   std::string FunctionStartsNameBuffer;
12030b57cec5SDimitry Andric   raw_string_ostream FOS(FunctionStartsNameBuffer);
1204e8d8bef9SDimitry Andric 
12050b57cec5SDimitry Andric   MachO::mach_header H;
12060b57cec5SDimitry Andric   MachO::mach_header_64 H_64;
12070b57cec5SDimitry Andric   uint32_t HFlags = 0;
1208e8d8bef9SDimitry Andric   if (MachO.is64Bit()) {
1209e8d8bef9SDimitry Andric     H_64 = MachO.MachOObjectFile::getHeader64();
12100b57cec5SDimitry Andric     HFlags = H_64.flags;
12110b57cec5SDimitry Andric   } else {
1212e8d8bef9SDimitry Andric     H = MachO.MachOObjectFile::getHeader();
12130b57cec5SDimitry Andric     HFlags = H.flags;
12140b57cec5SDimitry Andric   }
12150b57cec5SDimitry Andric   uint64_t BaseSegmentAddress = 0;
1216e8d8bef9SDimitry Andric   for (const auto &Command : MachO.load_commands()) {
12170b57cec5SDimitry Andric     if (Command.C.cmd == MachO::LC_SEGMENT) {
1218e8d8bef9SDimitry Andric       MachO::segment_command Seg = MachO.getSegmentLoadCommand(Command);
12190b57cec5SDimitry Andric       if (Seg.fileoff == 0 && Seg.filesize != 0) {
12200b57cec5SDimitry Andric         BaseSegmentAddress = Seg.vmaddr;
12210b57cec5SDimitry Andric         break;
12220b57cec5SDimitry Andric       }
12230b57cec5SDimitry Andric     } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1224e8d8bef9SDimitry Andric       MachO::segment_command_64 Seg = MachO.getSegment64LoadCommand(Command);
12250b57cec5SDimitry Andric       if (Seg.fileoff == 0 && Seg.filesize != 0) {
12260b57cec5SDimitry Andric         BaseSegmentAddress = Seg.vmaddr;
12270b57cec5SDimitry Andric         break;
12280b57cec5SDimitry Andric       }
12290b57cec5SDimitry Andric     }
12300b57cec5SDimitry Andric   }
12310b57cec5SDimitry Andric   if (DyldInfoOnly || AddDyldInfo ||
12320b57cec5SDimitry Andric       HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
12330b57cec5SDimitry Andric     unsigned ExportsAdded = 0;
12340b57cec5SDimitry Andric     Error Err = Error::success();
1235e8d8bef9SDimitry Andric     for (const llvm::object::ExportEntry &Entry : MachO.exports(Err)) {
12360b57cec5SDimitry Andric       bool found = false;
12370b57cec5SDimitry Andric       bool ReExport = false;
12380b57cec5SDimitry Andric       if (!DyldInfoOnly) {
12390b57cec5SDimitry Andric         for (const NMSymbol &S : SymbolList)
12400b57cec5SDimitry Andric           if (S.Address == Entry.address() + BaseSegmentAddress &&
12410b57cec5SDimitry Andric               S.Name == Entry.name()) {
12420b57cec5SDimitry Andric             found = true;
12430b57cec5SDimitry Andric             break;
12440b57cec5SDimitry Andric           }
12450b57cec5SDimitry Andric       }
12460b57cec5SDimitry Andric       if (!found) {
12470b57cec5SDimitry Andric         NMSymbol S = {};
12480b57cec5SDimitry Andric         S.Address = Entry.address() + BaseSegmentAddress;
12490b57cec5SDimitry Andric         S.Size = 0;
12500b57cec5SDimitry Andric         S.TypeChar = '\0';
1251e8d8bef9SDimitry Andric         S.Name = Entry.name().str();
12520b57cec5SDimitry Andric         // There is no symbol in the nlist symbol table for this so we set
12530b57cec5SDimitry Andric         // Sym effectivly to null and the rest of code in here must test for
12540b57cec5SDimitry Andric         // it and not do things like Sym.getFlags() for it.
12550b57cec5SDimitry Andric         S.Sym = BasicSymbolRef();
12560b57cec5SDimitry Andric         S.SymFlags = SymbolRef::SF_Global;
12570b57cec5SDimitry Andric         S.Section = SectionRef();
12580b57cec5SDimitry Andric         S.NType = 0;
12590b57cec5SDimitry Andric         S.NSect = 0;
12600b57cec5SDimitry Andric         S.NDesc = 0;
12610b57cec5SDimitry Andric 
12620b57cec5SDimitry Andric         uint64_t EFlags = Entry.flags();
12630b57cec5SDimitry Andric         bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
12640b57cec5SDimitry Andric                     MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
1265e8d8bef9SDimitry Andric         bool Resolver = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
12660b57cec5SDimitry Andric         ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
12670b57cec5SDimitry Andric         bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
12680b57cec5SDimitry Andric         if (WeakDef)
12690b57cec5SDimitry Andric           S.NDesc |= MachO::N_WEAK_DEF;
12700b57cec5SDimitry Andric         if (Abs) {
12710b57cec5SDimitry Andric           S.NType = MachO::N_EXT | MachO::N_ABS;
12720b57cec5SDimitry Andric           S.TypeChar = 'A';
12730b57cec5SDimitry Andric         } else if (ReExport) {
12740b57cec5SDimitry Andric           S.NType = MachO::N_EXT | MachO::N_INDR;
12750b57cec5SDimitry Andric           S.TypeChar = 'I';
12760b57cec5SDimitry Andric         } else {
12770b57cec5SDimitry Andric           S.NType = MachO::N_EXT | MachO::N_SECT;
12780b57cec5SDimitry Andric           if (Resolver) {
12790b57cec5SDimitry Andric             S.Address = Entry.other() + BaseSegmentAddress;
1280e8d8bef9SDimitry Andric             if ((S.Address & 1) != 0 && !MachO.is64Bit() &&
1281e8d8bef9SDimitry Andric                 H.cputype == MachO::CPU_TYPE_ARM) {
12820b57cec5SDimitry Andric               S.Address &= ~1LL;
12830b57cec5SDimitry Andric               S.NDesc |= MachO::N_ARM_THUMB_DEF;
12840b57cec5SDimitry Andric             }
12850b57cec5SDimitry Andric           } else {
12860b57cec5SDimitry Andric             S.Address = Entry.address() + BaseSegmentAddress;
12870b57cec5SDimitry Andric           }
12880b57cec5SDimitry Andric           StringRef SegmentName = StringRef();
12890b57cec5SDimitry Andric           StringRef SectionName = StringRef();
1290e8d8bef9SDimitry Andric           for (const SectionRef &Section : MachO.sections()) {
12910b57cec5SDimitry Andric             S.NSect++;
12928bcb0991SDimitry Andric 
12938bcb0991SDimitry Andric             if (Expected<StringRef> NameOrErr = Section.getName())
12948bcb0991SDimitry Andric               SectionName = *NameOrErr;
12958bcb0991SDimitry Andric             else
12968bcb0991SDimitry Andric               consumeError(NameOrErr.takeError());
12978bcb0991SDimitry Andric 
1298e8d8bef9SDimitry Andric             SegmentName =
1299e8d8bef9SDimitry Andric                 MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
13000b57cec5SDimitry Andric             if (S.Address >= Section.getAddress() &&
13010b57cec5SDimitry Andric                 S.Address < Section.getAddress() + Section.getSize()) {
13020b57cec5SDimitry Andric               S.Section = Section;
13030b57cec5SDimitry Andric               break;
13040b57cec5SDimitry Andric             } else if (Entry.name() == "__mh_execute_header" &&
13050b57cec5SDimitry Andric                        SegmentName == "__TEXT" && SectionName == "__text") {
13060b57cec5SDimitry Andric               S.Section = Section;
13070b57cec5SDimitry Andric               S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
13080b57cec5SDimitry Andric               break;
13090b57cec5SDimitry Andric             }
13100b57cec5SDimitry Andric           }
13110b57cec5SDimitry Andric           if (SegmentName == "__TEXT" && SectionName == "__text")
13120b57cec5SDimitry Andric             S.TypeChar = 'T';
13130b57cec5SDimitry Andric           else if (SegmentName == "__DATA" && SectionName == "__data")
13140b57cec5SDimitry Andric             S.TypeChar = 'D';
13150b57cec5SDimitry Andric           else if (SegmentName == "__DATA" && SectionName == "__bss")
13160b57cec5SDimitry Andric             S.TypeChar = 'B';
13170b57cec5SDimitry Andric           else
13180b57cec5SDimitry Andric             S.TypeChar = 'S';
13190b57cec5SDimitry Andric         }
13200b57cec5SDimitry Andric         SymbolList.push_back(S);
13210b57cec5SDimitry Andric 
13220b57cec5SDimitry Andric         EOS << Entry.name();
13230b57cec5SDimitry Andric         EOS << '\0';
13240b57cec5SDimitry Andric         ExportsAdded++;
13250b57cec5SDimitry Andric 
13260b57cec5SDimitry Andric         // For ReExports there are a two more things to do, first add the
13270b57cec5SDimitry Andric         // indirect name and second create the undefined symbol using the
13280b57cec5SDimitry Andric         // referened dynamic library.
13290b57cec5SDimitry Andric         if (ReExport) {
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric           // Add the indirect name.
13320b57cec5SDimitry Andric           if (Entry.otherName().empty())
13330b57cec5SDimitry Andric             EOS << Entry.name();
13340b57cec5SDimitry Andric           else
13350b57cec5SDimitry Andric             EOS << Entry.otherName();
13360b57cec5SDimitry Andric           EOS << '\0';
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric           // Now create the undefined symbol using the referened dynamic
13390b57cec5SDimitry Andric           // library.
13400b57cec5SDimitry Andric           NMSymbol U = {};
13410b57cec5SDimitry Andric           U.Address = 0;
13420b57cec5SDimitry Andric           U.Size = 0;
13430b57cec5SDimitry Andric           U.TypeChar = 'U';
13440b57cec5SDimitry Andric           if (Entry.otherName().empty())
1345e8d8bef9SDimitry Andric             U.Name = Entry.name().str();
13460b57cec5SDimitry Andric           else
1347e8d8bef9SDimitry Andric             U.Name = Entry.otherName().str();
13480b57cec5SDimitry Andric           // Again there is no symbol in the nlist symbol table for this so
13490b57cec5SDimitry Andric           // we set Sym effectivly to null and the rest of code in here must
13500b57cec5SDimitry Andric           // test for it and not do things like Sym.getFlags() for it.
13510b57cec5SDimitry Andric           U.Sym = BasicSymbolRef();
13520b57cec5SDimitry Andric           U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
13530b57cec5SDimitry Andric           U.Section = SectionRef();
13540b57cec5SDimitry Andric           U.NType = MachO::N_EXT | MachO::N_UNDF;
13550b57cec5SDimitry Andric           U.NSect = 0;
13560b57cec5SDimitry Andric           U.NDesc = 0;
13570b57cec5SDimitry Andric           // The library ordinal for this undefined symbol is in the export
13580b57cec5SDimitry Andric           // trie Entry.other().
13590b57cec5SDimitry Andric           MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
13600b57cec5SDimitry Andric           SymbolList.push_back(U);
13610b57cec5SDimitry Andric 
13620b57cec5SDimitry Andric           // Finally add the undefined symbol's name.
13630b57cec5SDimitry Andric           if (Entry.otherName().empty())
13640b57cec5SDimitry Andric             EOS << Entry.name();
13650b57cec5SDimitry Andric           else
13660b57cec5SDimitry Andric             EOS << Entry.otherName();
13670b57cec5SDimitry Andric           EOS << '\0';
13680b57cec5SDimitry Andric           ExportsAdded++;
13690b57cec5SDimitry Andric         }
13700b57cec5SDimitry Andric       }
13710b57cec5SDimitry Andric     }
13720b57cec5SDimitry Andric     if (Err)
1373e8d8bef9SDimitry Andric       error(std::move(Err), MachO.getFileName());
13740b57cec5SDimitry Andric     // Set the symbol names and indirect names for the added symbols.
13750b57cec5SDimitry Andric     if (ExportsAdded) {
13760b57cec5SDimitry Andric       EOS.flush();
13770b57cec5SDimitry Andric       const char *Q = ExportsNameBuffer.c_str();
13780b57cec5SDimitry Andric       for (unsigned K = 0; K < ExportsAdded; K++) {
13790b57cec5SDimitry Andric         SymbolList[I].Name = Q;
13800b57cec5SDimitry Andric         Q += strlen(Q) + 1;
13810b57cec5SDimitry Andric         if (SymbolList[I].TypeChar == 'I') {
13820b57cec5SDimitry Andric           SymbolList[I].IndirectName = Q;
13830b57cec5SDimitry Andric           Q += strlen(Q) + 1;
13840b57cec5SDimitry Andric         }
13850b57cec5SDimitry Andric         I++;
13860b57cec5SDimitry Andric       }
13870b57cec5SDimitry Andric     }
13880b57cec5SDimitry Andric 
13890b57cec5SDimitry Andric     // Add the undefined symbols from the bind entries.
13900b57cec5SDimitry Andric     unsigned BindsAdded = 0;
13910b57cec5SDimitry Andric     Error BErr = Error::success();
13920b57cec5SDimitry Andric     StringRef LastSymbolName = StringRef();
1393e8d8bef9SDimitry Andric     for (const llvm::object::MachOBindEntry &Entry : MachO.bindTable(BErr)) {
13940b57cec5SDimitry Andric       bool found = false;
13950b57cec5SDimitry Andric       if (LastSymbolName == Entry.symbolName())
13960b57cec5SDimitry Andric         found = true;
13970b57cec5SDimitry Andric       else if (!DyldInfoOnly) {
13980b57cec5SDimitry Andric         for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
13990b57cec5SDimitry Andric           if (SymbolList[J].Name == Entry.symbolName())
14000b57cec5SDimitry Andric             found = true;
14010b57cec5SDimitry Andric         }
14020b57cec5SDimitry Andric       }
14030b57cec5SDimitry Andric       if (!found) {
14040b57cec5SDimitry Andric         LastSymbolName = Entry.symbolName();
14050b57cec5SDimitry Andric         NMSymbol B = {};
14060b57cec5SDimitry Andric         B.Address = 0;
14070b57cec5SDimitry Andric         B.Size = 0;
14080b57cec5SDimitry Andric         B.TypeChar = 'U';
14090b57cec5SDimitry Andric         // There is no symbol in the nlist symbol table for this so we set
14100b57cec5SDimitry Andric         // Sym effectivly to null and the rest of code in here must test for
14110b57cec5SDimitry Andric         // it and not do things like Sym.getFlags() for it.
14120b57cec5SDimitry Andric         B.Sym = BasicSymbolRef();
14130b57cec5SDimitry Andric         B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
14140b57cec5SDimitry Andric         B.NType = MachO::N_EXT | MachO::N_UNDF;
14150b57cec5SDimitry Andric         B.NSect = 0;
14160b57cec5SDimitry Andric         B.NDesc = 0;
14170b57cec5SDimitry Andric         MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
1418e8d8bef9SDimitry Andric         B.Name = Entry.symbolName().str();
14190b57cec5SDimitry Andric         SymbolList.push_back(B);
14200b57cec5SDimitry Andric         BOS << Entry.symbolName();
14210b57cec5SDimitry Andric         BOS << '\0';
14220b57cec5SDimitry Andric         BindsAdded++;
14230b57cec5SDimitry Andric       }
14240b57cec5SDimitry Andric     }
14250b57cec5SDimitry Andric     if (BErr)
1426e8d8bef9SDimitry Andric       error(std::move(BErr), MachO.getFileName());
14270b57cec5SDimitry Andric     // Set the symbol names and indirect names for the added symbols.
14280b57cec5SDimitry Andric     if (BindsAdded) {
14290b57cec5SDimitry Andric       BOS.flush();
14300b57cec5SDimitry Andric       const char *Q = BindsNameBuffer.c_str();
14310b57cec5SDimitry Andric       for (unsigned K = 0; K < BindsAdded; K++) {
14320b57cec5SDimitry Andric         SymbolList[I].Name = Q;
14330b57cec5SDimitry Andric         Q += strlen(Q) + 1;
14340b57cec5SDimitry Andric         if (SymbolList[I].TypeChar == 'I') {
14350b57cec5SDimitry Andric           SymbolList[I].IndirectName = Q;
14360b57cec5SDimitry Andric           Q += strlen(Q) + 1;
14370b57cec5SDimitry Andric         }
14380b57cec5SDimitry Andric         I++;
14390b57cec5SDimitry Andric       }
14400b57cec5SDimitry Andric     }
14410b57cec5SDimitry Andric 
14420b57cec5SDimitry Andric     // Add the undefined symbols from the lazy bind entries.
14430b57cec5SDimitry Andric     unsigned LazysAdded = 0;
14440b57cec5SDimitry Andric     Error LErr = Error::success();
14450b57cec5SDimitry Andric     LastSymbolName = StringRef();
14460b57cec5SDimitry Andric     for (const llvm::object::MachOBindEntry &Entry :
1447e8d8bef9SDimitry Andric          MachO.lazyBindTable(LErr)) {
14480b57cec5SDimitry Andric       bool found = false;
14490b57cec5SDimitry Andric       if (LastSymbolName == Entry.symbolName())
14500b57cec5SDimitry Andric         found = true;
14510b57cec5SDimitry Andric       else {
14520b57cec5SDimitry Andric         // Here we must check to see it this symbol is already in the
14530b57cec5SDimitry Andric         // SymbolList as it might have already have been added above via a
14540b57cec5SDimitry Andric         // non-lazy (bind) entry.
14550b57cec5SDimitry Andric         for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
14560b57cec5SDimitry Andric           if (SymbolList[J].Name == Entry.symbolName())
14570b57cec5SDimitry Andric             found = true;
14580b57cec5SDimitry Andric         }
14590b57cec5SDimitry Andric       }
14600b57cec5SDimitry Andric       if (!found) {
14610b57cec5SDimitry Andric         LastSymbolName = Entry.symbolName();
14620b57cec5SDimitry Andric         NMSymbol L = {};
1463e8d8bef9SDimitry Andric         L.Name = Entry.symbolName().str();
14640b57cec5SDimitry Andric         L.Address = 0;
14650b57cec5SDimitry Andric         L.Size = 0;
14660b57cec5SDimitry Andric         L.TypeChar = 'U';
14670b57cec5SDimitry Andric         // There is no symbol in the nlist symbol table for this so we set
14680b57cec5SDimitry Andric         // Sym effectivly to null and the rest of code in here must test for
14690b57cec5SDimitry Andric         // it and not do things like Sym.getFlags() for it.
14700b57cec5SDimitry Andric         L.Sym = BasicSymbolRef();
14710b57cec5SDimitry Andric         L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
14720b57cec5SDimitry Andric         L.NType = MachO::N_EXT | MachO::N_UNDF;
14730b57cec5SDimitry Andric         L.NSect = 0;
14740b57cec5SDimitry Andric         // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
14750b57cec5SDimitry Andric         // makes sence since we are creating this from a lazy bind entry.
14760b57cec5SDimitry Andric         L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
14770b57cec5SDimitry Andric         MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
14780b57cec5SDimitry Andric         SymbolList.push_back(L);
14790b57cec5SDimitry Andric         LOS << Entry.symbolName();
14800b57cec5SDimitry Andric         LOS << '\0';
14810b57cec5SDimitry Andric         LazysAdded++;
14820b57cec5SDimitry Andric       }
14830b57cec5SDimitry Andric     }
14840b57cec5SDimitry Andric     if (LErr)
1485e8d8bef9SDimitry Andric       error(std::move(LErr), MachO.getFileName());
14860b57cec5SDimitry Andric     // Set the symbol names and indirect names for the added symbols.
14870b57cec5SDimitry Andric     if (LazysAdded) {
14880b57cec5SDimitry Andric       LOS.flush();
14890b57cec5SDimitry Andric       const char *Q = LazysNameBuffer.c_str();
14900b57cec5SDimitry Andric       for (unsigned K = 0; K < LazysAdded; K++) {
14910b57cec5SDimitry Andric         SymbolList[I].Name = Q;
14920b57cec5SDimitry Andric         Q += strlen(Q) + 1;
14930b57cec5SDimitry Andric         if (SymbolList[I].TypeChar == 'I') {
14940b57cec5SDimitry Andric           SymbolList[I].IndirectName = Q;
14950b57cec5SDimitry Andric           Q += strlen(Q) + 1;
14960b57cec5SDimitry Andric         }
14970b57cec5SDimitry Andric         I++;
14980b57cec5SDimitry Andric       }
14990b57cec5SDimitry Andric     }
15000b57cec5SDimitry Andric 
15010b57cec5SDimitry Andric     // Add the undefineds symbol from the weak bind entries which are not
15020b57cec5SDimitry Andric     // strong symbols.
15030b57cec5SDimitry Andric     unsigned WeaksAdded = 0;
15040b57cec5SDimitry Andric     Error WErr = Error::success();
15050b57cec5SDimitry Andric     LastSymbolName = StringRef();
15060b57cec5SDimitry Andric     for (const llvm::object::MachOBindEntry &Entry :
1507e8d8bef9SDimitry Andric          MachO.weakBindTable(WErr)) {
15080b57cec5SDimitry Andric       bool found = false;
15090b57cec5SDimitry Andric       unsigned J = 0;
15100b57cec5SDimitry Andric       if (LastSymbolName == Entry.symbolName() ||
15110b57cec5SDimitry Andric           Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
15120b57cec5SDimitry Andric         found = true;
15130b57cec5SDimitry Andric       } else {
15140b57cec5SDimitry Andric         for (J = 0; J < SymbolList.size() && !found; ++J) {
15150b57cec5SDimitry Andric           if (SymbolList[J].Name == Entry.symbolName()) {
15160b57cec5SDimitry Andric             found = true;
15170b57cec5SDimitry Andric             break;
15180b57cec5SDimitry Andric           }
15190b57cec5SDimitry Andric         }
15200b57cec5SDimitry Andric       }
15210b57cec5SDimitry Andric       if (!found) {
15220b57cec5SDimitry Andric         LastSymbolName = Entry.symbolName();
1523e8d8bef9SDimitry Andric         NMSymbol W = {};
1524e8d8bef9SDimitry Andric         W.Name = Entry.symbolName().str();
15250b57cec5SDimitry Andric         W.Address = 0;
15260b57cec5SDimitry Andric         W.Size = 0;
15270b57cec5SDimitry Andric         W.TypeChar = 'U';
15280b57cec5SDimitry Andric         // There is no symbol in the nlist symbol table for this so we set
15290b57cec5SDimitry Andric         // Sym effectivly to null and the rest of code in here must test for
15300b57cec5SDimitry Andric         // it and not do things like Sym.getFlags() for it.
15310b57cec5SDimitry Andric         W.Sym = BasicSymbolRef();
15320b57cec5SDimitry Andric         W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
15330b57cec5SDimitry Andric         W.NType = MachO::N_EXT | MachO::N_UNDF;
15340b57cec5SDimitry Andric         W.NSect = 0;
15350b57cec5SDimitry Andric         // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
15360b57cec5SDimitry Andric         // what is created in this case by the linker when there are real
15370b57cec5SDimitry Andric         // symbols in the nlist structs.
15380b57cec5SDimitry Andric         W.NDesc = MachO::N_WEAK_DEF;
15390b57cec5SDimitry Andric         SymbolList.push_back(W);
15400b57cec5SDimitry Andric         WOS << Entry.symbolName();
15410b57cec5SDimitry Andric         WOS << '\0';
15420b57cec5SDimitry Andric         WeaksAdded++;
15430b57cec5SDimitry Andric       } else {
15440b57cec5SDimitry Andric         // This is the case the symbol was previously been found and it could
15450b57cec5SDimitry Andric         // have been added from a bind or lazy bind symbol.  If so and not
15460b57cec5SDimitry Andric         // a definition also mark it as weak.
15470b57cec5SDimitry Andric         if (SymbolList[J].TypeChar == 'U')
15480b57cec5SDimitry Andric           // See comment above about N_WEAK_DEF.
15490b57cec5SDimitry Andric           SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
15500b57cec5SDimitry Andric       }
15510b57cec5SDimitry Andric     }
15520b57cec5SDimitry Andric     if (WErr)
1553e8d8bef9SDimitry Andric       error(std::move(WErr), MachO.getFileName());
15540b57cec5SDimitry Andric     // Set the symbol names and indirect names for the added symbols.
15550b57cec5SDimitry Andric     if (WeaksAdded) {
15560b57cec5SDimitry Andric       WOS.flush();
15570b57cec5SDimitry Andric       const char *Q = WeaksNameBuffer.c_str();
15580b57cec5SDimitry Andric       for (unsigned K = 0; K < WeaksAdded; K++) {
15590b57cec5SDimitry Andric         SymbolList[I].Name = Q;
15600b57cec5SDimitry Andric         Q += strlen(Q) + 1;
15610b57cec5SDimitry Andric         if (SymbolList[I].TypeChar == 'I') {
15620b57cec5SDimitry Andric           SymbolList[I].IndirectName = Q;
15630b57cec5SDimitry Andric           Q += strlen(Q) + 1;
15640b57cec5SDimitry Andric         }
15650b57cec5SDimitry Andric         I++;
15660b57cec5SDimitry Andric       }
15670b57cec5SDimitry Andric     }
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric     // Trying adding symbol from the function starts table and LC_MAIN entry
15700b57cec5SDimitry Andric     // point.
15710b57cec5SDimitry Andric     SmallVector<uint64_t, 8> FoundFns;
15720b57cec5SDimitry Andric     uint64_t lc_main_offset = UINT64_MAX;
1573e8d8bef9SDimitry Andric     for (const auto &Command : MachO.load_commands()) {
15740b57cec5SDimitry Andric       if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
15750b57cec5SDimitry Andric         // We found a function starts segment, parse the addresses for
15760b57cec5SDimitry Andric         // consumption.
15770b57cec5SDimitry Andric         MachO::linkedit_data_command LLC =
1578e8d8bef9SDimitry Andric             MachO.getLinkeditDataLoadCommand(Command);
15790b57cec5SDimitry Andric 
1580e8d8bef9SDimitry Andric         MachO.ReadULEB128s(LLC.dataoff, FoundFns);
15810b57cec5SDimitry Andric       } else if (Command.C.cmd == MachO::LC_MAIN) {
1582e8d8bef9SDimitry Andric         MachO::entry_point_command LCmain = MachO.getEntryPointCommand(Command);
15830b57cec5SDimitry Andric         lc_main_offset = LCmain.entryoff;
15840b57cec5SDimitry Andric       }
15850b57cec5SDimitry Andric     }
15860b57cec5SDimitry Andric     // See if these addresses are already in the symbol table.
15870b57cec5SDimitry Andric     unsigned FunctionStartsAdded = 0;
15880b57cec5SDimitry Andric     for (uint64_t f = 0; f < FoundFns.size(); f++) {
15890b57cec5SDimitry Andric       bool found = false;
15900b57cec5SDimitry Andric       for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
15910b57cec5SDimitry Andric         if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
15920b57cec5SDimitry Andric           found = true;
15930b57cec5SDimitry Andric       }
15940b57cec5SDimitry Andric       // See this address is not already in the symbol table fake up an
15950b57cec5SDimitry Andric       // nlist for it.
15960b57cec5SDimitry Andric       if (!found) {
15970b57cec5SDimitry Andric         NMSymbol F = {};
15980b57cec5SDimitry Andric         F.Name = "<redacted function X>";
15990b57cec5SDimitry Andric         F.Address = FoundFns[f] + BaseSegmentAddress;
16000b57cec5SDimitry Andric         F.Size = 0;
16010b57cec5SDimitry Andric         // There is no symbol in the nlist symbol table for this so we set
16020b57cec5SDimitry Andric         // Sym effectivly to null and the rest of code in here must test for
16030b57cec5SDimitry Andric         // it and not do things like Sym.getFlags() for it.
16040b57cec5SDimitry Andric         F.Sym = BasicSymbolRef();
16050b57cec5SDimitry Andric         F.SymFlags = 0;
16060b57cec5SDimitry Andric         F.NType = MachO::N_SECT;
16070b57cec5SDimitry Andric         F.NSect = 0;
16080b57cec5SDimitry Andric         StringRef SegmentName = StringRef();
16090b57cec5SDimitry Andric         StringRef SectionName = StringRef();
1610e8d8bef9SDimitry Andric         for (const SectionRef &Section : MachO.sections()) {
16118bcb0991SDimitry Andric           if (Expected<StringRef> NameOrErr = Section.getName())
16128bcb0991SDimitry Andric             SectionName = *NameOrErr;
16138bcb0991SDimitry Andric           else
16148bcb0991SDimitry Andric             consumeError(NameOrErr.takeError());
16158bcb0991SDimitry Andric 
1616e8d8bef9SDimitry Andric           SegmentName =
1617e8d8bef9SDimitry Andric               MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
16180b57cec5SDimitry Andric           F.NSect++;
16190b57cec5SDimitry Andric           if (F.Address >= Section.getAddress() &&
16200b57cec5SDimitry Andric               F.Address < Section.getAddress() + Section.getSize()) {
16210b57cec5SDimitry Andric             F.Section = Section;
16220b57cec5SDimitry Andric             break;
16230b57cec5SDimitry Andric           }
16240b57cec5SDimitry Andric         }
16250b57cec5SDimitry Andric         if (SegmentName == "__TEXT" && SectionName == "__text")
16260b57cec5SDimitry Andric           F.TypeChar = 't';
16270b57cec5SDimitry Andric         else if (SegmentName == "__DATA" && SectionName == "__data")
16280b57cec5SDimitry Andric           F.TypeChar = 'd';
16290b57cec5SDimitry Andric         else if (SegmentName == "__DATA" && SectionName == "__bss")
16300b57cec5SDimitry Andric           F.TypeChar = 'b';
16310b57cec5SDimitry Andric         else
16320b57cec5SDimitry Andric           F.TypeChar = 's';
16330b57cec5SDimitry Andric         F.NDesc = 0;
16340b57cec5SDimitry Andric         SymbolList.push_back(F);
16350b57cec5SDimitry Andric         if (FoundFns[f] == lc_main_offset)
16360b57cec5SDimitry Andric           FOS << "<redacted LC_MAIN>";
16370b57cec5SDimitry Andric         else
16380b57cec5SDimitry Andric           FOS << "<redacted function " << f << ">";
16390b57cec5SDimitry Andric         FOS << '\0';
16400b57cec5SDimitry Andric         FunctionStartsAdded++;
16410b57cec5SDimitry Andric       }
16420b57cec5SDimitry Andric     }
16430b57cec5SDimitry Andric     if (FunctionStartsAdded) {
16440b57cec5SDimitry Andric       FOS.flush();
16450b57cec5SDimitry Andric       const char *Q = FunctionStartsNameBuffer.c_str();
16460b57cec5SDimitry Andric       for (unsigned K = 0; K < FunctionStartsAdded; K++) {
16470b57cec5SDimitry Andric         SymbolList[I].Name = Q;
16480b57cec5SDimitry Andric         Q += strlen(Q) + 1;
16490b57cec5SDimitry Andric         if (SymbolList[I].TypeChar == 'I') {
16500b57cec5SDimitry Andric           SymbolList[I].IndirectName = Q;
16510b57cec5SDimitry Andric           Q += strlen(Q) + 1;
16520b57cec5SDimitry Andric         }
16530b57cec5SDimitry Andric         I++;
16540b57cec5SDimitry Andric       }
16550b57cec5SDimitry Andric     }
16560b57cec5SDimitry Andric   }
16570b57cec5SDimitry Andric }
16580b57cec5SDimitry Andric 
1659*81ad6265SDimitry Andric static bool shouldDump(SymbolicFile &Obj) {
1660*81ad6265SDimitry Andric   // The -X option is currently only implemented for XCOFF, ELF, and IR object
1661*81ad6265SDimitry Andric   // files. The option isn't fundamentally impossible with other formats, just
1662*81ad6265SDimitry Andric   // isn't implemented.
1663*81ad6265SDimitry Andric   if (!isa<XCOFFObjectFile>(Obj) && !isa<ELFObjectFileBase>(Obj) &&
1664*81ad6265SDimitry Andric       !isa<IRObjectFile>(Obj))
1665*81ad6265SDimitry Andric     return true;
1666*81ad6265SDimitry Andric 
1667*81ad6265SDimitry Andric   return isSymbolList64Bit(Obj) ? BitMode != BitModeTy::Bit32
1668*81ad6265SDimitry Andric                                 : BitMode != BitModeTy::Bit64;
1669*81ad6265SDimitry Andric }
1670*81ad6265SDimitry Andric 
1671*81ad6265SDimitry Andric static void getXCOFFExports(XCOFFObjectFile *XCOFFObj,
1672*81ad6265SDimitry Andric                             std::vector<NMSymbol> &SymbolList,
1673*81ad6265SDimitry Andric                             StringRef ArchiveName) {
1674*81ad6265SDimitry Andric   // Skip Shared object file.
1675*81ad6265SDimitry Andric   if (XCOFFObj->getFlags() & XCOFF::F_SHROBJ)
1676*81ad6265SDimitry Andric     return;
1677*81ad6265SDimitry Andric 
1678*81ad6265SDimitry Andric   for (SymbolRef Sym : XCOFFObj->symbols()) {
1679*81ad6265SDimitry Andric     // There is no visibility in old 32 bit XCOFF object file interpret.
1680*81ad6265SDimitry Andric     bool HasVisibilityAttr =
1681*81ad6265SDimitry Andric         XCOFFObj->is64Bit() || (XCOFFObj->auxiliaryHeader32() &&
1682*81ad6265SDimitry Andric                                 (XCOFFObj->auxiliaryHeader32()->getVersion() ==
1683*81ad6265SDimitry Andric                                  XCOFF::NEW_XCOFF_INTERPRET));
1684*81ad6265SDimitry Andric 
1685*81ad6265SDimitry Andric     if (HasVisibilityAttr) {
1686*81ad6265SDimitry Andric       XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl());
1687*81ad6265SDimitry Andric       uint16_t SymType = XCOFFSym.getSymbolType();
1688*81ad6265SDimitry Andric       if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_INTERNAL)
1689*81ad6265SDimitry Andric         continue;
1690*81ad6265SDimitry Andric       if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_HIDDEN)
1691*81ad6265SDimitry Andric         continue;
1692*81ad6265SDimitry Andric     }
1693*81ad6265SDimitry Andric 
1694*81ad6265SDimitry Andric     Expected<section_iterator> SymSecOrErr = Sym.getSection();
1695*81ad6265SDimitry Andric     if (!SymSecOrErr) {
1696*81ad6265SDimitry Andric       warn(SymSecOrErr.takeError(), XCOFFObj->getFileName(),
1697*81ad6265SDimitry Andric            "for symbol with index " +
1698*81ad6265SDimitry Andric                Twine(XCOFFObj->getSymbolIndex(Sym.getRawDataRefImpl().p)),
1699*81ad6265SDimitry Andric            ArchiveName);
1700*81ad6265SDimitry Andric       continue;
1701*81ad6265SDimitry Andric     }
1702*81ad6265SDimitry Andric     section_iterator SecIter = *SymSecOrErr;
1703*81ad6265SDimitry Andric     // If the symbol is not in a text or data section, it is not exported.
1704*81ad6265SDimitry Andric     if (SecIter == XCOFFObj->section_end())
1705*81ad6265SDimitry Andric       continue;
1706*81ad6265SDimitry Andric     if (!(SecIter->isText() || SecIter->isData() || SecIter->isBSS()))
1707*81ad6265SDimitry Andric       continue;
1708*81ad6265SDimitry Andric 
1709*81ad6265SDimitry Andric     StringRef SymName = cantFail(Sym.getName());
1710*81ad6265SDimitry Andric     if (SymName.empty())
1711*81ad6265SDimitry Andric       continue;
1712*81ad6265SDimitry Andric     if (SymName.startswith("__sinit") || SymName.startswith("__sterm") ||
1713*81ad6265SDimitry Andric         SymName.front() == '.' || SymName.front() == '(')
1714*81ad6265SDimitry Andric       continue;
1715*81ad6265SDimitry Andric 
1716*81ad6265SDimitry Andric     // Check the SymName regex matching with "^__[0-9]+__".
1717*81ad6265SDimitry Andric     if (SymName.size() > 4 && SymName.startswith("__") &&
1718*81ad6265SDimitry Andric         SymName.endswith("__")) {
1719*81ad6265SDimitry Andric       if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit))
1720*81ad6265SDimitry Andric         continue;
1721*81ad6265SDimitry Andric     }
1722*81ad6265SDimitry Andric 
1723*81ad6265SDimitry Andric     if (SymName == "__rsrc" && NoRsrc)
1724*81ad6265SDimitry Andric       continue;
1725*81ad6265SDimitry Andric 
1726*81ad6265SDimitry Andric     if (SymName.startswith("__tf1"))
1727*81ad6265SDimitry Andric       SymName = SymName.substr(6);
1728*81ad6265SDimitry Andric     else if (SymName.startswith("__tf9"))
1729*81ad6265SDimitry Andric       SymName = SymName.substr(14);
1730*81ad6265SDimitry Andric 
1731*81ad6265SDimitry Andric     NMSymbol S = {};
1732*81ad6265SDimitry Andric     S.Name = SymName.str();
1733*81ad6265SDimitry Andric     S.Sym = Sym;
1734*81ad6265SDimitry Andric 
1735*81ad6265SDimitry Andric     if (HasVisibilityAttr) {
1736*81ad6265SDimitry Andric       XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl());
1737*81ad6265SDimitry Andric       uint16_t SymType = XCOFFSym.getSymbolType();
1738*81ad6265SDimitry Andric       if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_PROTECTED)
1739*81ad6265SDimitry Andric         S.Visibility = "protected";
1740*81ad6265SDimitry Andric       else if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_EXPORTED)
1741*81ad6265SDimitry Andric         S.Visibility = "export";
1742*81ad6265SDimitry Andric     }
1743*81ad6265SDimitry Andric     if (S.initializeFlags(*XCOFFObj))
1744*81ad6265SDimitry Andric       SymbolList.push_back(S);
1745*81ad6265SDimitry Andric   }
1746*81ad6265SDimitry Andric }
1747*81ad6265SDimitry Andric 
1748*81ad6265SDimitry Andric static Expected<SymbolicFile::basic_symbol_iterator_range>
1749*81ad6265SDimitry Andric getDynamicSyms(SymbolicFile &Obj) {
1750*81ad6265SDimitry Andric   const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
1751*81ad6265SDimitry Andric   if (!E)
1752*81ad6265SDimitry Andric     return createError("File format has no dynamic symbol table");
1753*81ad6265SDimitry Andric   return E->getDynamicSymbolIterators();
1754*81ad6265SDimitry Andric }
1755*81ad6265SDimitry Andric 
1756*81ad6265SDimitry Andric // Returns false if there is error found or true otherwise.
1757*81ad6265SDimitry Andric static bool getSymbolNamesFromObject(SymbolicFile &Obj,
1758*81ad6265SDimitry Andric                                      std::vector<NMSymbol> &SymbolList) {
1759e8d8bef9SDimitry Andric   auto Symbols = Obj.symbols();
1760349cc55cSDimitry Andric   std::vector<VersionEntry> SymbolVersions;
1761e8d8bef9SDimitry Andric 
1762*81ad6265SDimitry Andric   if (DynamicSyms) {
1763*81ad6265SDimitry Andric     Expected<SymbolicFile::basic_symbol_iterator_range> SymbolsOrErr =
1764*81ad6265SDimitry Andric         getDynamicSyms(Obj);
1765*81ad6265SDimitry Andric     if (!SymbolsOrErr) {
1766*81ad6265SDimitry Andric       error(SymbolsOrErr.takeError(), Obj.getFileName());
1767*81ad6265SDimitry Andric       return false;
1768*81ad6265SDimitry Andric     }
1769*81ad6265SDimitry Andric     Symbols = *SymbolsOrErr;
1770*81ad6265SDimitry Andric     if (const auto *E = dyn_cast<ELFObjectFileBase>(&Obj)) {
1771349cc55cSDimitry Andric       if (Expected<std::vector<VersionEntry>> VersionsOrErr =
1772349cc55cSDimitry Andric               E->readDynsymVersions())
1773e8d8bef9SDimitry Andric         SymbolVersions = std::move(*VersionsOrErr);
1774e8d8bef9SDimitry Andric       else
1775e8d8bef9SDimitry Andric         WithColor::warning(errs(), ToolName)
1776e8d8bef9SDimitry Andric             << "unable to read symbol versions: "
1777e8d8bef9SDimitry Andric             << toString(VersionsOrErr.takeError()) << "\n";
1778e8d8bef9SDimitry Andric     }
1779*81ad6265SDimitry Andric   }
1780e8d8bef9SDimitry Andric   // If a "-s segname sectname" option was specified and this is a Mach-O
1781e8d8bef9SDimitry Andric   // file get the section number for that section in this object file.
1782e8d8bef9SDimitry Andric   unsigned int Nsect = 0;
1783e8d8bef9SDimitry Andric   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
1784e8d8bef9SDimitry Andric   if (!SegSect.empty() && MachO) {
1785e8d8bef9SDimitry Andric     Nsect = getNsectForSegSect(MachO);
1786e8d8bef9SDimitry Andric     // If this section is not in the object file no symbols are printed.
1787e8d8bef9SDimitry Andric     if (Nsect == 0)
1788*81ad6265SDimitry Andric       return false;
1789e8d8bef9SDimitry Andric   }
1790*81ad6265SDimitry Andric 
1791e8d8bef9SDimitry Andric   if (!(MachO && DyldInfoOnly)) {
1792e8d8bef9SDimitry Andric     size_t I = -1;
1793e8d8bef9SDimitry Andric     for (BasicSymbolRef Sym : Symbols) {
1794e8d8bef9SDimitry Andric       ++I;
1795e8d8bef9SDimitry Andric       Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
1796e8d8bef9SDimitry Andric       if (!SymFlagsOrErr) {
1797e8d8bef9SDimitry Andric         error(SymFlagsOrErr.takeError(), Obj.getFileName());
1798*81ad6265SDimitry Andric         return false;
1799e8d8bef9SDimitry Andric       }
1800fe6060f1SDimitry Andric 
1801fe6060f1SDimitry Andric       // Don't drop format specifc symbols for ARM and AArch64 ELF targets, they
1802fe6060f1SDimitry Andric       // are used to repesent mapping symbols and needed to honor the
1803fe6060f1SDimitry Andric       // --special-syms option.
1804fe6060f1SDimitry Andric       auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj);
1805fe6060f1SDimitry Andric       if ((!ELFObj || (ELFObj->getEMachine() != ELF::EM_ARM &&
1806fe6060f1SDimitry Andric                        ELFObj->getEMachine() != ELF::EM_AARCH64)) &&
1807fe6060f1SDimitry Andric           !DebugSyms && (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific))
1808e8d8bef9SDimitry Andric         continue;
1809e8d8bef9SDimitry Andric       if (WithoutAliases && (*SymFlagsOrErr & SymbolRef::SF_Indirect))
1810e8d8bef9SDimitry Andric         continue;
1811e8d8bef9SDimitry Andric       // If a "-s segname sectname" option was specified and this is a Mach-O
1812e8d8bef9SDimitry Andric       // file and this section appears in this file, Nsect will be non-zero then
1813e8d8bef9SDimitry Andric       // see if this symbol is a symbol from that section and if not skip it.
1814e8d8bef9SDimitry Andric       if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
1815e8d8bef9SDimitry Andric         continue;
1816e8d8bef9SDimitry Andric       NMSymbol S = {};
1817e8d8bef9SDimitry Andric       S.Size = 0;
1818e8d8bef9SDimitry Andric       S.Address = 0;
1819e8d8bef9SDimitry Andric       if (isa<ELFObjectFileBase>(&Obj))
1820e8d8bef9SDimitry Andric         S.Size = ELFSymbolRef(Sym).getSize();
182104eeddc0SDimitry Andric 
182204eeddc0SDimitry Andric       if (const XCOFFObjectFile *XCOFFObj =
182304eeddc0SDimitry Andric               dyn_cast<const XCOFFObjectFile>(&Obj))
182404eeddc0SDimitry Andric         S.Size = XCOFFObj->getSymbolSize(Sym.getRawDataRefImpl());
182504eeddc0SDimitry Andric 
1826e8d8bef9SDimitry Andric       if (PrintAddress && isa<ObjectFile>(Obj)) {
1827e8d8bef9SDimitry Andric         SymbolRef SymRef(Sym);
1828e8d8bef9SDimitry Andric         Expected<uint64_t> AddressOrErr = SymRef.getAddress();
1829e8d8bef9SDimitry Andric         if (!AddressOrErr) {
1830e8d8bef9SDimitry Andric           consumeError(AddressOrErr.takeError());
1831e8d8bef9SDimitry Andric           break;
1832e8d8bef9SDimitry Andric         }
1833e8d8bef9SDimitry Andric         S.Address = *AddressOrErr;
1834e8d8bef9SDimitry Andric       }
1835e8d8bef9SDimitry Andric       S.TypeName = getNMTypeName(Obj, Sym);
1836e8d8bef9SDimitry Andric       S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
1837e8d8bef9SDimitry Andric 
1838e8d8bef9SDimitry Andric       raw_string_ostream OS(S.Name);
1839e8d8bef9SDimitry Andric       if (Error E = Sym.printName(OS)) {
1840e8d8bef9SDimitry Andric         if (MachO) {
1841e8d8bef9SDimitry Andric           OS << "bad string index";
1842e8d8bef9SDimitry Andric           consumeError(std::move(E));
1843e8d8bef9SDimitry Andric         } else
1844e8d8bef9SDimitry Andric           error(std::move(E), Obj.getFileName());
1845e8d8bef9SDimitry Andric       }
1846e8d8bef9SDimitry Andric       if (!SymbolVersions.empty() && !SymbolVersions[I].Name.empty())
1847e8d8bef9SDimitry Andric         S.Name +=
1848349cc55cSDimitry Andric             (SymbolVersions[I].IsVerDef ? "@@" : "@") + SymbolVersions[I].Name;
1849e8d8bef9SDimitry Andric 
1850e8d8bef9SDimitry Andric       S.Sym = Sym;
1851*81ad6265SDimitry Andric       if (S.initializeFlags(Obj))
1852e8d8bef9SDimitry Andric         SymbolList.push_back(S);
1853e8d8bef9SDimitry Andric     }
1854e8d8bef9SDimitry Andric   }
1855e8d8bef9SDimitry Andric 
1856e8d8bef9SDimitry Andric   // If this is a Mach-O file where the nlist symbol table is out of sync
1857e8d8bef9SDimitry Andric   // with the dyld export trie then look through exports and fake up symbols
1858e8d8bef9SDimitry Andric   // for the ones that are missing (also done with the -add-dyldinfo flag).
1859e8d8bef9SDimitry Andric   // This is needed if strip(1) -T is run on a binary containing swift
1860e8d8bef9SDimitry Andric   // language symbols for example.  The option -only-dyldinfo will fake up
1861e8d8bef9SDimitry Andric   // all symbols from the dyld export trie as well as the bind info.
1862e8d8bef9SDimitry Andric   if (MachO && !NoDyldInfo)
1863*81ad6265SDimitry Andric     dumpSymbolsFromDLInfoMachO(*MachO, SymbolList);
1864e8d8bef9SDimitry Andric 
1865*81ad6265SDimitry Andric   return true;
1866*81ad6265SDimitry Andric }
1867*81ad6265SDimitry Andric 
1868*81ad6265SDimitry Andric static void printObjectLabel(bool PrintArchiveName, StringRef ArchiveName,
1869*81ad6265SDimitry Andric                              StringRef ArchitectureName,
1870*81ad6265SDimitry Andric                              StringRef ObjectFileName) {
1871*81ad6265SDimitry Andric   outs() << "\n";
1872*81ad6265SDimitry Andric   if (ArchiveName.empty() || !PrintArchiveName)
1873*81ad6265SDimitry Andric     outs() << ObjectFileName;
1874*81ad6265SDimitry Andric   else
1875*81ad6265SDimitry Andric     outs() << ArchiveName << "(" << ObjectFileName << ")";
1876*81ad6265SDimitry Andric   if (!ArchitectureName.empty())
1877*81ad6265SDimitry Andric     outs() << " (for architecture " << ArchitectureName << ")";
1878*81ad6265SDimitry Andric   outs() << ":\n";
1879*81ad6265SDimitry Andric }
1880*81ad6265SDimitry Andric 
1881*81ad6265SDimitry Andric static Expected<bool> hasSymbols(SymbolicFile &Obj) {
1882*81ad6265SDimitry Andric   if (DynamicSyms) {
1883*81ad6265SDimitry Andric     Expected<SymbolicFile::basic_symbol_iterator_range> DynamicSymsOrErr =
1884*81ad6265SDimitry Andric         getDynamicSyms(Obj);
1885*81ad6265SDimitry Andric     if (!DynamicSymsOrErr)
1886*81ad6265SDimitry Andric       return DynamicSymsOrErr.takeError();
1887*81ad6265SDimitry Andric     return !DynamicSymsOrErr->empty();
1888*81ad6265SDimitry Andric   }
1889*81ad6265SDimitry Andric   return !Obj.symbols().empty();
1890*81ad6265SDimitry Andric }
1891*81ad6265SDimitry Andric 
1892*81ad6265SDimitry Andric static void dumpSymbolNamesFromObject(
1893*81ad6265SDimitry Andric     SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList,
1894*81ad6265SDimitry Andric     bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {},
1895*81ad6265SDimitry Andric     StringRef ArchitectureName = {}, StringRef ObjectName = {},
1896*81ad6265SDimitry Andric     bool PrintArchiveName = true) {
1897*81ad6265SDimitry Andric   if (!shouldDump(Obj))
1898*81ad6265SDimitry Andric     return;
1899*81ad6265SDimitry Andric 
1900*81ad6265SDimitry Andric   if (ExportSymbols && Obj.isXCOFF()) {
1901*81ad6265SDimitry Andric     XCOFFObjectFile *XCOFFObj = cast<XCOFFObjectFile>(&Obj);
1902*81ad6265SDimitry Andric     getXCOFFExports(XCOFFObj, SymbolList, ArchiveName);
1903*81ad6265SDimitry Andric     return;
1904*81ad6265SDimitry Andric   }
1905*81ad6265SDimitry Andric 
1906*81ad6265SDimitry Andric   if (PrintObjectLabel && !ExportSymbols)
1907*81ad6265SDimitry Andric     printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName,
1908*81ad6265SDimitry Andric                      ObjectName.empty() ? Obj.getFileName() : ObjectName);
1909*81ad6265SDimitry Andric   if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols)
1910*81ad6265SDimitry Andric     return;
19110b57cec5SDimitry Andric   CurrentFilename = Obj.getFileName();
19125ffd83dbSDimitry Andric 
1913*81ad6265SDimitry Andric   // If there is an error in hasSymbols(), the error should be encountered in
1914*81ad6265SDimitry Andric   // function getSymbolNamesFromObject first.
1915*81ad6265SDimitry Andric   if (!cantFail(hasSymbols(Obj)) && SymbolList.empty() && !Quiet) {
19165ffd83dbSDimitry Andric     writeFileName(errs(), ArchiveName, ArchitectureName);
19175ffd83dbSDimitry Andric     errs() << "no symbols\n";
19185ffd83dbSDimitry Andric   }
19195ffd83dbSDimitry Andric 
1920*81ad6265SDimitry Andric   sortSymbolList(SymbolList);
1921*81ad6265SDimitry Andric   printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName,
1922*81ad6265SDimitry Andric                   ArchitectureName);
19230b57cec5SDimitry Andric }
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
19260b57cec5SDimitry Andric // and if it is and there is a list of architecture flags is specified then
19270b57cec5SDimitry Andric // check to make sure this Mach-O file is one of those architectures or all
19280b57cec5SDimitry Andric // architectures was specificed.  If not then an error is generated and this
19290b57cec5SDimitry Andric // routine returns false.  Else it returns true.
1930*81ad6265SDimitry Andric static bool checkMachOAndArchFlags(SymbolicFile *O, StringRef Filename) {
19310b57cec5SDimitry Andric   auto *MachO = dyn_cast<MachOObjectFile>(O);
19320b57cec5SDimitry Andric 
19330b57cec5SDimitry Andric   if (!MachO || ArchAll || ArchFlags.empty())
19340b57cec5SDimitry Andric     return true;
19350b57cec5SDimitry Andric 
19360b57cec5SDimitry Andric   MachO::mach_header H;
19370b57cec5SDimitry Andric   MachO::mach_header_64 H_64;
19380b57cec5SDimitry Andric   Triple T;
19390b57cec5SDimitry Andric   const char *McpuDefault, *ArchFlag;
19400b57cec5SDimitry Andric   if (MachO->is64Bit()) {
19410b57cec5SDimitry Andric     H_64 = MachO->MachOObjectFile::getHeader64();
19420b57cec5SDimitry Andric     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
19430b57cec5SDimitry Andric                                        &McpuDefault, &ArchFlag);
19440b57cec5SDimitry Andric   } else {
19450b57cec5SDimitry Andric     H = MachO->MachOObjectFile::getHeader();
19460b57cec5SDimitry Andric     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
19470b57cec5SDimitry Andric                                        &McpuDefault, &ArchFlag);
19480b57cec5SDimitry Andric   }
19490b57cec5SDimitry Andric   const std::string ArchFlagName(ArchFlag);
1950e8d8bef9SDimitry Andric   if (!llvm::is_contained(ArchFlags, ArchFlagName)) {
19510b57cec5SDimitry Andric     error("No architecture specified", Filename);
19520b57cec5SDimitry Andric     return false;
19530b57cec5SDimitry Andric   }
19540b57cec5SDimitry Andric   return true;
19550b57cec5SDimitry Andric }
19560b57cec5SDimitry Andric 
1957*81ad6265SDimitry Andric static void dumpArchiveMap(Archive *A, StringRef Filename) {
19580b57cec5SDimitry Andric   Archive::symbol_iterator I = A->symbol_begin();
19590b57cec5SDimitry Andric   Archive::symbol_iterator E = A->symbol_end();
19600b57cec5SDimitry Andric   if (I != E) {
19610b57cec5SDimitry Andric     outs() << "Archive map\n";
19620b57cec5SDimitry Andric     for (; I != E; ++I) {
19630b57cec5SDimitry Andric       Expected<Archive::Child> C = I->getMember();
19640b57cec5SDimitry Andric       if (!C) {
19650b57cec5SDimitry Andric         error(C.takeError(), Filename);
19660b57cec5SDimitry Andric         break;
19670b57cec5SDimitry Andric       }
19680b57cec5SDimitry Andric       Expected<StringRef> FileNameOrErr = C->getName();
19690b57cec5SDimitry Andric       if (!FileNameOrErr) {
19700b57cec5SDimitry Andric         error(FileNameOrErr.takeError(), Filename);
19710b57cec5SDimitry Andric         break;
19720b57cec5SDimitry Andric       }
19730b57cec5SDimitry Andric       StringRef SymName = I->getName();
19740b57cec5SDimitry Andric       outs() << SymName << " in " << FileNameOrErr.get() << "\n";
19750b57cec5SDimitry Andric     }
19760b57cec5SDimitry Andric     outs() << "\n";
19770b57cec5SDimitry Andric   }
19780b57cec5SDimitry Andric }
19790b57cec5SDimitry Andric 
1980*81ad6265SDimitry Andric static void dumpArchive(Archive *A, std::vector<NMSymbol> &SymbolList,
1981*81ad6265SDimitry Andric                         StringRef Filename, LLVMContext *ContextPtr) {
1982*81ad6265SDimitry Andric   if (ArchiveMap)
1983*81ad6265SDimitry Andric     dumpArchiveMap(A, Filename);
1984*81ad6265SDimitry Andric 
19850b57cec5SDimitry Andric   Error Err = Error::success();
19860b57cec5SDimitry Andric   for (auto &C : A->children(Err)) {
1987*81ad6265SDimitry Andric     Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(ContextPtr);
19880b57cec5SDimitry Andric     if (!ChildOrErr) {
19890b57cec5SDimitry Andric       if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
19900b57cec5SDimitry Andric         error(std::move(E), Filename, C);
19910b57cec5SDimitry Andric       continue;
19920b57cec5SDimitry Andric     }
19930b57cec5SDimitry Andric     if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
19940b57cec5SDimitry Andric       if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
19950b57cec5SDimitry Andric         WithColor::warning(errs(), ToolName)
19960b57cec5SDimitry Andric             << "sizes with -print-size for Mach-O files are always zero.\n";
19970b57cec5SDimitry Andric         MachOPrintSizeWarning = true;
19980b57cec5SDimitry Andric       }
19990b57cec5SDimitry Andric       if (!checkMachOAndArchFlags(O, Filename))
20000b57cec5SDimitry Andric         return;
2001*81ad6265SDimitry Andric       dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/false,
2002*81ad6265SDimitry Andric                                 !PrintFileName, Filename,
2003*81ad6265SDimitry Andric                                 /*ArchitectureName=*/{}, O->getFileName(),
2004*81ad6265SDimitry Andric                                 /*PrintArchiveName=*/false);
20050b57cec5SDimitry Andric     }
20060b57cec5SDimitry Andric   }
20070b57cec5SDimitry Andric   if (Err)
20080b57cec5SDimitry Andric     error(std::move(Err), A->getFileName());
20090b57cec5SDimitry Andric }
2010*81ad6265SDimitry Andric 
2011*81ad6265SDimitry Andric static void dumpMachOUniversalBinaryMatchArchFlags(
2012*81ad6265SDimitry Andric     MachOUniversalBinary *UB, std::vector<NMSymbol> &SymbolList,
2013*81ad6265SDimitry Andric     StringRef Filename, LLVMContext *ContextPtr) {
20140b57cec5SDimitry Andric   // Look for a slice in the universal binary that matches each ArchFlag.
20150b57cec5SDimitry Andric   bool ArchFound;
20160b57cec5SDimitry Andric   for (unsigned i = 0; i < ArchFlags.size(); ++i) {
20170b57cec5SDimitry Andric     ArchFound = false;
20180b57cec5SDimitry Andric     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
20190b57cec5SDimitry Andric                                                E = UB->end_objects();
20200b57cec5SDimitry Andric          I != E; ++I) {
20210b57cec5SDimitry Andric       if (ArchFlags[i] == I->getArchFlagName()) {
20220b57cec5SDimitry Andric         ArchFound = true;
2023*81ad6265SDimitry Andric         Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
20240b57cec5SDimitry Andric         std::string ArchiveName;
20250b57cec5SDimitry Andric         std::string ArchitectureName;
20260b57cec5SDimitry Andric         ArchiveName.clear();
20270b57cec5SDimitry Andric         ArchitectureName.clear();
20280b57cec5SDimitry Andric         if (ObjOrErr) {
20290b57cec5SDimitry Andric           ObjectFile &Obj = *ObjOrErr.get();
2030*81ad6265SDimitry Andric           if (ArchFlags.size() > 1)
20310b57cec5SDimitry Andric             ArchitectureName = I->getArchFlagName();
2032*81ad6265SDimitry Andric           dumpSymbolNamesFromObject(Obj, SymbolList,
2033*81ad6265SDimitry Andric                                     /*PrintSymbolObject=*/false,
2034*81ad6265SDimitry Andric                                     (ArchFlags.size() > 1) && !PrintFileName,
2035*81ad6265SDimitry Andric                                     ArchiveName, ArchitectureName);
2036*81ad6265SDimitry Andric         } else if (auto E =
2037*81ad6265SDimitry Andric                        isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2038*81ad6265SDimitry Andric           error(std::move(E), Filename,
2039*81ad6265SDimitry Andric                 ArchFlags.size() > 1 ? StringRef(I->getArchFlagName())
2040*81ad6265SDimitry Andric                                      : StringRef());
20410b57cec5SDimitry Andric           continue;
20420b57cec5SDimitry Andric         } else if (Expected<std::unique_ptr<Archive>> AOrErr =
20430b57cec5SDimitry Andric                        I->getAsArchive()) {
20440b57cec5SDimitry Andric           std::unique_ptr<Archive> &A = *AOrErr;
20450b57cec5SDimitry Andric           Error Err = Error::success();
20460b57cec5SDimitry Andric           for (auto &C : A->children(Err)) {
20470b57cec5SDimitry Andric             Expected<std::unique_ptr<Binary>> ChildOrErr =
20480b57cec5SDimitry Andric                 C.getAsBinary(ContextPtr);
20490b57cec5SDimitry Andric             if (!ChildOrErr) {
2050*81ad6265SDimitry Andric               if (auto E =
2051*81ad6265SDimitry Andric                       isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
2052*81ad6265SDimitry Andric                 error(std::move(E), Filename, C,
2053*81ad6265SDimitry Andric                       ArchFlags.size() > 1 ? StringRef(I->getArchFlagName())
2054*81ad6265SDimitry Andric                                            : StringRef());
20550b57cec5SDimitry Andric               }
20560b57cec5SDimitry Andric               continue;
20570b57cec5SDimitry Andric             }
2058*81ad6265SDimitry Andric             if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
20595ffd83dbSDimitry Andric               ArchiveName = std::string(A->getFileName());
20600b57cec5SDimitry Andric               if (ArchFlags.size() > 1)
20610b57cec5SDimitry Andric                 ArchitectureName = I->getArchFlagName();
2062*81ad6265SDimitry Andric               dumpSymbolNamesFromObject(
2063*81ad6265SDimitry Andric                   *O, SymbolList, /*PrintSymbolObject=*/false, !PrintFileName,
2064*81ad6265SDimitry Andric                   ArchiveName, ArchitectureName);
20650b57cec5SDimitry Andric             }
20660b57cec5SDimitry Andric           }
20670b57cec5SDimitry Andric           if (Err)
20680b57cec5SDimitry Andric             error(std::move(Err), A->getFileName());
20690b57cec5SDimitry Andric         } else {
20700b57cec5SDimitry Andric           consumeError(AOrErr.takeError());
20710b57cec5SDimitry Andric           error(Filename + " for architecture " +
20720b57cec5SDimitry Andric                     StringRef(I->getArchFlagName()) +
20730b57cec5SDimitry Andric                     " is not a Mach-O file or an archive file",
20740b57cec5SDimitry Andric                 "Mach-O universal file");
20750b57cec5SDimitry Andric         }
20760b57cec5SDimitry Andric       }
20770b57cec5SDimitry Andric     }
20780b57cec5SDimitry Andric     if (!ArchFound) {
20790b57cec5SDimitry Andric       error(ArchFlags[i],
20800b57cec5SDimitry Andric             "file: " + Filename + " does not contain architecture");
20810b57cec5SDimitry Andric       return;
20820b57cec5SDimitry Andric     }
20830b57cec5SDimitry Andric   }
20840b57cec5SDimitry Andric }
2085*81ad6265SDimitry Andric 
2086*81ad6265SDimitry Andric // Returns true If the binary contains a slice that matches the host
2087*81ad6265SDimitry Andric // architecture, or false otherwise.
2088*81ad6265SDimitry Andric static bool dumpMachOUniversalBinaryMatchHost(MachOUniversalBinary *UB,
2089*81ad6265SDimitry Andric                                               std::vector<NMSymbol> &SymbolList,
2090*81ad6265SDimitry Andric                                               StringRef Filename,
2091*81ad6265SDimitry Andric                                               LLVMContext *ContextPtr) {
20920b57cec5SDimitry Andric   Triple HostTriple = MachOObjectFile::getHostArch();
20930b57cec5SDimitry Andric   StringRef HostArchName = HostTriple.getArchName();
20940b57cec5SDimitry Andric   for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
20950b57cec5SDimitry Andric                                              E = UB->end_objects();
20960b57cec5SDimitry Andric        I != E; ++I) {
20970b57cec5SDimitry Andric     if (HostArchName == I->getArchFlagName()) {
20980b57cec5SDimitry Andric       Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
20990b57cec5SDimitry Andric       std::string ArchiveName;
21000b57cec5SDimitry Andric       if (ObjOrErr) {
21010b57cec5SDimitry Andric         ObjectFile &Obj = *ObjOrErr.get();
2102*81ad6265SDimitry Andric         dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false,
2103*81ad6265SDimitry Andric                                   /*PrintObjectLabel=*/false);
2104*81ad6265SDimitry Andric       } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
21050b57cec5SDimitry Andric         error(std::move(E), Filename);
2106*81ad6265SDimitry Andric       else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
21070b57cec5SDimitry Andric         std::unique_ptr<Archive> &A = *AOrErr;
21080b57cec5SDimitry Andric         Error Err = Error::success();
21090b57cec5SDimitry Andric         for (auto &C : A->children(Err)) {
21100b57cec5SDimitry Andric           Expected<std::unique_ptr<Binary>> ChildOrErr =
21110b57cec5SDimitry Andric               C.getAsBinary(ContextPtr);
21120b57cec5SDimitry Andric           if (!ChildOrErr) {
2113*81ad6265SDimitry Andric             if (auto E =
2114*81ad6265SDimitry Andric                     isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
21150b57cec5SDimitry Andric               error(std::move(E), Filename, C);
21160b57cec5SDimitry Andric             continue;
21170b57cec5SDimitry Andric           }
2118*81ad6265SDimitry Andric           if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
21195ffd83dbSDimitry Andric             ArchiveName = std::string(A->getFileName());
2120*81ad6265SDimitry Andric             dumpSymbolNamesFromObject(*O, SymbolList,
2121*81ad6265SDimitry Andric                                       /*PrintSymbolObject=*/false,
2122*81ad6265SDimitry Andric                                       !PrintFileName, ArchiveName);
21230b57cec5SDimitry Andric           }
21240b57cec5SDimitry Andric         }
21250b57cec5SDimitry Andric         if (Err)
21260b57cec5SDimitry Andric           error(std::move(Err), A->getFileName());
21270b57cec5SDimitry Andric       } else {
21280b57cec5SDimitry Andric         consumeError(AOrErr.takeError());
21290b57cec5SDimitry Andric         error(Filename + " for architecture " +
21300b57cec5SDimitry Andric                   StringRef(I->getArchFlagName()) +
21310b57cec5SDimitry Andric                   " is not a Mach-O file or an archive file",
21320b57cec5SDimitry Andric               "Mach-O universal file");
21330b57cec5SDimitry Andric       }
2134*81ad6265SDimitry Andric       return true;
21350b57cec5SDimitry Andric     }
21360b57cec5SDimitry Andric   }
2137*81ad6265SDimitry Andric   return false;
21380b57cec5SDimitry Andric }
2139*81ad6265SDimitry Andric 
2140*81ad6265SDimitry Andric static void dumpMachOUniversalBinaryArchAll(MachOUniversalBinary *UB,
2141*81ad6265SDimitry Andric                                             std::vector<NMSymbol> &SymbolList,
2142*81ad6265SDimitry Andric                                             StringRef Filename,
2143*81ad6265SDimitry Andric                                             LLVMContext *ContextPtr) {
21440b57cec5SDimitry Andric   bool moreThanOneArch = UB->getNumberOfObjects() > 1;
21450b57cec5SDimitry Andric   for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
21460b57cec5SDimitry Andric     Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
21470b57cec5SDimitry Andric     std::string ArchiveName;
21480b57cec5SDimitry Andric     std::string ArchitectureName;
21490b57cec5SDimitry Andric     ArchiveName.clear();
21500b57cec5SDimitry Andric     ArchitectureName.clear();
21510b57cec5SDimitry Andric     if (ObjOrErr) {
21520b57cec5SDimitry Andric       ObjectFile &Obj = *ObjOrErr.get();
21530b57cec5SDimitry Andric       if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
21540b57cec5SDimitry Andric         ArchitectureName = O.getArchFlagName();
2155*81ad6265SDimitry Andric       dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false,
2156*81ad6265SDimitry Andric                                 !PrintFileName, ArchiveName, ArchitectureName);
2157*81ad6265SDimitry Andric     } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2158*81ad6265SDimitry Andric       error(std::move(E), Filename,
2159*81ad6265SDimitry Andric             moreThanOneArch ? StringRef(O.getArchFlagName()) : StringRef());
21600b57cec5SDimitry Andric       continue;
2161*81ad6265SDimitry Andric     } else if (Expected<std::unique_ptr<Archive>> AOrErr = O.getAsArchive()) {
21620b57cec5SDimitry Andric       std::unique_ptr<Archive> &A = *AOrErr;
21630b57cec5SDimitry Andric       Error Err = Error::success();
21640b57cec5SDimitry Andric       for (auto &C : A->children(Err)) {
21650b57cec5SDimitry Andric         Expected<std::unique_ptr<Binary>> ChildOrErr =
21660b57cec5SDimitry Andric             C.getAsBinary(ContextPtr);
21670b57cec5SDimitry Andric         if (!ChildOrErr) {
2168*81ad6265SDimitry Andric           if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2169*81ad6265SDimitry Andric             error(std::move(E), Filename, C,
2170*81ad6265SDimitry Andric                   moreThanOneArch ? StringRef(ArchitectureName) : StringRef());
21710b57cec5SDimitry Andric           continue;
21720b57cec5SDimitry Andric         }
21730b57cec5SDimitry Andric         if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
21745ffd83dbSDimitry Andric           ArchiveName = std::string(A->getFileName());
21750b57cec5SDimitry Andric           if (isa<MachOObjectFile>(F) && moreThanOneArch)
21760b57cec5SDimitry Andric             ArchitectureName = O.getArchFlagName();
2177*81ad6265SDimitry Andric           dumpSymbolNamesFromObject(*F, SymbolList, /*PrintSymbolObject=*/false,
2178*81ad6265SDimitry Andric                                     !PrintFileName, ArchiveName,
2179*81ad6265SDimitry Andric                                     ArchitectureName);
21800b57cec5SDimitry Andric         }
21810b57cec5SDimitry Andric       }
21820b57cec5SDimitry Andric       if (Err)
21830b57cec5SDimitry Andric         error(std::move(Err), A->getFileName());
21840b57cec5SDimitry Andric     } else {
21850b57cec5SDimitry Andric       consumeError(AOrErr.takeError());
2186*81ad6265SDimitry Andric       error(Filename + " for architecture " + StringRef(O.getArchFlagName()) +
21870b57cec5SDimitry Andric                 " is not a Mach-O file or an archive file",
21880b57cec5SDimitry Andric             "Mach-O universal file");
21890b57cec5SDimitry Andric     }
21900b57cec5SDimitry Andric   }
2191*81ad6265SDimitry Andric }
2192*81ad6265SDimitry Andric 
2193*81ad6265SDimitry Andric static void dumpMachOUniversalBinary(MachOUniversalBinary *UB,
2194*81ad6265SDimitry Andric                                      std::vector<NMSymbol> &SymbolList,
2195*81ad6265SDimitry Andric                                      StringRef Filename,
2196*81ad6265SDimitry Andric                                      LLVMContext *ContextPtr) {
2197*81ad6265SDimitry Andric   // If we have a list of architecture flags specified dump only those.
2198*81ad6265SDimitry Andric   if (!ArchAll && !ArchFlags.empty()) {
2199*81ad6265SDimitry Andric     dumpMachOUniversalBinaryMatchArchFlags(UB, SymbolList, Filename,
2200*81ad6265SDimitry Andric                                            ContextPtr);
22010b57cec5SDimitry Andric     return;
22020b57cec5SDimitry Andric   }
22035ffd83dbSDimitry Andric 
2204*81ad6265SDimitry Andric   // No architecture flags were specified so if this contains a slice that
2205*81ad6265SDimitry Andric   // matches the host architecture dump only that.
2206*81ad6265SDimitry Andric   if (!ArchAll &&
2207*81ad6265SDimitry Andric       dumpMachOUniversalBinaryMatchHost(UB, SymbolList, Filename, ContextPtr))
2208*81ad6265SDimitry Andric     return;
2209*81ad6265SDimitry Andric 
2210*81ad6265SDimitry Andric   // Either all architectures have been specified or none have been specified
2211*81ad6265SDimitry Andric   // and this does not contain the host architecture so dump all the slices.
2212*81ad6265SDimitry Andric   dumpMachOUniversalBinaryArchAll(UB, SymbolList, Filename, ContextPtr);
2213*81ad6265SDimitry Andric }
2214*81ad6265SDimitry Andric 
2215*81ad6265SDimitry Andric static void dumpTapiUniversal(TapiUniversal *TU,
2216*81ad6265SDimitry Andric                               std::vector<NMSymbol> &SymbolList,
2217*81ad6265SDimitry Andric                               StringRef Filename) {
22185ffd83dbSDimitry Andric   for (const TapiUniversal::ObjectForArch &I : TU->objects()) {
22195ffd83dbSDimitry Andric     StringRef ArchName = I.getArchFlagName();
22205ffd83dbSDimitry Andric     const bool ShowArch =
2221e8d8bef9SDimitry Andric         ArchFlags.empty() || llvm::is_contained(ArchFlags, ArchName);
22225ffd83dbSDimitry Andric     if (!ShowArch)
22235ffd83dbSDimitry Andric       continue;
22245ffd83dbSDimitry Andric     if (!AddInlinedInfo && !I.isTopLevelLib())
22255ffd83dbSDimitry Andric       continue;
2226*81ad6265SDimitry Andric     if (auto ObjOrErr = I.getAsObjectFile())
2227*81ad6265SDimitry Andric       dumpSymbolNamesFromObject(
2228*81ad6265SDimitry Andric           *ObjOrErr.get(), SymbolList, /*PrintSymbolObject=*/false,
2229*81ad6265SDimitry Andric           /*PrintObjectLabel=*/true,
2230*81ad6265SDimitry Andric           /*ArchiveName=*/{}, ArchName, I.getInstallName());
2231*81ad6265SDimitry Andric     else if (Error E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
22325ffd83dbSDimitry Andric       error(std::move(E), Filename, ArchName);
22335ffd83dbSDimitry Andric     }
22345ffd83dbSDimitry Andric   }
22355ffd83dbSDimitry Andric }
22365ffd83dbSDimitry Andric 
2237*81ad6265SDimitry Andric static void dumpSymbolicFile(SymbolicFile *O, std::vector<NMSymbol> &SymbolList,
2238*81ad6265SDimitry Andric                              StringRef Filename) {
22390b57cec5SDimitry Andric   if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
22400b57cec5SDimitry Andric     WithColor::warning(errs(), ToolName)
22410b57cec5SDimitry Andric         << "sizes with --print-size for Mach-O files are always zero.\n";
22420b57cec5SDimitry Andric     MachOPrintSizeWarning = true;
22430b57cec5SDimitry Andric   }
22440b57cec5SDimitry Andric   if (!checkMachOAndArchFlags(O, Filename))
22450b57cec5SDimitry Andric     return;
2246*81ad6265SDimitry Andric   dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/true,
2247*81ad6265SDimitry Andric                             /*PrintObjectLabel=*/false);
22480b57cec5SDimitry Andric }
2249*81ad6265SDimitry Andric 
2250*81ad6265SDimitry Andric static std::vector<NMSymbol> dumpSymbolNamesFromFile(StringRef Filename) {
2251*81ad6265SDimitry Andric   std::vector<NMSymbol> SymbolList;
2252*81ad6265SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
2253*81ad6265SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Filename);
2254*81ad6265SDimitry Andric   if (error(BufferOrErr.getError(), Filename))
2255*81ad6265SDimitry Andric     return SymbolList;
2256*81ad6265SDimitry Andric 
2257*81ad6265SDimitry Andric   // Always enable opaque pointers, to handle archives with mixed typed and
2258*81ad6265SDimitry Andric   // opaque pointer bitcode files gracefully. As we're only reading symbols,
2259*81ad6265SDimitry Andric   // the used pointer types don't matter.
2260*81ad6265SDimitry Andric   LLVMContext Context;
2261*81ad6265SDimitry Andric   Context.setOpaquePointers(true);
2262*81ad6265SDimitry Andric   LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
2263*81ad6265SDimitry Andric   Expected<std::unique_ptr<Binary>> BinaryOrErr =
2264*81ad6265SDimitry Andric       createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
2265*81ad6265SDimitry Andric   if (!BinaryOrErr) {
2266*81ad6265SDimitry Andric     error(BinaryOrErr.takeError(), Filename);
2267*81ad6265SDimitry Andric     return SymbolList;
2268*81ad6265SDimitry Andric   }
2269*81ad6265SDimitry Andric   Binary &Bin = *BinaryOrErr.get();
2270*81ad6265SDimitry Andric   if (Archive *A = dyn_cast<Archive>(&Bin))
2271*81ad6265SDimitry Andric     dumpArchive(A, SymbolList, Filename, ContextPtr);
2272*81ad6265SDimitry Andric   else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
2273*81ad6265SDimitry Andric     dumpMachOUniversalBinary(UB, SymbolList, Filename, ContextPtr);
2274*81ad6265SDimitry Andric   else if (TapiUniversal *TU = dyn_cast<TapiUniversal>(&Bin))
2275*81ad6265SDimitry Andric     dumpTapiUniversal(TU, SymbolList, Filename);
2276*81ad6265SDimitry Andric   else if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin))
2277*81ad6265SDimitry Andric     dumpSymbolicFile(O, SymbolList, Filename);
2278*81ad6265SDimitry Andric   return SymbolList;
2279*81ad6265SDimitry Andric }
2280*81ad6265SDimitry Andric 
2281*81ad6265SDimitry Andric static void
2282*81ad6265SDimitry Andric exportSymbolNamesFromFiles(const std::vector<std::string> &InputFilenames) {
2283*81ad6265SDimitry Andric   std::vector<NMSymbol> SymbolList;
2284*81ad6265SDimitry Andric   for (const auto &FileName : InputFilenames) {
2285*81ad6265SDimitry Andric     std::vector<NMSymbol> FileSymList = dumpSymbolNamesFromFile(FileName);
2286*81ad6265SDimitry Andric     SymbolList.insert(SymbolList.end(), FileSymList.begin(), FileSymList.end());
2287*81ad6265SDimitry Andric   }
2288*81ad6265SDimitry Andric 
2289*81ad6265SDimitry Andric   // Delete symbols which should not be printed from SymolList.
2290*81ad6265SDimitry Andric   SymbolList.erase(
2291*81ad6265SDimitry Andric       llvm::remove_if(SymbolList,
2292*81ad6265SDimitry Andric                       [](const NMSymbol &s) { return !s.shouldPrint(); }),
2293*81ad6265SDimitry Andric       SymbolList.end());
2294*81ad6265SDimitry Andric   sortSymbolList(SymbolList);
2295*81ad6265SDimitry Andric   SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()),
2296*81ad6265SDimitry Andric                    SymbolList.end());
2297*81ad6265SDimitry Andric   printExportSymbolList(SymbolList);
22980b57cec5SDimitry Andric }
22990b57cec5SDimitry Andric 
23000b57cec5SDimitry Andric int main(int argc, char **argv) {
23010b57cec5SDimitry Andric   InitLLVM X(argc, argv);
2302fe6060f1SDimitry Andric   BumpPtrAllocator A;
2303fe6060f1SDimitry Andric   StringSaver Saver(A);
2304fe6060f1SDimitry Andric   NmOptTable Tbl;
2305fe6060f1SDimitry Andric   ToolName = argv[0];
2306fe6060f1SDimitry Andric   opt::InputArgList Args =
2307fe6060f1SDimitry Andric       Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
2308fe6060f1SDimitry Andric         error(Msg);
2309fe6060f1SDimitry Andric         exit(1);
2310fe6060f1SDimitry Andric       });
2311fe6060f1SDimitry Andric   if (Args.hasArg(OPT_help)) {
2312fe6060f1SDimitry Andric     Tbl.printHelp(
2313fe6060f1SDimitry Andric         outs(),
2314fe6060f1SDimitry Andric         (Twine(ToolName) + " [options] <input object files>").str().c_str(),
2315fe6060f1SDimitry Andric         "LLVM symbol table dumper");
2316fe6060f1SDimitry Andric     // TODO Replace this with OptTable API once it adds extrahelp support.
2317fe6060f1SDimitry Andric     outs() << "\nPass @FILE as argument to read options from FILE.\n";
2318fe6060f1SDimitry Andric     return 0;
2319fe6060f1SDimitry Andric   }
2320fe6060f1SDimitry Andric   if (Args.hasArg(OPT_version)) {
2321fe6060f1SDimitry Andric     // This needs to contain the word "GNU", libtool looks for that string.
2322fe6060f1SDimitry Andric     outs() << "llvm-nm, compatible with GNU nm" << '\n';
2323fe6060f1SDimitry Andric     cl::PrintVersionMessage();
2324fe6060f1SDimitry Andric     return 0;
2325fe6060f1SDimitry Andric   }
2326fe6060f1SDimitry Andric 
2327fe6060f1SDimitry Andric   DebugSyms = Args.hasArg(OPT_debug_syms);
2328fe6060f1SDimitry Andric   DefinedOnly = Args.hasArg(OPT_defined_only);
2329fe6060f1SDimitry Andric   Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
2330fe6060f1SDimitry Andric   DynamicSyms = Args.hasArg(OPT_dynamic);
2331fe6060f1SDimitry Andric   ExternalOnly = Args.hasArg(OPT_extern_only);
2332fe6060f1SDimitry Andric   StringRef V = Args.getLastArgValue(OPT_format_EQ, "bsd");
2333fe6060f1SDimitry Andric   if (V == "bsd")
2334fe6060f1SDimitry Andric     OutputFormat = bsd;
2335fe6060f1SDimitry Andric   else if (V == "posix")
2336fe6060f1SDimitry Andric     OutputFormat = posix;
2337fe6060f1SDimitry Andric   else if (V == "sysv")
2338fe6060f1SDimitry Andric     OutputFormat = sysv;
2339fe6060f1SDimitry Andric   else if (V == "darwin")
2340fe6060f1SDimitry Andric     OutputFormat = darwin;
2341fe6060f1SDimitry Andric   else if (V == "just-symbols")
2342fe6060f1SDimitry Andric     OutputFormat = just_symbols;
2343fe6060f1SDimitry Andric   else
2344fe6060f1SDimitry Andric     error("--format value should be one of: bsd, posix, sysv, darwin, "
2345fe6060f1SDimitry Andric           "just-symbols");
2346fe6060f1SDimitry Andric   NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc);
2347fe6060f1SDimitry Andric   NoSort = Args.hasArg(OPT_no_sort);
2348fe6060f1SDimitry Andric   NoWeakSymbols = Args.hasArg(OPT_no_weak);
2349fe6060f1SDimitry Andric   NumericSort = Args.hasArg(OPT_numeric_sort);
2350fe6060f1SDimitry Andric   ArchiveMap = Args.hasArg(OPT_print_armap);
2351fe6060f1SDimitry Andric   PrintFileName = Args.hasArg(OPT_print_file_name);
2352fe6060f1SDimitry Andric   PrintSize = Args.hasArg(OPT_print_size);
2353fe6060f1SDimitry Andric   ReverseSort = Args.hasArg(OPT_reverse_sort);
2354*81ad6265SDimitry Andric   ExportSymbols = Args.hasArg(OPT_export_symbols);
2355*81ad6265SDimitry Andric   if (ExportSymbols) {
2356*81ad6265SDimitry Andric     ExternalOnly = true;
2357*81ad6265SDimitry Andric     DefinedOnly = true;
2358*81ad6265SDimitry Andric   }
2359*81ad6265SDimitry Andric 
2360fe6060f1SDimitry Andric   Quiet = Args.hasArg(OPT_quiet);
2361fe6060f1SDimitry Andric   V = Args.getLastArgValue(OPT_radix_EQ, "x");
2362fe6060f1SDimitry Andric   if (V == "o")
2363fe6060f1SDimitry Andric     AddressRadix = Radix::o;
2364fe6060f1SDimitry Andric   else if (V == "d")
2365fe6060f1SDimitry Andric     AddressRadix = Radix::d;
2366fe6060f1SDimitry Andric   else if (V == "x")
2367fe6060f1SDimitry Andric     AddressRadix = Radix::x;
2368fe6060f1SDimitry Andric   else
2369fe6060f1SDimitry Andric     error("--radix value should be one of: 'o' (octal), 'd' (decimal), 'x' "
2370fe6060f1SDimitry Andric           "(hexadecimal)");
2371fe6060f1SDimitry Andric   SizeSort = Args.hasArg(OPT_size_sort);
2372fe6060f1SDimitry Andric   SpecialSyms = Args.hasArg(OPT_special_syms);
2373fe6060f1SDimitry Andric   UndefinedOnly = Args.hasArg(OPT_undefined_only);
2374fe6060f1SDimitry Andric   WithoutAliases = Args.hasArg(OPT_without_aliases);
2375fe6060f1SDimitry Andric 
2376*81ad6265SDimitry Andric   StringRef Mode = Args.getLastArgValue(OPT_X, "any");
2377*81ad6265SDimitry Andric   if (Mode == "32")
2378*81ad6265SDimitry Andric     BitMode = BitModeTy::Bit32;
2379*81ad6265SDimitry Andric   else if (Mode == "64")
2380*81ad6265SDimitry Andric     BitMode = BitModeTy::Bit64;
2381*81ad6265SDimitry Andric   else if (Mode == "32_64")
2382*81ad6265SDimitry Andric     BitMode = BitModeTy::Bit32_64;
2383*81ad6265SDimitry Andric   else if (Mode == "any")
2384*81ad6265SDimitry Andric     BitMode = BitModeTy::Any;
2385*81ad6265SDimitry Andric   else
2386*81ad6265SDimitry Andric     error("-X value should be one of: 32, 64, 32_64, (default) any");
2387*81ad6265SDimitry Andric 
2388fe6060f1SDimitry Andric   // Mach-O specific options.
2389fe6060f1SDimitry Andric   FormatMachOasHex = Args.hasArg(OPT_x);
2390fe6060f1SDimitry Andric   AddDyldInfo = Args.hasArg(OPT_add_dyldinfo);
2391fe6060f1SDimitry Andric   AddInlinedInfo = Args.hasArg(OPT_add_inlinedinfo);
2392fe6060f1SDimitry Andric   DyldInfoOnly = Args.hasArg(OPT_dyldinfo_only);
2393fe6060f1SDimitry Andric   NoDyldInfo = Args.hasArg(OPT_no_dyldinfo);
23940b57cec5SDimitry Andric 
2395*81ad6265SDimitry Andric   // XCOFF specific options.
2396*81ad6265SDimitry Andric   NoRsrc = Args.hasArg(OPT_no_rsrc);
2397*81ad6265SDimitry Andric 
23980b57cec5SDimitry Andric   // llvm-nm only reads binary files.
23990b57cec5SDimitry Andric   if (error(sys::ChangeStdinToBinary()))
24000b57cec5SDimitry Andric     return 1;
24010b57cec5SDimitry Andric 
24020b57cec5SDimitry Andric   // These calls are needed so that we can read bitcode correctly.
24030b57cec5SDimitry Andric   llvm::InitializeAllTargetInfos();
24040b57cec5SDimitry Andric   llvm::InitializeAllTargetMCs();
24050b57cec5SDimitry Andric   llvm::InitializeAllAsmParsers();
24060b57cec5SDimitry Andric 
24070b57cec5SDimitry Andric   // The relative order of these is important. If you pass --size-sort it should
24080b57cec5SDimitry Andric   // only print out the size. However, if you pass -S --size-sort, it should
24090b57cec5SDimitry Andric   // print out both the size and address.
24100b57cec5SDimitry Andric   if (SizeSort && !PrintSize)
24110b57cec5SDimitry Andric     PrintAddress = false;
24120b57cec5SDimitry Andric   if (OutputFormat == sysv || SizeSort)
24130b57cec5SDimitry Andric     PrintSize = true;
24140b57cec5SDimitry Andric 
2415fe6060f1SDimitry Andric   for (const auto *A : Args.filtered(OPT_arch_EQ)) {
2416fe6060f1SDimitry Andric     SmallVector<StringRef, 2> Values;
2417fe6060f1SDimitry Andric     llvm::SplitString(A->getValue(), Values, ",");
2418fe6060f1SDimitry Andric     for (StringRef V : Values) {
2419fe6060f1SDimitry Andric       if (V == "all")
24200b57cec5SDimitry Andric         ArchAll = true;
2421fe6060f1SDimitry Andric       else if (MachOObjectFile::isValidArch(V))
2422fe6060f1SDimitry Andric         ArchFlags.push_back(V);
2423fe6060f1SDimitry Andric       else
2424fe6060f1SDimitry Andric         error("Unknown architecture named '" + V + "'",
24250b57cec5SDimitry Andric               "for the --arch option");
24260b57cec5SDimitry Andric     }
24270b57cec5SDimitry Andric   }
24280b57cec5SDimitry Andric 
2429fe6060f1SDimitry Andric   // Mach-O takes -s to accept two arguments. We emulate this by iterating over
2430fe6060f1SDimitry Andric   // both OPT_s and OPT_INPUT.
2431fe6060f1SDimitry Andric   std::vector<std::string> InputFilenames;
2432fe6060f1SDimitry Andric   int SegSectArgs = 0;
2433fe6060f1SDimitry Andric   for (opt::Arg *A : Args.filtered(OPT_s, OPT_INPUT)) {
2434fe6060f1SDimitry Andric     if (SegSectArgs > 0) {
2435fe6060f1SDimitry Andric       --SegSectArgs;
2436fe6060f1SDimitry Andric       SegSect.push_back(A->getValue());
2437fe6060f1SDimitry Andric     } else if (A->getOption().matches(OPT_s)) {
2438fe6060f1SDimitry Andric       SegSectArgs = 2;
2439fe6060f1SDimitry Andric     } else {
2440fe6060f1SDimitry Andric       InputFilenames.push_back(A->getValue());
2441fe6060f1SDimitry Andric     }
2442fe6060f1SDimitry Andric   }
24430b57cec5SDimitry Andric   if (!SegSect.empty() && SegSect.size() != 2)
24440b57cec5SDimitry Andric     error("bad number of arguments (must be two arguments)",
24450b57cec5SDimitry Andric           "for the -s option");
24460b57cec5SDimitry Andric 
2447fe6060f1SDimitry Andric   if (InputFilenames.empty())
2448fe6060f1SDimitry Andric     InputFilenames.push_back("a.out");
2449fe6060f1SDimitry Andric   if (InputFilenames.size() > 1)
2450fe6060f1SDimitry Andric     MultipleFiles = true;
2451fe6060f1SDimitry Andric 
24520b57cec5SDimitry Andric   if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
24530b57cec5SDimitry Andric     error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
24540b57cec5SDimitry Andric 
2455*81ad6265SDimitry Andric   if (ExportSymbols)
2456*81ad6265SDimitry Andric     exportSymbolNamesFromFiles(InputFilenames);
2457*81ad6265SDimitry Andric   else
24580b57cec5SDimitry Andric     llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
24590b57cec5SDimitry Andric 
24600b57cec5SDimitry Andric   if (HadError)
24610b57cec5SDimitry Andric     return 1;
24620b57cec5SDimitry Andric }
2463