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