summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-nm/llvm-nm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-nm/llvm-nm.cpp')
-rw-r--r--llvm/tools/llvm-nm/llvm-nm.cpp2137
1 files changed, 2137 insertions, 0 deletions
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
new file mode 100644
index 000000000000..ee55722dc139
--- /dev/null
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -0,0 +1,2137 @@
+//===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that works like traditional Unix "nm", that is, it
+// prints out the names of symbols in a bitcode or object file, along with some
+// information about each symbol.
+//
+// This "nm" supports many of the features of GNU "nm", including its different
+// output formats.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+enum OutputFormatTy { bsd, sysv, posix, darwin };
+
+cl::OptionCategory NMCat("llvm-nm Options");
+
+cl::opt<OutputFormatTy> OutputFormat(
+ "format", cl::desc("Specify output format"),
+ cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"),
+ clEnumVal(posix, "POSIX.2 format"),
+ clEnumVal(darwin, "Darwin -m format")),
+ cl::init(bsd), cl::cat(NMCat));
+cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
+ cl::aliasopt(OutputFormat));
+
+cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
+ cl::ZeroOrMore);
+
+cl::opt<bool> UndefinedOnly("undefined-only",
+ cl::desc("Show only undefined symbols"),
+ cl::cat(NMCat));
+cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
+ cl::aliasopt(UndefinedOnly), cl::Grouping);
+
+cl::opt<bool> DynamicSyms("dynamic",
+ cl::desc("Display the dynamic symbols instead "
+ "of normal symbols."),
+ cl::cat(NMCat));
+cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
+ cl::aliasopt(DynamicSyms), cl::Grouping);
+
+cl::opt<bool> DefinedOnly("defined-only", cl::desc("Show only defined symbols"),
+ cl::cat(NMCat));
+cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"),
+ cl::aliasopt(DefinedOnly), cl::Grouping);
+
+cl::opt<bool> ExternalOnly("extern-only",
+ cl::desc("Show only external symbols"),
+ cl::ZeroOrMore, cl::cat(NMCat));
+cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
+ cl::aliasopt(ExternalOnly), cl::Grouping,
+ cl::ZeroOrMore);
+
+cl::opt<bool> NoWeakSymbols("no-weak", cl::desc("Show only non-weak symbols"),
+ cl::cat(NMCat));
+cl::alias NoWeakSymbols2("W", cl::desc("Alias for --no-weak"),
+ cl::aliasopt(NoWeakSymbols), cl::Grouping);
+
+cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"), cl::Grouping,
+ cl::cat(NMCat));
+cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"),
+ cl::Grouping, cl::cat(NMCat));
+cl::alias Portability("portability", cl::desc("Alias for --format=posix"),
+ cl::aliasopt(POSIXFormat), cl::NotHidden);
+cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"),
+ cl::Grouping, cl::cat(NMCat));
+
+static cl::list<std::string>
+ ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
+ cl::ZeroOrMore, cl::cat(NMCat));
+bool ArchAll = false;
+
+cl::opt<bool> PrintFileName(
+ "print-file-name",
+ cl::desc("Precede each symbol with the object file it came from"),
+ cl::cat(NMCat));
+
+cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
+ cl::aliasopt(PrintFileName), cl::Grouping);
+cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
+ cl::aliasopt(PrintFileName), cl::Grouping);
+
+cl::opt<bool> DebugSyms("debug-syms",
+ cl::desc("Show all symbols, even debugger only"),
+ cl::cat(NMCat));
+cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
+ cl::aliasopt(DebugSyms), cl::Grouping);
+
+cl::opt<bool> NumericSort("numeric-sort", cl::desc("Sort symbols by address"),
+ cl::cat(NMCat));
+cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
+ cl::aliasopt(NumericSort), cl::Grouping);
+cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
+ cl::aliasopt(NumericSort), cl::Grouping);
+
+cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered"),
+ cl::cat(NMCat));
+cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort),
+ cl::Grouping);
+
+cl::opt<bool> Demangle("demangle", cl::ZeroOrMore,
+ cl::desc("Demangle C++ symbol names"), cl::cat(NMCat));
+cl::alias DemangleC("C", cl::desc("Alias for --demangle"),
+ cl::aliasopt(Demangle), cl::Grouping);
+cl::opt<bool> NoDemangle("no-demangle", cl::init(false), cl::ZeroOrMore,
+ cl::desc("Don't demangle symbol names"),
+ cl::cat(NMCat));
+
+cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order"),
+ cl::cat(NMCat));
+cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"),
+ cl::aliasopt(ReverseSort), cl::Grouping);
+
+cl::opt<bool> PrintSize("print-size",
+ cl::desc("Show symbol size as well as address"),
+ cl::cat(NMCat));
+cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
+ cl::aliasopt(PrintSize), cl::Grouping);
+bool MachOPrintSizeWarning = false;
+
+cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"),
+ cl::cat(NMCat));
+
+cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden,
+ cl::desc("Exclude aliases from output"),
+ cl::cat(NMCat));
+
+cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map"),
+ cl::cat(NMCat));
+cl::alias ArchiveMaps("M", cl::desc("Alias for --print-armap"),
+ cl::aliasopt(ArchiveMap), cl::Grouping);
+
+enum Radix { d, o, x };
+cl::opt<Radix>
+ AddressRadix("radix", cl::desc("Radix (o/d/x) for printing symbol Values"),
+ cl::values(clEnumVal(d, "decimal"), clEnumVal(o, "octal"),
+ clEnumVal(x, "hexadecimal")),
+ cl::init(x), cl::cat(NMCat));
+cl::alias RadixAlias("t", cl::desc("Alias for --radix"),
+ cl::aliasopt(AddressRadix));
+
+cl::opt<bool> JustSymbolName("just-symbol-name",
+ cl::desc("Print just the symbol's name"),
+ cl::cat(NMCat));
+cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"),
+ cl::aliasopt(JustSymbolName), cl::Grouping);
+
+cl::opt<bool> SpecialSyms("special-syms",
+ cl::desc("No-op. Used for GNU compatibility only"));
+
+cl::list<std::string> SegSect("s", cl::multi_val(2), cl::ZeroOrMore,
+ cl::value_desc("segment section"), cl::Hidden,
+ cl::desc("Dump only symbols from this segment "
+ "and section name, Mach-O only"),
+ cl::cat(NMCat));
+
+cl::opt<bool> FormatMachOasHex("x",
+ cl::desc("Print symbol entry in hex, "
+ "Mach-O only"),
+ cl::Grouping, cl::cat(NMCat));
+cl::opt<bool> AddDyldInfo("add-dyldinfo",
+ cl::desc("Add symbols from the dyldinfo not already "
+ "in the symbol table, Mach-O only"),
+ cl::cat(NMCat));
+cl::opt<bool> NoDyldInfo("no-dyldinfo",
+ cl::desc("Don't add any symbols from the dyldinfo, "
+ "Mach-O only"),
+ cl::cat(NMCat));
+cl::opt<bool> DyldInfoOnly("dyldinfo-only",
+ cl::desc("Show only symbols from the dyldinfo, "
+ "Mach-O only"),
+ cl::cat(NMCat));
+
+cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
+ cl::desc("Disable LLVM bitcode reader"),
+ cl::cat(NMCat));
+
+cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
+
+bool PrintAddress = true;
+
+bool MultipleFiles = false;
+
+bool HadError = false;
+
+std::string ToolName;
+} // anonymous namespace
+
+static void error(Twine Message, Twine Path = Twine()) {
+ HadError = true;
+ WithColor::error(errs(), ToolName) << Path << ": " << Message << ".\n";
+}
+
+static bool error(std::error_code EC, Twine Path = Twine()) {
+ if (EC) {
+ error(EC.message(), Path);
+ return true;
+ }
+ return false;
+}
+
+// This version of error() prints the archive name and member name, for example:
+// "libx.a(foo.o)" after the ToolName before the error message. It sets
+// HadError but returns allowing the code to move on to other archive members.
+static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
+ StringRef ArchitectureName = StringRef()) {
+ HadError = true;
+ WithColor::error(errs(), ToolName) << FileName;
+
+ Expected<StringRef> NameOrErr = C.getName();
+ // TODO: if we have a error getting the name then it would be nice to print
+ // the index of which archive member this is and or its offset in the
+ // archive instead of "???" as the name.
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ errs() << "(" << "???" << ")";
+ } else
+ errs() << "(" << NameOrErr.get() << ")";
+
+ if (!ArchitectureName.empty())
+ errs() << " (for architecture " << ArchitectureName << ") ";
+
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(std::move(E), OS);
+ OS.flush();
+ errs() << " " << Buf << "\n";
+}
+
+// This version of error() prints the file name and which architecture slice it
+// is from, for example: "foo.o (for architecture i386)" after the ToolName
+// before the error message. It sets HadError but returns allowing the code to
+// move on to other architecture slices.
+static void error(llvm::Error E, StringRef FileName,
+ StringRef ArchitectureName = StringRef()) {
+ HadError = true;
+ WithColor::error(errs(), ToolName) << FileName;
+
+ if (!ArchitectureName.empty())
+ errs() << " (for architecture " << ArchitectureName << ") ";
+
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(std::move(E), OS);
+ OS.flush();
+ errs() << " " << Buf << "\n";
+}
+
+namespace {
+struct NMSymbol {
+ uint64_t Address;
+ uint64_t Size;
+ char TypeChar;
+ StringRef Name;
+ StringRef SectionName;
+ StringRef TypeName;
+ BasicSymbolRef Sym;
+ // The Sym field above points to the native symbol in the object file,
+ // for Mach-O when we are creating symbols from the dyld info the above
+ // pointer is null as there is no native symbol. In these cases the fields
+ // below are filled in to represent what would have been a Mach-O nlist
+ // native symbol.
+ uint32_t SymFlags;
+ SectionRef Section;
+ uint8_t NType;
+ uint8_t NSect;
+ uint16_t NDesc;
+ StringRef IndirectName;
+};
+} // anonymous namespace
+
+static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) {
+ bool ADefined;
+ if (A.Sym.getRawDataRefImpl().p)
+ ADefined = !(A.Sym.getFlags() & SymbolRef::SF_Undefined);
+ else
+ ADefined = A.TypeChar != 'U';
+ bool BDefined;
+ if (B.Sym.getRawDataRefImpl().p)
+ BDefined = !(B.Sym.getFlags() & SymbolRef::SF_Undefined);
+ else
+ BDefined = B.TypeChar != 'U';
+ return std::make_tuple(ADefined, A.Address, A.Name, A.Size) <
+ std::make_tuple(BDefined, B.Address, B.Name, B.Size);
+}
+
+static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) {
+ return std::make_tuple(A.Size, A.Name, A.Address) <
+ std::make_tuple(B.Size, B.Name, B.Address);
+}
+
+static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
+ return std::make_tuple(A.Name, A.Size, A.Address) <
+ std::make_tuple(B.Name, B.Size, B.Address);
+}
+
+static char isSymbolList64Bit(SymbolicFile &Obj) {
+ if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
+ return Triple(IRObj->getTargetTriple()).isArch64Bit();
+ if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
+ return false;
+ if (isa<WasmObjectFile>(Obj))
+ return false;
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
+ return MachO->is64Bit();
+ return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
+}
+
+static StringRef CurrentFilename;
+static std::vector<NMSymbol> SymbolList;
+
+static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
+
+// darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
+// the OutputFormat is darwin or we are printing Mach-O symbols in hex. For
+// the darwin format it produces the same output as darwin's nm(1) -m output
+// and when printing Mach-O symbols in hex it produces the same output as
+// darwin's nm(1) -x format.
+static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
+ char *SymbolAddrStr, const char *printBlanks,
+ const char *printDashes,
+ const char *printFormat) {
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ uint32_t Filetype = MachO::MH_OBJECT;
+ uint32_t Flags = 0;
+ uint8_t NType = 0;
+ uint8_t NSect = 0;
+ uint16_t NDesc = 0;
+ uint32_t NStrx = 0;
+ uint64_t NValue = 0;
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (Obj.isIR()) {
+ uint32_t SymFlags = S.Sym.getFlags();
+ if (SymFlags & SymbolRef::SF_Global)
+ NType |= MachO::N_EXT;
+ if (SymFlags & SymbolRef::SF_Hidden)
+ NType |= MachO::N_PEXT;
+ if (SymFlags & SymbolRef::SF_Undefined)
+ NType |= MachO::N_EXT | MachO::N_UNDF;
+ else {
+ // Here we have a symbol definition. So to fake out a section name we
+ // use 1, 2 and 3 for section numbers. See below where they are used to
+ // print out fake section names.
+ NType |= MachO::N_SECT;
+ if (SymFlags & SymbolRef::SF_Const)
+ NSect = 3;
+ else if (SymFlags & SymbolRef::SF_Executable)
+ NSect = 1;
+ else
+ NSect = 2;
+ }
+ if (SymFlags & SymbolRef::SF_Weak)
+ NDesc |= MachO::N_WEAK_DEF;
+ } else {
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ Filetype = H_64.filetype;
+ Flags = H_64.flags;
+ if (SymDRI.p){
+ MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ NStrx = STE_64.n_strx;
+ NValue = STE_64.n_value;
+ } else {
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
+ NStrx = 0;
+ NValue = S.Address;
+ }
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ Filetype = H.filetype;
+ Flags = H.flags;
+ if (SymDRI.p){
+ MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ NStrx = STE.n_strx;
+ NValue = STE.n_value;
+ } else {
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
+ NStrx = 0;
+ NValue = S.Address;
+ }
+ }
+ }
+
+ // If we are printing Mach-O symbols in hex do that and return.
+ if (FormatMachOasHex) {
+ outs() << format(printFormat, NValue) << ' '
+ << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
+ << S.Name;
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
+ outs() << " (indirect for ";
+ outs() << format(printFormat, NValue) << ' ';
+ StringRef IndirectName;
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
+ }
+ outs() << "\n";
+ return;
+ }
+
+ if (PrintAddress) {
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR)
+ strcpy(SymbolAddrStr, printBlanks);
+ if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE)
+ strcpy(SymbolAddrStr, printDashes);
+ outs() << SymbolAddrStr << ' ';
+ }
+
+ switch (NType & MachO::N_TYPE) {
+ case MachO::N_UNDF:
+ if (NValue != 0) {
+ outs() << "(common) ";
+ if (MachO::GET_COMM_ALIGN(NDesc) != 0)
+ outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") ";
+ } else {
+ if ((NType & MachO::N_TYPE) == MachO::N_PBUD)
+ outs() << "(prebound ";
+ else
+ outs() << "(";
+ if ((NDesc & MachO::REFERENCE_TYPE) ==
+ MachO::REFERENCE_FLAG_UNDEFINED_LAZY)
+ outs() << "undefined [lazy bound]) ";
+ else if ((NDesc & MachO::REFERENCE_TYPE) ==
+ MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
+ outs() << "undefined [private lazy bound]) ";
+ else if ((NDesc & MachO::REFERENCE_TYPE) ==
+ MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
+ outs() << "undefined [private]) ";
+ else
+ outs() << "undefined) ";
+ }
+ break;
+ case MachO::N_ABS:
+ outs() << "(absolute) ";
+ break;
+ case MachO::N_INDR:
+ outs() << "(indirect) ";
+ break;
+ case MachO::N_SECT: {
+ if (Obj.isIR()) {
+ // For llvm bitcode files print out a fake section name using the values
+ // use 1, 2 and 3 for section numbers as set above.
+ if (NSect == 1)
+ outs() << "(LTO,CODE) ";
+ else if (NSect == 2)
+ outs() << "(LTO,DATA) ";
+ else if (NSect == 3)
+ outs() << "(LTO,RODATA) ";
+ else
+ outs() << "(?,?) ";
+ break;
+ }
+ section_iterator Sec = SectionRef();
+ if (S.Sym.getRawDataRefImpl().p) {
+ Expected<section_iterator> SecOrErr =
+ MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
+ if (!SecOrErr) {
+ consumeError(SecOrErr.takeError());
+ outs() << "(?,?) ";
+ break;
+ }
+ Sec = *SecOrErr;
+ if (Sec == MachO->section_end()) {
+ outs() << "(?,?) ";
+ break;
+ }
+ } else {
+ Sec = S.Section;
+ }
+ DataRefImpl Ref = Sec->getRawDataRefImpl();
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
+ SectionName = *NameOrErr;
+ StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
+ outs() << "(" << SegmentName << "," << SectionName << ") ";
+ break;
+ }
+ default:
+ outs() << "(?) ";
+ break;
+ }
+
+ if (NType & MachO::N_EXT) {
+ if (NDesc & MachO::REFERENCED_DYNAMICALLY)
+ outs() << "[referenced dynamically] ";
+ if (NType & MachO::N_PEXT) {
+ if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF)
+ outs() << "weak private external ";
+ else
+ outs() << "private external ";
+ } else {
+ if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF ||
+ (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) {
+ if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) ==
+ (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
+ outs() << "weak external automatically hidden ";
+ else
+ outs() << "weak external ";
+ } else
+ outs() << "external ";
+ }
+ } else {
+ if (NType & MachO::N_PEXT)
+ outs() << "non-external (was a private external) ";
+ else
+ outs() << "non-external ";
+ }
+
+ if (Filetype == MachO::MH_OBJECT) {
+ if (NDesc & MachO::N_NO_DEAD_STRIP)
+ outs() << "[no dead strip] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
+ NDesc & MachO::N_SYMBOL_RESOLVER)
+ outs() << "[symbol resolver] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
+ outs() << "[alt entry] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
+ outs() << "[cold func] ";
+ }
+
+ if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
+ outs() << "[Thumb] ";
+
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
+ outs() << S.Name << " (for ";
+ StringRef IndirectName;
+ if (MachO) {
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
+ } else
+ outs() << "?)";
+ } else
+ outs() << S.Name;
+
+ if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
+ (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
+ (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
+ uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
+ if (LibraryOrdinal != 0) {
+ if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL)
+ outs() << " (from executable)";
+ else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL)
+ outs() << " (dynamically looked up)";
+ else {
+ StringRef LibraryName;
+ if (!MachO ||
+ MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName))
+ outs() << " (from bad library ordinal " << LibraryOrdinal << ")";
+ else
+ outs() << " (from " << LibraryName << ")";
+ }
+ }
+ }
+
+ outs() << "\n";
+}
+
+// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
+struct DarwinStabName {
+ uint8_t NType;
+ const char *Name;
+};
+static const struct DarwinStabName DarwinStabNames[] = {
+ {MachO::N_GSYM, "GSYM"},
+ {MachO::N_FNAME, "FNAME"},
+ {MachO::N_FUN, "FUN"},
+ {MachO::N_STSYM, "STSYM"},
+ {MachO::N_LCSYM, "LCSYM"},
+ {MachO::N_BNSYM, "BNSYM"},
+ {MachO::N_PC, "PC"},
+ {MachO::N_AST, "AST"},
+ {MachO::N_OPT, "OPT"},
+ {MachO::N_RSYM, "RSYM"},
+ {MachO::N_SLINE, "SLINE"},
+ {MachO::N_ENSYM, "ENSYM"},
+ {MachO::N_SSYM, "SSYM"},
+ {MachO::N_SO, "SO"},
+ {MachO::N_OSO, "OSO"},
+ {MachO::N_LSYM, "LSYM"},
+ {MachO::N_BINCL, "BINCL"},
+ {MachO::N_SOL, "SOL"},
+ {MachO::N_PARAMS, "PARAM"},
+ {MachO::N_VERSION, "VERS"},
+ {MachO::N_OLEVEL, "OLEV"},
+ {MachO::N_PSYM, "PSYM"},
+ {MachO::N_EINCL, "EINCL"},
+ {MachO::N_ENTRY, "ENTRY"},
+ {MachO::N_LBRAC, "LBRAC"},
+ {MachO::N_EXCL, "EXCL"},
+ {MachO::N_RBRAC, "RBRAC"},
+ {MachO::N_BCOMM, "BCOMM"},
+ {MachO::N_ECOMM, "ECOMM"},
+ {MachO::N_ECOML, "ECOML"},
+ {MachO::N_LENG, "LENG"},
+};
+
+static const char *getDarwinStabString(uint8_t NType) {
+ for (auto I : makeArrayRef(DarwinStabNames))
+ if (I.NType == NType)
+ return I.Name;
+ return nullptr;
+}
+
+// darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
+// a stab n_type value in a Mach-O file.
+static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
+ MachO::nlist_64 STE_64;
+ MachO::nlist STE;
+ uint8_t NType;
+ uint8_t NSect;
+ uint16_t NDesc;
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
+ if (MachO->is64Bit()) {
+ STE_64 = MachO->getSymbol64TableEntry(SymDRI);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ } else {
+ STE = MachO->getSymbolTableEntry(SymDRI);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ }
+
+ outs() << format(" %02x %04x ", NSect, NDesc);
+ if (const char *stabString = getDarwinStabString(NType))
+ outs() << format("%5.5s", stabString);
+ else
+ outs() << format(" %02x", NType);
+}
+
+static Optional<std::string> demangle(StringRef Name, bool StripUnderscore) {
+ if (StripUnderscore && !Name.empty() && Name[0] == '_')
+ Name = Name.substr(1);
+
+ if (!Name.startswith("_Z"))
+ return None;
+
+ int Status;
+ char *Undecorated =
+ itaniumDemangle(Name.str().c_str(), nullptr, nullptr, &Status);
+ if (Status != 0)
+ return None;
+
+ std::string S(Undecorated);
+ free(Undecorated);
+ return S;
+}
+
+static bool symbolIsDefined(const NMSymbol &Sym) {
+ return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
+}
+
+static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
+ const std::string &ArchiveName,
+ const std::string &ArchitectureName) {
+ if (!NoSort) {
+ using Comparator = bool (*)(const NMSymbol &, const NMSymbol &);
+ Comparator Cmp;
+ if (NumericSort)
+ Cmp = &compareSymbolAddress;
+ else if (SizeSort)
+ Cmp = &compareSymbolSize;
+ else
+ Cmp = &compareSymbolName;
+
+ if (ReverseSort)
+ llvm::sort(SymbolList, [=](const NMSymbol &A, const NMSymbol &B) -> bool {
+ return Cmp(B, A);
+ });
+ else
+ llvm::sort(SymbolList, Cmp);
+ }
+
+ if (!PrintFileName) {
+ if (OutputFormat == posix && MultipleFiles && printName) {
+ outs() << '\n' << CurrentFilename << ":\n";
+ } else if (OutputFormat == bsd && MultipleFiles && printName) {
+ outs() << "\n" << CurrentFilename << ":\n";
+ } else if (OutputFormat == sysv) {
+ outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n";
+ if (isSymbolList64Bit(Obj))
+ outs() << "Name Value Class Type"
+ << " Size Line Section\n";
+ else
+ outs() << "Name Value Class Type"
+ << " Size Line Section\n";
+ }
+ }
+
+ const char *printBlanks, *printDashes, *printFormat;
+ if (isSymbolList64Bit(Obj)) {
+ printBlanks = " ";
+ printDashes = "----------------";
+ switch (AddressRadix) {
+ case Radix::o:
+ printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64;
+ break;
+ case Radix::x:
+ printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64;
+ break;
+ default:
+ printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64;
+ }
+ } else {
+ printBlanks = " ";
+ printDashes = "--------";
+ switch (AddressRadix) {
+ case Radix::o:
+ printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64;
+ break;
+ case Radix::x:
+ printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64;
+ break;
+ default:
+ printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64;
+ }
+ }
+
+ auto writeFileName = [&](raw_ostream &S) {
+ if (!ArchitectureName.empty())
+ S << "(for architecture " << ArchitectureName << "):";
+ if (OutputFormat == posix && !ArchiveName.empty())
+ S << ArchiveName << "[" << CurrentFilename << "]: ";
+ else {
+ if (!ArchiveName.empty())
+ S << ArchiveName << ":";
+ S << CurrentFilename << ": ";
+ }
+ };
+
+ if (SymbolList.empty()) {
+ if (PrintFileName)
+ writeFileName(errs());
+ errs() << "no symbols\n";
+ }
+
+ for (const NMSymbol &S : SymbolList) {
+ uint32_t SymFlags;
+ std::string Name = S.Name.str();
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (Demangle) {
+ if (Optional<std::string> Opt = demangle(S.Name, MachO))
+ Name = *Opt;
+ }
+ if (S.Sym.getRawDataRefImpl().p)
+ SymFlags = S.Sym.getFlags();
+ else
+ SymFlags = S.SymFlags;
+
+ bool Undefined = SymFlags & SymbolRef::SF_Undefined;
+ bool Global = SymFlags & SymbolRef::SF_Global;
+ bool Weak = SymFlags & SymbolRef::SF_Weak;
+ if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
+ (!Global && ExternalOnly) || (Weak && NoWeakSymbols))
+ continue;
+ if (PrintFileName)
+ writeFileName(outs());
+ if ((JustSymbolName ||
+ (UndefinedOnly && MachO && OutputFormat != darwin)) &&
+ OutputFormat != posix) {
+ outs() << Name << "\n";
+ continue;
+ }
+
+ char SymbolAddrStr[23], SymbolSizeStr[23];
+
+ // If the format is SysV or the symbol isn't defined, then print spaces.
+ if (OutputFormat == sysv || !symbolIsDefined(S)) {
+ if (OutputFormat == posix) {
+ format(printFormat, S.Address)
+ .print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ } else {
+ strcpy(SymbolAddrStr, printBlanks);
+ strcpy(SymbolSizeStr, printBlanks);
+ }
+ }
+
+ if (symbolIsDefined(S)) {
+ // Otherwise, print the symbol address and size.
+ if (Obj.isIR())
+ strcpy(SymbolAddrStr, printDashes);
+ else if (MachO && S.TypeChar == 'I')
+ strcpy(SymbolAddrStr, printBlanks);
+ else
+ format(printFormat, S.Address)
+ .print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ }
+
+ // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
+ // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
+ // nm(1) -m output or hex, else if OutputFormat is darwin or we are
+ // printing Mach-O symbols in hex and not a Mach-O object fall back to
+ // OutputFormat bsd (see below).
+ if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
+ darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
+ printFormat);
+ } else if (OutputFormat == posix) {
+ outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
+ << (MachO ? "0" : SymbolSizeStr) << "\n";
+ } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
+ if (PrintAddress)
+ outs() << SymbolAddrStr << ' ';
+ if (PrintSize)
+ outs() << SymbolSizeStr << ' ';
+ outs() << S.TypeChar;
+ if (S.TypeChar == '-' && MachO)
+ darwinPrintStab(MachO, S);
+ outs() << " " << Name;
+ if (S.TypeChar == 'I' && MachO) {
+ outs() << " (indirect for ";
+ if (S.Sym.getRawDataRefImpl().p) {
+ StringRef IndirectName;
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
+ }
+ outs() << "\n";
+ } else if (OutputFormat == sysv) {
+ outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
+ << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
+ << SymbolSizeStr << "| |" << S.SectionName << "\n";
+ }
+ }
+
+ SymbolList.clear();
+}
+
+static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
+ basic_symbol_iterator I) {
+ // OK, this is ELF
+ elf_symbol_iterator SymI(I);
+
+ Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
+ if (!SecIOrErr) {
+ consumeError(SecIOrErr.takeError());
+ return '?';
+ }
+
+ uint8_t Binding = SymI->getBinding();
+ if (Binding == ELF::STB_GNU_UNIQUE)
+ return 'u';
+
+ assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
+ if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
+ return '?';
+
+ elf_section_iterator SecI = *SecIOrErr;
+ if (SecI != Obj.section_end()) {
+ uint32_t Type = SecI->getType();
+ uint64_t Flags = SecI->getFlags();
+ if (Flags & ELF::SHF_EXECINSTR)
+ return 't';
+ if (Type == ELF::SHT_NOBITS)
+ return 'b';
+ if (Flags & ELF::SHF_ALLOC)
+ return Flags & ELF::SHF_WRITE ? 'd' : 'r';
+
+ auto NameOrErr = SecI->getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ return '?';
+ }
+ if ((*NameOrErr).startswith(".debug"))
+ return 'N';
+ if (!(Flags & ELF::SHF_WRITE))
+ return 'n';
+ }
+
+ return '?';
+}
+
+static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
+ COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
+ // OK, this is COFF.
+ symbol_iterator SymI(I);
+
+ Expected<StringRef> Name = SymI->getName();
+ if (!Name) {
+ consumeError(Name.takeError());
+ return '?';
+ }
+
+ char Ret = StringSwitch<char>(*Name)
+ .StartsWith(".debug", 'N')
+ .StartsWith(".sxdata", 'N')
+ .Default('?');
+
+ if (Ret != '?')
+ return Ret;
+
+ uint32_t Characteristics = 0;
+ if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
+ Expected<section_iterator> SecIOrErr = SymI->getSection();
+ if (!SecIOrErr) {
+ consumeError(SecIOrErr.takeError());
+ return '?';
+ }
+ section_iterator SecI = *SecIOrErr;
+ const coff_section *Section = Obj.getCOFFSection(*SecI);
+ Characteristics = Section->Characteristics;
+ if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
+ if (NameOrErr->startswith(".idata"))
+ return 'i';
+ }
+
+ switch (Symb.getSectionNumber()) {
+ case COFF::IMAGE_SYM_DEBUG:
+ return 'n';
+ default:
+ // Check section type.
+ if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
+ return 't';
+ if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
+ if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ return 'b';
+ if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
+ return 'i';
+ // Check for section symbol.
+ if (Symb.isSectionDefinition())
+ return 's';
+ }
+
+ return '?';
+}
+
+static char getSymbolNMTypeChar(COFFImportFile &Obj) {
+ switch (Obj.getCOFFImportHeader()->getType()) {
+ case COFF::IMPORT_CODE:
+ return 't';
+ case COFF::IMPORT_DATA:
+ return 'd';
+ case COFF::IMPORT_CONST:
+ return 'r';
+ }
+ return '?';
+}
+
+static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
+ DataRefImpl Symb = I->getRawDataRefImpl();
+ uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
+ : Obj.getSymbolTableEntry(Symb).n_type;
+
+ if (NType & MachO::N_STAB)
+ return '-';
+
+ switch (NType & MachO::N_TYPE) {
+ case MachO::N_ABS:
+ return 's';
+ case MachO::N_INDR:
+ return 'i';
+ case MachO::N_SECT: {
+ Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb);
+ if (!SecOrErr) {
+ consumeError(SecOrErr.takeError());
+ return 's';
+ }
+ section_iterator Sec = *SecOrErr;
+ if (Sec == Obj.section_end())
+ return 's';
+ DataRefImpl Ref = Sec->getRawDataRefImpl();
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
+ SectionName = *NameOrErr;
+ StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
+ if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
+ SegmentName == "__TEXT_EXEC" && SectionName == "__text")
+ return 't';
+ if (SegmentName == "__TEXT" && SectionName == "__text")
+ return 't';
+ if (SegmentName == "__DATA" && SectionName == "__data")
+ return 'd';
+ if (SegmentName == "__DATA" && SectionName == "__bss")
+ return 'b';
+ return 's';
+ }
+ }
+
+ return '?';
+}
+
+static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
+ uint32_t Flags = I->getFlags();
+ if (Flags & SymbolRef::SF_Executable)
+ return 't';
+ return 'd';
+}
+
+static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
+ uint32_t Flags = I->getFlags();
+ // FIXME: should we print 'b'? At the IR level we cannot be sure if this
+ // will be in bss or not, but we could approximate.
+ if (Flags & SymbolRef::SF_Executable)
+ return 't';
+ else if (Triple(Obj.getTargetTriple()).isOSDarwin() &&
+ (Flags & SymbolRef::SF_Const))
+ return 's';
+ else
+ return 'd';
+}
+
+static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
+ return !dyn_cast<ELFObjectFileBase>(&Obj)
+ ? false
+ : elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
+}
+
+// For ELF object files, Set TypeName to the symbol typename, to be printed
+// in the 'Type' column of the SYSV format output.
+static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
+ if (isa<ELFObjectFileBase>(&Obj)) {
+ elf_symbol_iterator SymI(I);
+ return SymI->getELFTypeName();
+ }
+ return "";
+}
+
+// Return Posix nm class type tag (single letter), but also set SecName and
+// section and name, to be used in format=sysv output.
+static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
+ StringRef &SecName) {
+ uint32_t Symflags = I->getFlags();
+ if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {
+ if (Symflags & object::SymbolRef::SF_Absolute)
+ SecName = "*ABS*";
+ else if (Symflags & object::SymbolRef::SF_Common)
+ SecName = "*COM*";
+ else if (Symflags & object::SymbolRef::SF_Undefined)
+ SecName = "*UND*";
+ else {
+ elf_symbol_iterator SymI(I);
+ Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
+ if (!SecIOrErr) {
+ consumeError(SecIOrErr.takeError());
+ return '?';
+ }
+
+ if (*SecIOrErr == ELFObj->section_end())
+ return '?';
+
+ Expected<StringRef> NameOrErr = (*SecIOrErr)->getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ return '?';
+ }
+ SecName = *NameOrErr;
+ }
+ }
+
+ if ((Symflags & object::SymbolRef::SF_Weak) && !isa<MachOObjectFile>(Obj)) {
+ char Ret = isObject(Obj, I) ? 'v' : 'w';
+ return (!(Symflags & object::SymbolRef::SF_Undefined)) ? toupper(Ret) : Ret;
+ }
+
+ if (Symflags & object::SymbolRef::SF_Undefined)
+ return 'U';
+
+ if (Symflags & object::SymbolRef::SF_Common)
+ return 'C';
+
+ char Ret = '?';
+ if (Symflags & object::SymbolRef::SF_Absolute)
+ Ret = 'a';
+ else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*IR, I);
+ else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*COFF, I);
+ else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*COFFImport);
+ else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*MachO, I);
+ else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*Wasm, I);
+ else
+ Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
+
+ if (!(Symflags & object::SymbolRef::SF_Global))
+ return Ret;
+
+ if (Obj.isELF() && ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
+ return Ret;
+
+ return toupper(Ret);
+}
+
+// getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
+// option to dump only those symbols from that section in a Mach-O file.
+// It is called once for each Mach-O file from dumpSymbolNamesFromObject()
+// to get the section number for that named section from the command line
+// arguments. It returns the section number for that section in the Mach-O
+// file or zero it is not present.
+static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
+ unsigned Nsect = 1;
+ for (auto &S : Obj->sections()) {
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
+ SectionName = *NameOrErr;
+ StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
+ if (SegmentName == SegSect[0] && SectionName == SegSect[1])
+ return Nsect;
+ Nsect++;
+ }
+ return 0;
+}
+
+// getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
+// option to dump only those symbols from that section in a Mach-O file.
+// It is called once for each symbol in a Mach-O file from
+// dumpSymbolNamesFromObject() and returns the section number for that symbol
+// if it is in a section, else it returns 0.
+static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
+ DataRefImpl Symb = Sym.getRawDataRefImpl();
+ if (Obj.is64Bit()) {
+ MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
+ return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
+ }
+ MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
+ return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
+}
+
+static void
+dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
+ const std::string &ArchiveName = std::string(),
+ const std::string &ArchitectureName = std::string()) {
+ auto Symbols = Obj.symbols();
+ if (DynamicSyms) {
+ const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
+ if (!E) {
+ error("File format has no dynamic symbol table", Obj.getFileName());
+ return;
+ }
+ Symbols = E->getDynamicSymbolIterators();
+ }
+ std::string NameBuffer;
+ raw_string_ostream OS(NameBuffer);
+ // If a "-s segname sectname" option was specified and this is a Mach-O
+ // file get the section number for that section in this object file.
+ unsigned int Nsect = 0;
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (!SegSect.empty() && MachO) {
+ Nsect = getNsectForSegSect(MachO);
+ // If this section is not in the object file no symbols are printed.
+ if (Nsect == 0)
+ return;
+ }
+ if (!MachO || !DyldInfoOnly) {
+ for (BasicSymbolRef Sym : Symbols) {
+ uint32_t SymFlags = Sym.getFlags();
+ if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
+ continue;
+ if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
+ continue;
+ // If a "-s segname sectname" option was specified and this is a Mach-O
+ // file and this section appears in this file, Nsect will be non-zero then
+ // see if this symbol is a symbol from that section and if not skip it.
+ if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
+ continue;
+ NMSymbol S = {};
+ S.Size = 0;
+ S.Address = 0;
+ if (isa<ELFObjectFileBase>(&Obj))
+ S.Size = ELFSymbolRef(Sym).getSize();
+ if (PrintAddress && isa<ObjectFile>(Obj)) {
+ SymbolRef SymRef(Sym);
+ Expected<uint64_t> AddressOrErr = SymRef.getAddress();
+ if (!AddressOrErr) {
+ consumeError(AddressOrErr.takeError());
+ break;
+ }
+ S.Address = *AddressOrErr;
+ }
+ S.TypeName = getNMTypeName(Obj, Sym);
+ S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
+ if (Error E = Sym.printName(OS)) {
+ if (MachO) {
+ OS << "bad string index";
+ consumeError(std::move(E));
+ } else
+ error(std::move(E), Obj.getFileName());
+ }
+ OS << '\0';
+ S.Sym = Sym;
+ SymbolList.push_back(S);
+ }
+ }
+
+ OS.flush();
+ const char *P = NameBuffer.c_str();
+ unsigned I;
+ for (I = 0; I < SymbolList.size(); ++I) {
+ SymbolList[I].Name = P;
+ P += strlen(P) + 1;
+ }
+
+ // If this is a Mach-O file where the nlist symbol table is out of sync
+ // with the dyld export trie then look through exports and fake up symbols
+ // for the ones that are missing (also done with the -add-dyldinfo flag).
+ // This is needed if strip(1) -T is run on a binary containing swift
+ // language symbols for example. The option -only-dyldinfo will fake up
+ // all symbols from the dyld export trie as well as the bind info.
+ std::string ExportsNameBuffer;
+ raw_string_ostream EOS(ExportsNameBuffer);
+ std::string BindsNameBuffer;
+ raw_string_ostream BOS(BindsNameBuffer);
+ std::string LazysNameBuffer;
+ raw_string_ostream LOS(LazysNameBuffer);
+ std::string WeaksNameBuffer;
+ raw_string_ostream WOS(WeaksNameBuffer);
+ std::string FunctionStartsNameBuffer;
+ raw_string_ostream FOS(FunctionStartsNameBuffer);
+ if (MachO && !NoDyldInfo) {
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ uint32_t HFlags = 0;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ HFlags = H_64.flags;
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ HFlags = H.flags;
+ }
+ uint64_t BaseSegmentAddress = 0;
+ for (const auto &Command : MachO->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ }
+ }
+ if (DyldInfoOnly || AddDyldInfo ||
+ HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
+ unsigned ExportsAdded = 0;
+ Error Err = Error::success();
+ for (const llvm::object::ExportEntry &Entry : MachO->exports(Err)) {
+ bool found = false;
+ bool ReExport = false;
+ if (!DyldInfoOnly) {
+ for (const NMSymbol &S : SymbolList)
+ if (S.Address == Entry.address() + BaseSegmentAddress &&
+ S.Name == Entry.name()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ NMSymbol S = {};
+ S.Address = Entry.address() + BaseSegmentAddress;
+ S.Size = 0;
+ S.TypeChar = '\0';
+ S.Name = Entry.name();
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ S.Sym = BasicSymbolRef();
+ S.SymFlags = SymbolRef::SF_Global;
+ S.Section = SectionRef();
+ S.NType = 0;
+ S.NSect = 0;
+ S.NDesc = 0;
+ S.IndirectName = StringRef();
+
+ uint64_t EFlags = Entry.flags();
+ bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ bool Resolver = (EFlags &
+ MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+ bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ if (WeakDef)
+ S.NDesc |= MachO::N_WEAK_DEF;
+ if (Abs) {
+ S.NType = MachO::N_EXT | MachO::N_ABS;
+ S.TypeChar = 'A';
+ } else if (ReExport) {
+ S.NType = MachO::N_EXT | MachO::N_INDR;
+ S.TypeChar = 'I';
+ } else {
+ S.NType = MachO::N_EXT | MachO::N_SECT;
+ if (Resolver) {
+ S.Address = Entry.other() + BaseSegmentAddress;
+ if ((S.Address & 1) != 0 &&
+ !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
+ S.Address &= ~1LL;
+ S.NDesc |= MachO::N_ARM_THUMB_DEF;
+ }
+ } else {
+ S.Address = Entry.address() + BaseSegmentAddress;
+ }
+ StringRef SegmentName = StringRef();
+ StringRef SectionName = StringRef();
+ for (const SectionRef &Section : MachO->sections()) {
+ S.NSect++;
+
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ SectionName = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ SegmentName = MachO->getSectionFinalSegmentName(
+ Section.getRawDataRefImpl());
+ if (S.Address >= Section.getAddress() &&
+ S.Address < Section.getAddress() + Section.getSize()) {
+ S.Section = Section;
+ break;
+ } else if (Entry.name() == "__mh_execute_header" &&
+ SegmentName == "__TEXT" && SectionName == "__text") {
+ S.Section = Section;
+ S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
+ break;
+ }
+ }
+ if (SegmentName == "__TEXT" && SectionName == "__text")
+ S.TypeChar = 'T';
+ else if (SegmentName == "__DATA" && SectionName == "__data")
+ S.TypeChar = 'D';
+ else if (SegmentName == "__DATA" && SectionName == "__bss")
+ S.TypeChar = 'B';
+ else
+ S.TypeChar = 'S';
+ }
+ SymbolList.push_back(S);
+
+ EOS << Entry.name();
+ EOS << '\0';
+ ExportsAdded++;
+
+ // For ReExports there are a two more things to do, first add the
+ // indirect name and second create the undefined symbol using the
+ // referened dynamic library.
+ if (ReExport) {
+
+ // Add the indirect name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+
+ // Now create the undefined symbol using the referened dynamic
+ // library.
+ NMSymbol U = {};
+ U.Address = 0;
+ U.Size = 0;
+ U.TypeChar = 'U';
+ if (Entry.otherName().empty())
+ U.Name = Entry.name();
+ else
+ U.Name = Entry.otherName();
+ // Again there is no symbol in the nlist symbol table for this so
+ // we set Sym effectivly to null and the rest of code in here must
+ // test for it and not do things like Sym.getFlags() for it.
+ U.Sym = BasicSymbolRef();
+ U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ U.Section = SectionRef();
+ U.NType = MachO::N_EXT | MachO::N_UNDF;
+ U.NSect = 0;
+ U.NDesc = 0;
+ // The library ordinal for this undefined symbol is in the export
+ // trie Entry.other().
+ MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
+ U.IndirectName = StringRef();
+ SymbolList.push_back(U);
+
+ // Finally add the undefined symbol's name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+ ExportsAdded++;
+ }
+ }
+ }
+ if (Err)
+ error(std::move(Err), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (ExportsAdded) {
+ EOS.flush();
+ const char *Q = ExportsNameBuffer.c_str();
+ for (unsigned K = 0; K < ExportsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the bind entries.
+ unsigned BindsAdded = 0;
+ Error BErr = Error::success();
+ StringRef LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else if(!DyldInfoOnly) {
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol B = {};
+ B.Address = 0;
+ B.Size = 0;
+ B.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ B.Sym = BasicSymbolRef();
+ B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ B.NType = MachO::N_EXT | MachO::N_UNDF;
+ B.NSect = 0;
+ B.NDesc = 0;
+ MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
+ B.IndirectName = StringRef();
+ B.Name = Entry.symbolName();
+ SymbolList.push_back(B);
+ BOS << Entry.symbolName();
+ BOS << '\0';
+ BindsAdded++;
+ }
+ }
+ if (BErr)
+ error(std::move(BErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (BindsAdded) {
+ BOS.flush();
+ const char *Q = BindsNameBuffer.c_str();
+ for (unsigned K = 0; K < BindsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the lazy bind entries.
+ unsigned LazysAdded = 0;
+ Error LErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->lazyBindTable(LErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else {
+ // Here we must check to see it this symbol is already in the
+ // SymbolList as it might have already have been added above via a
+ // non-lazy (bind) entry.
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol L = {};
+ L.Name = Entry.symbolName();
+ L.Address = 0;
+ L.Size = 0;
+ L.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ L.Sym = BasicSymbolRef();
+ L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ L.NType = MachO::N_EXT | MachO::N_UNDF;
+ L.NSect = 0;
+ // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
+ // makes sence since we are creating this from a lazy bind entry.
+ L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
+ MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
+ L.IndirectName = StringRef();
+ SymbolList.push_back(L);
+ LOS << Entry.symbolName();
+ LOS << '\0';
+ LazysAdded++;
+ }
+ }
+ if (LErr)
+ error(std::move(LErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (LazysAdded) {
+ LOS.flush();
+ const char *Q = LazysNameBuffer.c_str();
+ for (unsigned K = 0; K < LazysAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefineds symbol from the weak bind entries which are not
+ // strong symbols.
+ unsigned WeaksAdded = 0;
+ Error WErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->weakBindTable(WErr)) {
+ bool found = false;
+ unsigned J = 0;
+ if (LastSymbolName == Entry.symbolName() ||
+ Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
+ found = true;
+ } else {
+ for (J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName()) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol W;
+ memset(&W, '\0', sizeof(NMSymbol));
+ W.Name = Entry.symbolName();
+ W.Address = 0;
+ W.Size = 0;
+ W.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ W.Sym = BasicSymbolRef();
+ W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ W.NType = MachO::N_EXT | MachO::N_UNDF;
+ W.NSect = 0;
+ // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
+ // what is created in this case by the linker when there are real
+ // symbols in the nlist structs.
+ W.NDesc = MachO::N_WEAK_DEF;
+ W.IndirectName = StringRef();
+ SymbolList.push_back(W);
+ WOS << Entry.symbolName();
+ WOS << '\0';
+ WeaksAdded++;
+ } else {
+ // This is the case the symbol was previously been found and it could
+ // have been added from a bind or lazy bind symbol. If so and not
+ // a definition also mark it as weak.
+ if (SymbolList[J].TypeChar == 'U')
+ // See comment above about N_WEAK_DEF.
+ SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
+ }
+ }
+ if (WErr)
+ error(std::move(WErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (WeaksAdded) {
+ WOS.flush();
+ const char *Q = WeaksNameBuffer.c_str();
+ for (unsigned K = 0; K < WeaksAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Trying adding symbol from the function starts table and LC_MAIN entry
+ // point.
+ SmallVector<uint64_t, 8> FoundFns;
+ uint64_t lc_main_offset = UINT64_MAX;
+ for (const auto &Command : MachO->load_commands()) {
+ if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
+ // We found a function starts segment, parse the addresses for
+ // consumption.
+ MachO::linkedit_data_command LLC =
+ MachO->getLinkeditDataLoadCommand(Command);
+
+ MachO->ReadULEB128s(LLC.dataoff, FoundFns);
+ } else if (Command.C.cmd == MachO::LC_MAIN) {
+ MachO::entry_point_command LCmain =
+ MachO->getEntryPointCommand(Command);
+ lc_main_offset = LCmain.entryoff;
+ }
+ }
+ // See if these addresses are already in the symbol table.
+ unsigned FunctionStartsAdded = 0;
+ for (uint64_t f = 0; f < FoundFns.size(); f++) {
+ bool found = false;
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
+ found = true;
+ }
+ // See this address is not already in the symbol table fake up an
+ // nlist for it.
+ if (!found) {
+ NMSymbol F = {};
+ F.Name = "<redacted function X>";
+ F.Address = FoundFns[f] + BaseSegmentAddress;
+ F.Size = 0;
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ F.Sym = BasicSymbolRef();
+ F.SymFlags = 0;
+ F.NType = MachO::N_SECT;
+ F.NSect = 0;
+ StringRef SegmentName = StringRef();
+ StringRef SectionName = StringRef();
+ for (const SectionRef &Section : MachO->sections()) {
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ SectionName = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ SegmentName = MachO->getSectionFinalSegmentName(
+ Section.getRawDataRefImpl());
+ F.NSect++;
+ if (F.Address >= Section.getAddress() &&
+ F.Address < Section.getAddress() + Section.getSize()) {
+ F.Section = Section;
+ break;
+ }
+ }
+ if (SegmentName == "__TEXT" && SectionName == "__text")
+ F.TypeChar = 't';
+ else if (SegmentName == "__DATA" && SectionName == "__data")
+ F.TypeChar = 'd';
+ else if (SegmentName == "__DATA" && SectionName == "__bss")
+ F.TypeChar = 'b';
+ else
+ F.TypeChar = 's';
+ F.NDesc = 0;
+ F.IndirectName = StringRef();
+ SymbolList.push_back(F);
+ if (FoundFns[f] == lc_main_offset)
+ FOS << "<redacted LC_MAIN>";
+ else
+ FOS << "<redacted function " << f << ">";
+ FOS << '\0';
+ FunctionStartsAdded++;
+ }
+ }
+ if (FunctionStartsAdded) {
+ FOS.flush();
+ const char *Q = FunctionStartsNameBuffer.c_str();
+ for (unsigned K = 0; K < FunctionStartsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+ }
+ }
+
+ CurrentFilename = Obj.getFileName();
+ sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
+}
+
+// checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
+// and if it is and there is a list of architecture flags is specified then
+// check to make sure this Mach-O file is one of those architectures or all
+// architectures was specificed. If not then an error is generated and this
+// routine returns false. Else it returns true.
+static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
+ auto *MachO = dyn_cast<MachOObjectFile>(O);
+
+ if (!MachO || ArchAll || ArchFlags.empty())
+ return true;
+
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ Triple T;
+ const char *McpuDefault, *ArchFlag;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
+ &McpuDefault, &ArchFlag);
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
+ &McpuDefault, &ArchFlag);
+ }
+ const std::string ArchFlagName(ArchFlag);
+ if (none_of(ArchFlags, [&](const std::string &Name) {
+ return Name == ArchFlagName;
+ })) {
+ error("No architecture specified", Filename);
+ return false;
+ }
+ return true;
+}
+
+static void dumpSymbolNamesFromFile(std::string &Filename) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ if (error(BufferOrErr.getError(), Filename))
+ return;
+
+ LLVMContext Context;
+ LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
+ if (!BinaryOrErr) {
+ error(BinaryOrErr.takeError(), Filename);
+ return;
+ }
+ Binary &Bin = *BinaryOrErr.get();
+
+ if (Archive *A = dyn_cast<Archive>(&Bin)) {
+ if (ArchiveMap) {
+ Archive::symbol_iterator I = A->symbol_begin();
+ Archive::symbol_iterator E = A->symbol_end();
+ if (I != E) {
+ outs() << "Archive map\n";
+ for (; I != E; ++I) {
+ Expected<Archive::Child> C = I->getMember();
+ if (!C) {
+ error(C.takeError(), Filename);
+ break;
+ }
+ Expected<StringRef> FileNameOrErr = C->getName();
+ if (!FileNameOrErr) {
+ error(FileNameOrErr.takeError(), Filename);
+ break;
+ }
+ StringRef SymName = I->getName();
+ outs() << SymName << " in " << FileNameOrErr.get() << "\n";
+ }
+ outs() << "\n";
+ }
+ }
+
+ {
+ Error Err = Error::success();
+ for (auto &C : A->children(Err)) {
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
+ if (!ChildOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ error(std::move(E), Filename, C);
+ continue;
+ }
+ if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ WithColor::warning(errs(), ToolName)
+ << "sizes with -print-size for Mach-O files are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ if (!PrintFileName) {
+ outs() << "\n";
+ if (isa<MachOObjectFile>(O)) {
+ outs() << Filename << "(" << O->getFileName() << ")";
+ } else
+ outs() << O->getFileName();
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(*O, false, Filename);
+ }
+ }
+ if (Err)
+ error(std::move(Err), A->getFileName());
+ }
+ return;
+ }
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
+ // If we have a list of architecture flags specified dump only those.
+ if (!ArchAll && !ArchFlags.empty()) {
+ // Look for a slice in the universal binary that matches each ArchFlag.
+ bool ArchFound;
+ for (unsigned i = 0; i < ArchFlags.size(); ++i) {
+ ArchFound = false;
+ for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ if (ArchFlags[i] == I->getArchFlagName()) {
+ ArchFound = true;
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
+ I->getAsObjectFile();
+ std::string ArchiveName;
+ std::string ArchitectureName;
+ ArchiveName.clear();
+ ArchitectureName.clear();
+ if (ObjOrErr) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ if (ArchFlags.size() > 1) {
+ if (PrintFileName)
+ ArchitectureName = I->getArchFlagName();
+ else
+ outs() << "\n" << Obj.getFileName() << " (for architecture "
+ << I->getArchFlagName() << ")"
+ << ":\n";
+ }
+ dumpSymbolNamesFromObject(Obj, false, ArchiveName,
+ ArchitectureName);
+ } else if (auto E = isNotObjectErrorInvalidFileType(
+ ObjOrErr.takeError())) {
+ error(std::move(E), Filename, ArchFlags.size() > 1 ?
+ StringRef(I->getArchFlagName()) : StringRef());
+ continue;
+ } else if (Expected<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ Error Err = Error::success();
+ for (auto &C : A->children(Err)) {
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
+ if (!ChildOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(
+ ChildOrErr.takeError())) {
+ error(std::move(E), Filename, C, ArchFlags.size() > 1 ?
+ StringRef(I->getArchFlagName()) : StringRef());
+ }
+ continue;
+ }
+ if (SymbolicFile *O =
+ dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (PrintFileName) {
+ ArchiveName = A->getFileName();
+ if (ArchFlags.size() > 1)
+ ArchitectureName = I->getArchFlagName();
+ } else {
+ outs() << "\n" << A->getFileName();
+ outs() << "(" << O->getFileName() << ")";
+ if (ArchFlags.size() > 1) {
+ outs() << " (for architecture " << I->getArchFlagName()
+ << ")";
+ }
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(*O, false, ArchiveName,
+ ArchitectureName);
+ }
+ }
+ if (Err)
+ error(std::move(Err), A->getFileName());
+ } else {
+ consumeError(AOrErr.takeError());
+ error(Filename + " for architecture " +
+ StringRef(I->getArchFlagName()) +
+ " is not a Mach-O file or an archive file",
+ "Mach-O universal file");
+ }
+ }
+ }
+ if (!ArchFound) {
+ error(ArchFlags[i],
+ "file: " + Filename + " does not contain architecture");
+ return;
+ }
+ }
+ return;
+ }
+ // No architecture flags were specified so if this contains a slice that
+ // matches the host architecture dump only that.
+ if (!ArchAll) {
+ Triple HostTriple = MachOObjectFile::getHostArch();
+ StringRef HostArchName = HostTriple.getArchName();
+ for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ if (HostArchName == I->getArchFlagName()) {
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ std::string ArchiveName;
+ if (ObjOrErr) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ dumpSymbolNamesFromObject(Obj, false);
+ } else if (auto E = isNotObjectErrorInvalidFileType(
+ ObjOrErr.takeError())) {
+ error(std::move(E), Filename);
+ return;
+ } else if (Expected<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ Error Err = Error::success();
+ for (auto &C : A->children(Err)) {
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
+ if (!ChildOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(
+ ChildOrErr.takeError()))
+ error(std::move(E), Filename, C);
+ continue;
+ }
+ if (SymbolicFile *O =
+ dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (PrintFileName)
+ ArchiveName = A->getFileName();
+ else
+ outs() << "\n" << A->getFileName() << "(" << O->getFileName()
+ << ")"
+ << ":\n";
+ dumpSymbolNamesFromObject(*O, false, ArchiveName);
+ }
+ }
+ if (Err)
+ error(std::move(Err), A->getFileName());
+ } else {
+ consumeError(AOrErr.takeError());
+ error(Filename + " for architecture " +
+ StringRef(I->getArchFlagName()) +
+ " is not a Mach-O file or an archive file",
+ "Mach-O universal file");
+ }
+ return;
+ }
+ }
+ }
+ // Either all architectures have been specified or none have been specified
+ // and this does not contain the host architecture so dump all the slices.
+ bool moreThanOneArch = UB->getNumberOfObjects() > 1;
+ for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
+ std::string ArchiveName;
+ std::string ArchitectureName;
+ ArchiveName.clear();
+ ArchitectureName.clear();
+ if (ObjOrErr) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ if (PrintFileName) {
+ if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
+ ArchitectureName = O.getArchFlagName();
+ } else {
+ if (moreThanOneArch)
+ outs() << "\n";
+ outs() << Obj.getFileName();
+ if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
+ outs() << " (for architecture " << O.getArchFlagName() << ")";
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName);
+ } else if (auto E = isNotObjectErrorInvalidFileType(
+ ObjOrErr.takeError())) {
+ error(std::move(E), Filename, moreThanOneArch ?
+ StringRef(O.getArchFlagName()) : StringRef());
+ continue;
+ } else if (Expected<std::unique_ptr<Archive>> AOrErr =
+ O.getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
+ Error Err = Error::success();
+ for (auto &C : A->children(Err)) {
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
+ if (!ChildOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(
+ ChildOrErr.takeError()))
+ error(std::move(E), Filename, C, moreThanOneArch ?
+ StringRef(ArchitectureName) : StringRef());
+ continue;
+ }
+ if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (PrintFileName) {
+ ArchiveName = A->getFileName();
+ if (isa<MachOObjectFile>(F) && moreThanOneArch)
+ ArchitectureName = O.getArchFlagName();
+ } else {
+ outs() << "\n" << A->getFileName();
+ if (isa<MachOObjectFile>(F)) {
+ outs() << "(" << F->getFileName() << ")";
+ if (moreThanOneArch)
+ outs() << " (for architecture " << O.getArchFlagName()
+ << ")";
+ } else
+ outs() << ":" << F->getFileName();
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(*F, false, ArchiveName, ArchitectureName);
+ }
+ }
+ if (Err)
+ error(std::move(Err), A->getFileName());
+ } else {
+ consumeError(AOrErr.takeError());
+ error(Filename + " for architecture " +
+ StringRef(O.getArchFlagName()) +
+ " is not a Mach-O file or an archive file",
+ "Mach-O universal file");
+ }
+ }
+ return;
+ }
+ if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ WithColor::warning(errs(), ToolName)
+ << "sizes with --print-size for Mach-O files are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ dumpSymbolNamesFromObject(*O, true);
+ }
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+ cl::HideUnrelatedOptions(NMCat);
+ cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
+
+ // llvm-nm only reads binary files.
+ if (error(sys::ChangeStdinToBinary()))
+ return 1;
+
+ // These calls are needed so that we can read bitcode correctly.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+
+ ToolName = argv[0];
+ if (BSDFormat)
+ OutputFormat = bsd;
+ if (POSIXFormat)
+ OutputFormat = posix;
+ if (DarwinFormat)
+ OutputFormat = darwin;
+
+ // The relative order of these is important. If you pass --size-sort it should
+ // only print out the size. However, if you pass -S --size-sort, it should
+ // print out both the size and address.
+ if (SizeSort && !PrintSize)
+ PrintAddress = false;
+ if (OutputFormat == sysv || SizeSort)
+ PrintSize = true;
+ if (InputFilenames.empty())
+ InputFilenames.push_back("a.out");
+ if (InputFilenames.size() > 1)
+ MultipleFiles = true;
+
+ // If both --demangle and --no-demangle are specified then pick the last one.
+ if (NoDemangle.getPosition() > Demangle.getPosition())
+ Demangle = !NoDemangle;
+
+ for (unsigned i = 0; i < ArchFlags.size(); ++i) {
+ if (ArchFlags[i] == "all") {
+ ArchAll = true;
+ } else {
+ if (!MachOObjectFile::isValidArch(ArchFlags[i]))
+ error("Unknown architecture named '" + ArchFlags[i] + "'",
+ "for the --arch option");
+ }
+ }
+
+ if (!SegSect.empty() && SegSect.size() != 2)
+ error("bad number of arguments (must be two arguments)",
+ "for the -s option");
+
+ if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
+ error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
+
+ llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
+
+ if (HadError)
+ return 1;
+}