aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-nm/llvm-nm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-nm/llvm-nm.cpp')
-rw-r--r--tools/llvm-nm/llvm-nm.cpp517
1 files changed, 272 insertions, 245 deletions
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index 042e284e8369..aa62e6f0209b 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -1,9 +1,8 @@
//===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -47,12 +46,15 @@ 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::init(bsd), cl::cat(NMCat));
cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
cl::aliasopt(OutputFormat));
@@ -60,50 +62,53 @@ 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::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."));
+ "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::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::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::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::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::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::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::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::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);
@@ -111,40 +116,52 @@ 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::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::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::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::desc("Demangle C++ symbol names"));
-cl::alias DemangleC("C", cl::desc("Alias for --demangle"), cl::aliasopt(Demangle),
- 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::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 instead of address"));
+ 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::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::desc("Exclude aliases from output"),
+ cl::cat(NMCat));
-cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map"));
+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);
@@ -153,38 +170,45 @@ 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::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::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);
-// FIXME: This option takes exactly two strings and should be allowed anywhere
-// on the command line. Such that "llvm-nm -s __TEXT __text foo.o" would work.
-// But that does not as the CommandLine Library does not have a way to make
-// this work. For now the "-s __TEXT __text" has to be last on the command
-// line.
-cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
+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"));
+ "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::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"));
+ "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"));
+ "Mach-O only"),
+ cl::cat(NMCat));
cl::opt<bool> DyldInfoOnly("dyldinfo-only",
cl::desc("Show only symbols from the dyldinfo, "
- "Mach-O only"));
+ "Mach-O only"),
+ cl::cat(NMCat));
cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
- cl::desc("Disable LLVM bitcode reader"));
+ cl::desc("Disable LLVM bitcode reader"),
+ cl::cat(NMCat));
cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
@@ -263,6 +287,8 @@ struct NMSymbol {
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
@@ -316,8 +342,7 @@ static char isSymbolList64Bit(SymbolicFile &Obj) {
}
static StringRef CurrentFilename;
-typedef std::vector<NMSymbol> SymbolListT;
-static SymbolListT SymbolList;
+static std::vector<NMSymbol> SymbolList;
static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
@@ -326,9 +351,10 @@ static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
// 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, SymbolListT::iterator I,
+static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
char *SymbolAddrStr, const char *printBlanks,
- const char *printDashes, const char *printFormat) {
+ const char *printDashes,
+ const char *printFormat) {
MachO::mach_header H;
MachO::mach_header_64 H_64;
uint32_t Filetype = MachO::MH_OBJECT;
@@ -340,7 +366,7 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
uint64_t NValue = 0;
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (Obj.isIR()) {
- uint32_t SymFlags = I->Sym.getFlags();
+ uint32_t SymFlags = S.Sym.getFlags();
if (SymFlags & SymbolRef::SF_Global)
NType |= MachO::N_EXT;
if (SymFlags & SymbolRef::SF_Hidden)
@@ -362,7 +388,7 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
if (SymFlags & SymbolRef::SF_Weak)
NDesc |= MachO::N_WEAK_DEF;
} else {
- DataRefImpl SymDRI = I->Sym.getRawDataRefImpl();
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
Filetype = H_64.filetype;
@@ -375,11 +401,11 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
NStrx = STE_64.n_strx;
NValue = STE_64.n_value;
} else {
- NType = I->NType;
- NSect = I->NSect;
- NDesc = I->NDesc;
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
NStrx = 0;
- NValue = I->Address;
+ NValue = S.Address;
}
} else {
H = MachO->MachOObjectFile::getHeader();
@@ -393,42 +419,31 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
NStrx = STE.n_strx;
NValue = STE.n_value;
} else {
- NType = I->NType;
- NSect = I->NSect;
- NDesc = I->NDesc;
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
NStrx = 0;
- NValue = I->Address;
+ NValue = S.Address;
}
}
}
// If we are printing Mach-O symbols in hex do that and return.
if (FormatMachOasHex) {
- char Str[18] = "";
- format(printFormat, NValue).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%02x", NType).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%02x", NSect).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%04x", NDesc).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%08x", NStrx).print(Str, sizeof(Str));
- outs() << Str << ' ';
- outs() << I->Name;
+ 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 ";
- format(printFormat, NValue).print(Str, sizeof(Str));
- outs() << Str << ' ';
+ outs() << format(printFormat, NValue) << ' ';
StringRef IndirectName;
- if (I->Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
- }
- else
- outs() << I->IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
}
outs() << "\n";
return;
@@ -487,9 +502,9 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
break;
}
section_iterator Sec = SectionRef();
- if (I->Sym.getRawDataRefImpl().p) {
+ if (S.Sym.getRawDataRefImpl().p) {
Expected<section_iterator> SecOrErr =
- MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
+ MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
if (!SecOrErr) {
consumeError(SecOrErr.takeError());
outs() << "(?,?) ";
@@ -501,11 +516,12 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
break;
}
} else {
- Sec = I->Section;
+ Sec = S.Section;
}
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
- MachO->getSectionName(Ref, SectionName);
+ if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
+ SectionName = *NameOrErr;
StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
outs() << "(" << SegmentName << "," << SectionName << ") ";
break;
@@ -541,39 +557,36 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << "non-external ";
}
- if (Filetype == MachO::MH_OBJECT &&
- (NDesc & MachO::N_NO_DEAD_STRIP) == MachO::N_NO_DEAD_STRIP)
- outs() << "[no dead strip] ";
-
- if (Filetype == MachO::MH_OBJECT &&
- ((NType & MachO::N_TYPE) != MachO::N_UNDF) &&
- (NDesc & MachO::N_SYMBOL_RESOLVER) == MachO::N_SYMBOL_RESOLVER)
- outs() << "[symbol resolver] ";
-
- if (Filetype == MachO::MH_OBJECT &&
- ((NType & MachO::N_TYPE) != MachO::N_UNDF) &&
- (NDesc & MachO::N_ALT_ENTRY) == MachO::N_ALT_ENTRY)
- outs() << "[alt entry] ";
+ 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() << I->Name << " (for ";
+ outs() << S.Name << " (for ";
StringRef IndirectName;
if (MachO) {
- if (I->Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
- }
- else
- outs() << I->IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
} else
outs() << "?)";
} else
- outs() << I->Name;
+ outs() << S.Name;
if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
(((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
@@ -635,25 +648,24 @@ static const struct DarwinStabName DarwinStabNames[] = {
{MachO::N_ECOMM, "ECOMM"},
{MachO::N_ECOML, "ECOML"},
{MachO::N_LENG, "LENG"},
- {0, nullptr}};
+};
static const char *getDarwinStabString(uint8_t NType) {
- for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
- if (DarwinStabNames[i].NType == NType)
- return DarwinStabNames[i].Name;
- }
+ 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, SymbolListT::iterator I) {
+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 = I->Sym.getRawDataRefImpl();
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
if (MachO->is64Bit()) {
STE_64 = MachO->getSymbol64TableEntry(SymDRI);
NType = STE_64.n_type;
@@ -666,16 +678,11 @@ static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
NDesc = STE.n_desc;
}
- char Str[18] = "";
- format("%02x", NSect).print(Str, sizeof(Str));
- outs() << ' ' << Str << ' ';
- format("%04x", NDesc).print(Str, sizeof(Str));
- outs() << Str << ' ';
+ outs() << format(" %02x %04x ", NSect, NDesc);
if (const char *stabString = getDarwinStabString(NType))
- format("%5.5s", stabString).print(Str, sizeof(Str));
+ outs() << format("%5.5s", stabString);
else
- format(" %02x", NType).print(Str, sizeof(Str));
- outs() << Str;
+ outs() << format(" %02x", NType);
}
static Optional<std::string> demangle(StringRef Name, bool StripUnderscore) {
@@ -780,26 +787,24 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
errs() << "no symbols\n";
}
- for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end();
- I != E; ++I) {
+ for (const NMSymbol &S : SymbolList) {
uint32_t SymFlags;
- std::string Name = I->Name.str();
+ std::string Name = S.Name.str();
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (Demangle) {
- if (Optional<std::string> Opt = demangle(I->Name, MachO))
+ if (Optional<std::string> Opt = demangle(S.Name, MachO))
Name = *Opt;
}
- if (I->Sym.getRawDataRefImpl().p)
- SymFlags = I->Sym.getFlags();
+ if (S.Sym.getRawDataRefImpl().p)
+ SymFlags = S.Sym.getFlags();
else
- SymFlags = I->SymFlags;
+ 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) || (SizeSort && !PrintAddress) ||
- (Weak && NoWeakSymbols))
+ (!Global && ExternalOnly) || (Weak && NoWeakSymbols))
continue;
if (PrintFileName)
writeFileName(outs());
@@ -810,32 +815,30 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
continue;
}
- char SymbolAddrStr[18] = "";
- char SymbolSizeStr[18] = "";
+ char SymbolAddrStr[23], SymbolSizeStr[23];
// If the format is SysV or the symbol isn't defined, then print spaces.
- if (OutputFormat == sysv || !symbolIsDefined(*I)) {
+ if (OutputFormat == sysv || !symbolIsDefined(S)) {
if (OutputFormat == posix) {
- format(printFormat, I->Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, I->Size)
- .print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ format(printFormat, S.Address)
+ .print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
} else {
strcpy(SymbolAddrStr, printBlanks);
strcpy(SymbolSizeStr, printBlanks);
}
}
- // Otherwise, print the symbol address and size.
- if (symbolIsDefined(*I)) {
+ if (symbolIsDefined(S)) {
+ // Otherwise, print the symbol address and size.
if (Obj.isIR())
strcpy(SymbolAddrStr, printDashes);
- else if(MachO && I->TypeChar == 'I')
+ else if (MachO && S.TypeChar == 'I')
strcpy(SymbolAddrStr, printBlanks);
else
- format(printFormat, I->Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ 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
@@ -844,43 +847,36 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
// 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, I, SymbolAddrStr, printBlanks, printDashes,
+ darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
printFormat);
} else if (OutputFormat == posix) {
- outs() << Name << " " << I->TypeChar << " ";
- if (MachO)
- outs() << SymbolAddrStr << " " << "0" /* SymbolSizeStr */ << "\n";
- else
- outs() << SymbolAddrStr << " " << SymbolSizeStr << "\n";
+ 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() << ' ';
- }
- outs() << I->TypeChar;
- if (I->TypeChar == '-' && MachO)
- darwinPrintStab(MachO, I);
+ if (PrintSize)
+ outs() << SymbolSizeStr << ' ';
+ outs() << S.TypeChar;
+ if (S.TypeChar == '-' && MachO)
+ darwinPrintStab(MachO, S);
outs() << " " << Name;
- if (I->TypeChar == 'I' && MachO) {
+ if (S.TypeChar == 'I' && MachO) {
outs() << " (indirect for ";
- if (I->Sym.getRawDataRefImpl().p) {
+ if (S.Sym.getRawDataRefImpl().p) {
StringRef IndirectName;
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
} else
- outs() << I->IndirectName << ")";
+ outs() << S.IndirectName << ")";
}
outs() << "\n";
} else if (OutputFormat == sysv) {
- std::string PaddedName(Name);
- while (PaddedName.length() < 20)
- PaddedName += " ";
- outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar
- << " | |" << SymbolSizeStr << "| |\n";
+ outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
+ << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
+ << SymbolSizeStr << "| |" << S.SectionName << "\n";
}
}
@@ -898,44 +894,35 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
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()) {
- switch (SecI->getType()) {
- case ELF::SHT_PROGBITS:
- case ELF::SHT_DYNAMIC:
- switch (SecI->getFlags()) {
- case (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR):
- return 't';
- case (ELF::SHF_TLS | ELF::SHF_ALLOC | ELF::SHF_WRITE):
- case (ELF::SHF_ALLOC | ELF::SHF_WRITE):
- return 'd';
- case ELF::SHF_ALLOC:
- case (ELF::SHF_ALLOC | ELF::SHF_MERGE):
- case (ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS):
- return 'r';
- }
- break;
- case ELF::SHT_NOBITS:
- return 'b';
- case ELF::SHT_INIT_ARRAY:
- case ELF::SHT_FINI_ARRAY:
+ 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';
- if (SymI->getELFType() == ELF::STT_SECTION) {
- Expected<StringRef> Name = SymI->getName();
- if (!Name) {
- consumeError(Name.takeError());
+ StringRef SecName;
+ if (SecI->getName(SecName))
return '?';
- }
- return StringSwitch<char>(*Name)
- .StartsWith(".debug", 'N')
- .StartsWith(".note", 'n')
- .Default('?');
+ if (SecName.startswith(".debug"))
+ return 'N';
+ if (!(Flags & ELF::SHF_WRITE))
+ return 'n';
}
- return 'n';
+ return '?';
}
static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
@@ -967,10 +954,9 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
section_iterator SecI = *SecIOrErr;
const coff_section *Section = Obj.getCOFFSection(*SecI);
Characteristics = Section->Characteristics;
- StringRef SectionName;
- Obj.getSectionName(Section, SectionName);
- if (SectionName.startswith(".idata"))
- return 'i';
+ if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
+ if (NameOrErr->startswith(".idata"))
+ return 'i';
}
switch (Symb.getSectionNumber()) {
@@ -1030,7 +1016,8 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
return 's';
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
- Obj.getSectionName(Ref, 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")
@@ -1074,8 +1061,40 @@ static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
: elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
}
-static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
+// 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 (isa<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 '?';
+ }
+ elf_section_iterator secT = *SecIOrErr;
+ secT->getName(SecName);
+ }
+ }
+
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;
@@ -1103,10 +1122,13 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
else
Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
- if (Symflags & object::SymbolRef::SF_Global)
- Ret = toupper(Ret);
+ if (!(Symflags & object::SymbolRef::SF_Global))
+ return Ret;
- 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"
@@ -1120,7 +1142,8 @@ static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
for (auto &S : Obj->sections()) {
DataRefImpl Ref = S.getRawDataRefImpl();
StringRef SectionName;
- Obj->getSectionName(Ref, SectionName);
+ if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
+ SectionName = *NameOrErr;
StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
if (SegmentName == SegSect[0] && SectionName == SegSect[1])
return Nsect;
@@ -1155,9 +1178,7 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
error("File format has no dynamic symbol table", Obj.getFileName());
return;
}
- auto DynSymbols = E->getDynamicSymbolIterators();
- Symbols =
- make_range<basic_symbol_iterator>(DynSymbols.begin(), DynSymbols.end());
+ Symbols = E->getDynamicSymbolIterators();
}
std::string NameBuffer;
raw_string_ostream OS(NameBuffer);
@@ -1186,10 +1207,8 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
NMSymbol S = {};
S.Size = 0;
S.Address = 0;
- if (PrintSize) {
- if (isa<ELFObjectFileBase>(&Obj))
- S.Size = ELFSymbolRef(Sym).getSize();
- }
+ if (isa<ELFObjectFileBase>(&Obj))
+ S.Size = ELFSymbolRef(Sym).getSize();
if (PrintAddress && isa<ObjectFile>(Obj)) {
SymbolRef SymRef(Sym);
Expected<uint64_t> AddressOrErr = SymRef.getAddress();
@@ -1199,12 +1218,15 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
}
S.Address = *AddressOrErr;
}
- S.TypeChar = getNMTypeChar(Obj, Sym);
- std::error_code EC = Sym.printName(OS);
- if (EC && MachO)
- OS << "bad string index";
- else
- error(EC);
+ 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);
@@ -1270,11 +1292,12 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
bool found = false;
bool ReExport = false;
if (!DyldInfoOnly) {
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress &&
- SymbolList[J].Name == Entry.name())
+ for (const NMSymbol &S : SymbolList)
+ if (S.Address == Entry.address() + BaseSegmentAddress &&
+ S.Name == Entry.name()) {
found = true;
- }
+ break;
+ }
}
if (!found) {
NMSymbol S = {};
@@ -1445,7 +1468,6 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
B.NType = MachO::N_EXT | MachO::N_UNDF;
B.NSect = 0;
B.NDesc = 0;
- B.NDesc = 0;
MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
B.IndirectName = StringRef();
B.Name = Entry.symbolName();
@@ -1735,8 +1757,9 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
LLVMContext Context;
- Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
- BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context);
+ LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
if (!BinaryOrErr) {
error(BinaryOrErr.takeError(), Filename);
return;
@@ -1770,7 +1793,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
{
Error Err = Error::success();
for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context);
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
error(std::move(E), Filename, C);
@@ -1841,7 +1865,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError())) {
@@ -1912,7 +1936,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError()))
@@ -1946,10 +1970,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
// 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 (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
- E = UB->end_objects();
- I != E; ++I) {
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
std::string ArchiveName;
std::string ArchitectureName;
ArchiveName.clear();
@@ -1958,28 +1980,28 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
ObjectFile &Obj = *ObjOrErr.get();
if (PrintFileName) {
if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- ArchitectureName = I->getArchFlagName();
+ ArchitectureName = O.getArchFlagName();
} else {
if (moreThanOneArch)
outs() << "\n";
outs() << Obj.getFileName();
if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- outs() << " (for architecture " << I->getArchFlagName() << ")";
+ 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(I->getArchFlagName()) : StringRef());
+ StringRef(O.getArchFlagName()) : StringRef());
continue;
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
+ 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(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError()))
@@ -1987,23 +2009,23 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
StringRef(ArchitectureName) : StringRef());
continue;
}
- if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
if (PrintFileName) {
ArchiveName = A->getFileName();
- if (isa<MachOObjectFile>(O) && moreThanOneArch)
- ArchitectureName = I->getArchFlagName();
+ if (isa<MachOObjectFile>(F) && moreThanOneArch)
+ ArchitectureName = O.getArchFlagName();
} else {
outs() << "\n" << A->getFileName();
- if (isa<MachOObjectFile>(O)) {
- outs() << "(" << O->getFileName() << ")";
+ if (isa<MachOObjectFile>(F)) {
+ outs() << "(" << F->getFileName() << ")";
if (moreThanOneArch)
- outs() << " (for architecture " << I->getArchFlagName()
+ outs() << " (for architecture " << O.getArchFlagName()
<< ")";
} else
- outs() << ":" << O->getFileName();
+ outs() << ":" << F->getFileName();
outs() << ":\n";
}
- dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName);
+ dumpSymbolNamesFromObject(*F, false, ArchiveName, ArchitectureName);
}
}
if (Err)
@@ -2011,7 +2033,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
} else {
consumeError(AOrErr.takeError());
error(Filename + " for architecture " +
- StringRef(I->getArchFlagName()) +
+ StringRef(O.getArchFlagName()) +
" is not a Mach-O file or an archive file",
"Mach-O universal file");
}
@@ -2021,7 +2043,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
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";
+ << "sizes with --print-size for Mach-O files are always zero.\n";
MachOPrintSizeWarning = true;
}
if (!checkMachOAndArchFlags(O, Filename))
@@ -2032,6 +2054,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
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.
@@ -2063,13 +2086,17 @@ int main(int argc, char **argv) {
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");
+ "for the --arch option");
}
}
@@ -2078,7 +2105,7 @@ int main(int argc, char **argv) {
"for the -s option");
if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
- error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only");
+ error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);