X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-nm%2Fllvm-nm.cpp;h=8a89dd80dbad543911334922e54035d5ec93e15b;hb=7cba2a973f79861d810a8bf927fd78b352fb712f;hp=a24aae6061a4037e5cbab3c3428fbbf4ee071142;hpb=0f76e648d800d7641b4e6e6decb90949cd680b03;p=oota-llvm.git diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index a24aae6061a..8a89dd80dba 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -16,12 +16,18 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.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/Support/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -31,172 +37,396 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" +#include "llvm/Support/TargetSelect.h" #include #include #include #include +#include #include using namespace llvm; using namespace object; namespace { - enum OutputFormatTy { bsd, sysv, posix }; - cl::opt - OutputFormat("format", - cl::desc("Specify output format"), - cl::values(clEnumVal(bsd, "BSD format"), - clEnumVal(sysv, "System V format"), - clEnumVal(posix, "POSIX.2 format"), - clEnumValEnd), cl::init(bsd)); - cl::alias OutputFormat2("f", cl::desc("Alias for --format"), - cl::aliasopt(OutputFormat)); - - cl::list - InputFilenames(cl::Positional, cl::desc(""), - cl::ZeroOrMore); - - cl::opt UndefinedOnly("undefined-only", - cl::desc("Show only undefined symbols")); - cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), - cl::aliasopt(UndefinedOnly)); - - cl::opt DynamicSyms("dynamic", - cl::desc("Display the dynamic symbols instead " - "of normal symbols.")); - cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"), - cl::aliasopt(DynamicSyms)); - - cl::opt DefinedOnly("defined-only", - cl::desc("Show only defined symbols")); - - cl::opt ExternalOnly("extern-only", - cl::desc("Show only external symbols")); - cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), - cl::aliasopt(ExternalOnly)); - - cl::opt BSDFormat("B", cl::desc("Alias for --format=bsd")); - cl::opt POSIXFormat("P", cl::desc("Alias for --format=posix")); - - cl::opt PrintFileName("print-file-name", +enum OutputFormatTy { bsd, sysv, posix, darwin }; +cl::opt 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"), clEnumValEnd), + cl::init(bsd)); +cl::alias OutputFormat2("f", cl::desc("Alias for --format"), + cl::aliasopt(OutputFormat)); + +cl::list InputFilenames(cl::Positional, cl::desc(""), + cl::ZeroOrMore); + +cl::opt UndefinedOnly("undefined-only", + cl::desc("Show only undefined symbols")); +cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), + cl::aliasopt(UndefinedOnly)); + +cl::opt DynamicSyms("dynamic", + cl::desc("Display the dynamic symbols instead " + "of normal symbols.")); +cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"), + cl::aliasopt(DynamicSyms)); + +cl::opt DefinedOnly("defined-only", + cl::desc("Show only defined symbols")); +cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"), + cl::aliasopt(DefinedOnly)); + +cl::opt ExternalOnly("extern-only", + cl::desc("Show only external symbols")); +cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), + cl::aliasopt(ExternalOnly)); + +cl::opt BSDFormat("B", cl::desc("Alias for --format=bsd")); +cl::opt POSIXFormat("P", cl::desc("Alias for --format=posix")); +cl::opt DarwinFormat("m", cl::desc("Alias for --format=darwin")); + +static cl::list +ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; + +cl::opt PrintFileName( + "print-file-name", cl::desc("Precede each symbol with the object file it came from")); - cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"), - cl::aliasopt(PrintFileName)); - cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"), - cl::aliasopt(PrintFileName)); +cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"), + cl::aliasopt(PrintFileName)); +cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"), + cl::aliasopt(PrintFileName)); - cl::opt DebugSyms("debug-syms", - cl::desc("Show all symbols, even debugger only")); - cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"), - cl::aliasopt(DebugSyms)); +cl::opt DebugSyms("debug-syms", + cl::desc("Show all symbols, even debugger only")); +cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"), + cl::aliasopt(DebugSyms)); - cl::opt NumericSort("numeric-sort", - cl::desc("Sort symbols by address")); - cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"), - cl::aliasopt(NumericSort)); - cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), - cl::aliasopt(NumericSort)); +cl::opt NumericSort("numeric-sort", cl::desc("Sort symbols by address")); +cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"), + cl::aliasopt(NumericSort)); +cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), + cl::aliasopt(NumericSort)); - cl::opt NoSort("no-sort", - cl::desc("Show symbols in order encountered")); - cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), - cl::aliasopt(NoSort)); +cl::opt NoSort("no-sort", cl::desc("Show symbols in order encountered")); +cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort)); - cl::opt PrintSize("print-size", - cl::desc("Show symbol size instead of address")); - cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"), - cl::aliasopt(PrintSize)); +cl::opt ReverseSort("reverse-sort", cl::desc("Sort in reverse order")); +cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"), + cl::aliasopt(ReverseSort)); - cl::opt SizeSort("size-sort", cl::desc("Sort symbols by size")); +cl::opt PrintSize("print-size", + cl::desc("Show symbol size instead of address")); +cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"), + cl::aliasopt(PrintSize)); - cl::opt WithoutAliases("without-aliases", cl::Hidden, - cl::desc("Exclude aliases from output")); +cl::opt SizeSort("size-sort", cl::desc("Sort symbols by size")); - cl::opt ArchiveMap("print-armap", - cl::desc("Print the archive map")); - cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), - cl::aliasopt(ArchiveMap)); - bool PrintAddress = true; +cl::opt WithoutAliases("without-aliases", cl::Hidden, + cl::desc("Exclude aliases from output")); - bool MultipleFiles = false; +cl::opt ArchiveMap("print-armap", cl::desc("Print the archive map")); +cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), + cl::aliasopt(ArchiveMap)); - std::string ToolName; -} +cl::opt JustSymbolName("just-symbol-name", + cl::desc("Print just the symbol's name")); +cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"), + cl::aliasopt(JustSymbolName)); +bool PrintAddress = true; + +bool MultipleFiles = false; + +bool HadError = false; +std::string ToolName; +} -static void error(Twine message, Twine path = Twine()) { - errs() << ToolName << ": " << path << ": " << message << ".\n"; +static void error(Twine Message, Twine Path = Twine()) { + HadError = true; + errs() << ToolName << ": " << Path << ": " << Message << ".\n"; } -static bool error(error_code ec, Twine path = Twine()) { - if (ec) { - error(ec.message(), path); +static bool error(std::error_code EC, Twine Path = Twine()) { + if (EC) { + error(EC.message(), Path); return true; } return false; } namespace { - struct NMSymbol { - uint64_t Address; - uint64_t Size; - char TypeChar; - StringRef Name; - }; +struct NMSymbol { + uint64_t Address; + uint64_t Size; + char TypeChar; + StringRef Name; + DataRefImpl Symb; +}; +} - static bool CompareSymbolAddress(const NMSymbol &a, const NMSymbol &b) { - if (a.Address < b.Address) +static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) { + if (!ReverseSort) { + if (A.Address < B.Address) return true; - else if (a.Address == b.Address && a.Name < b.Name) + else if (A.Address == B.Address && A.Name < B.Name) return true; - else if (a.Address == b.Address && a.Name == b.Name && a.Size < b.Size) + else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) + return true; + else + return false; + } else { + if (A.Address > B.Address) + return true; + else if (A.Address == B.Address && A.Name > B.Name) + return true; + else if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size) return true; else return false; - } +} - static bool CompareSymbolSize(const NMSymbol &a, const NMSymbol &b) { - if (a.Size < b.Size) +static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) { + if (!ReverseSort) { + if (A.Size < B.Size) return true; - else if (a.Size == b.Size && a.Name < b.Name) + else if (A.Size == B.Size && A.Name < B.Name) return true; - else if (a.Size == b.Size && a.Name == b.Name && a.Address < b.Address) + else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) + return true; + else + return false; + } else { + if (A.Size > B.Size) + return true; + else if (A.Size == B.Size && A.Name > B.Name) + return true; + else if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address) return true; else return false; } +} - static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) { - if (a.Name < b.Name) +static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) { + if (!ReverseSort) { + if (A.Name < B.Name) return true; - else if (a.Name == b.Name && a.Size < b.Size) + else if (A.Name == B.Name && A.Size < B.Size) return true; - else if (a.Name == b.Name && a.Size == b.Size && a.Address < b.Address) + else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) + return true; + else + return false; + } else { + if (A.Name > B.Name) + return true; + else if (A.Name == B.Name && A.Size > B.Size) + return true; + else if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address) return true; else return false; } +} - StringRef CurrentFilename; - typedef std::vector SymbolListT; - SymbolListT SymbolList; +static char isSymbolList64Bit(SymbolicFile *Obj) { + if (isa(Obj)) + return false; + else if (isa(Obj)) + return false; + else if (MachOObjectFile *MachO = dyn_cast(Obj)) + return MachO->is64Bit(); + else if (isa(Obj)) + return false; + else if (isa(Obj)) + return true; + else if (isa(Obj)) + return false; + else if (isa(Obj)) + return true; + else + return false; } -static void SortAndPrintSymbolList() { +static StringRef CurrentFilename; +typedef std::vector SymbolListT; +static SymbolListT SymbolList; + +// darwinPrintSymbol() is used to print a symbol from a Mach-O file when the +// the OutputFormat is darwin. It produces the same output as darwin's nm(1) -m +// output. +static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, + char *SymbolAddrStr, const char *printBlanks) { + MachO::mach_header H; + MachO::mach_header_64 H_64; + uint32_t Filetype, Flags; + MachO::nlist_64 STE_64; + MachO::nlist STE; + uint8_t NType; + uint16_t NDesc; + uint64_t NValue; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + Filetype = H_64.filetype; + Flags = H_64.flags; + STE_64 = MachO->getSymbol64TableEntry(I->Symb); + NType = STE_64.n_type; + NDesc = STE_64.n_desc; + NValue = STE_64.n_value; + } else { + H = MachO->MachOObjectFile::getHeader(); + Filetype = H.filetype; + Flags = H.flags; + STE = MachO->getSymbolTableEntry(I->Symb); + NType = STE.n_type; + NDesc = STE.n_desc; + NValue = STE.n_value; + } + + if (PrintAddress) { + if ((NType & MachO::N_TYPE) == MachO::N_INDR) + strcpy(SymbolAddrStr, printBlanks); + 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_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: { + section_iterator Sec = MachO->section_end(); + MachO->getSymbolSection(I->Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + MachO->getSectionName(Ref, SectionName); + 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 && + (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 ((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 "; + StringRef IndirectName; + if (MachO->getIndirectName(I->Symb, IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } else + outs() << I->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->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName)) + outs() << " (from bad library ordinal " << LibraryOrdinal << ")"; + else + outs() << " (from " << LibraryName << ")"; + } + } + } + + outs() << "\n"; +} + +static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) { if (!NoSort) { if (NumericSort) - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolAddress); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolAddress); else if (SizeSort) - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolSize); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolSize); else - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolName); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolName); } - if (OutputFormat == posix && MultipleFiles) { + if (OutputFormat == posix && MultipleFiles && printName) { outs() << '\n' << CurrentFilename << ":\n"; - } else if (OutputFormat == bsd && MultipleFiles) { + } else if (OutputFormat == bsd && MultipleFiles && printName) { outs() << "\n" << CurrentFilename << ":\n"; } else if (OutputFormat == sysv) { outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n" @@ -204,47 +434,65 @@ static void SortAndPrintSymbolList() { << " Size Line Section\n"; } - for (SymbolListT::iterator i = SymbolList.begin(), - e = SymbolList.end(); i != e; ++i) { - if ((i->TypeChar != 'U') && UndefinedOnly) + const char *printBlanks, *printFormat; + if (isSymbolList64Bit(Obj)) { + printBlanks = " "; + printFormat = "%016" PRIx64; + } else { + printBlanks = " "; + printFormat = "%08" PRIx64; + } + + for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end(); + I != E; ++I) { + if ((I->TypeChar != 'U') && UndefinedOnly) continue; - if ((i->TypeChar == 'U') && DefinedOnly) + if ((I->TypeChar == 'U') && DefinedOnly) continue; - if (SizeSort && !PrintAddress && i->Size == UnknownAddressOrSize) + if (SizeSort && !PrintAddress && I->Size == UnknownAddressOrSize) continue; + if (JustSymbolName) { + outs() << I->Name << "\n"; + continue; + } - char SymbolAddrStr[10] = ""; - char SymbolSizeStr[10] = ""; + char SymbolAddrStr[18] = ""; + char SymbolSizeStr[18] = ""; - if (OutputFormat == sysv || i->Address == object::UnknownAddressOrSize) - strcpy(SymbolAddrStr, " "); + if (OutputFormat == sysv || I->Address == UnknownAddressOrSize) + strcpy(SymbolAddrStr, printBlanks); if (OutputFormat == sysv) - strcpy(SymbolSizeStr, " "); - - if (i->Address != object::UnknownAddressOrSize) - format("%08" PRIx64, i->Address).print(SymbolAddrStr, - sizeof(SymbolAddrStr)); - if (i->Size != object::UnknownAddressOrSize) - format("%08" PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); - - if (OutputFormat == posix) { - outs() << i->Name << " " << i->TypeChar << " " - << SymbolAddrStr << SymbolSizeStr << "\n"; - } else if (OutputFormat == bsd) { + strcpy(SymbolSizeStr, printBlanks); + + if (I->Address != UnknownAddressOrSize) + format(printFormat, I->Address) + .print(SymbolAddrStr, sizeof(SymbolAddrStr)); + if (I->Size != UnknownAddressOrSize) + format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); + + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // nm(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // fall back to OutputFormat bsd (see below). + MachOObjectFile *MachO = dyn_cast(Obj); + if (OutputFormat == darwin && MachO) { + darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks); + } else if (OutputFormat == posix) { + outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr + << SymbolSizeStr << "\n"; + } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { if (PrintAddress) outs() << SymbolAddrStr << ' '; if (PrintSize) { outs() << SymbolSizeStr; - if (i->Size != object::UnknownAddressOrSize) + if (I->Size != UnknownAddressOrSize) outs() << ' '; } - outs() << i->TypeChar << " " << i->Name << "\n"; + outs() << I->TypeChar << " " << I->Name << "\n"; } else if (OutputFormat == sysv) { - std::string PaddedName (i->Name); - while (PaddedName.length () < 20) + std::string PaddedName(I->Name); + while (PaddedName.length() < 20) PaddedName += " "; - outs() << PaddedName << "|" << SymbolAddrStr << "| " - << i->TypeChar + outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar << " | |" << SymbolSizeStr << "| |\n"; } } @@ -252,168 +500,499 @@ static void SortAndPrintSymbolList() { SymbolList.clear(); } -static char TypeCharForSymbol(GlobalValue &GV) { - if (GV.isDeclaration()) return 'U'; - if (GV.hasLinkOnceLinkage()) return 'C'; - if (GV.hasCommonLinkage()) return 'C'; - if (GV.hasWeakLinkage()) return 'W'; - if (isa(GV) && GV.hasInternalLinkage()) return 't'; - if (isa(GV)) return 'T'; - if (isa(GV) && GV.hasInternalLinkage()) return 'd'; - if (isa(GV)) return 'D'; - if (const GlobalAlias *GA = dyn_cast(&GV)) { - const GlobalValue *AliasedGV = GA->getAliasedGlobal(); - if (isa(AliasedGV)) return 'T'; - if (isa(AliasedGV)) return 'D'; +template +static char getSymbolNMTypeChar(ELFObjectFile &Obj, + basic_symbol_iterator I) { + typedef typename ELFObjectFile::Elf_Sym Elf_Sym; + typedef typename ELFObjectFile::Elf_Shdr Elf_Shdr; + + // OK, this is ELF + symbol_iterator SymI(I); + + DataRefImpl Symb = I->getRawDataRefImpl(); + const Elf_Sym *ESym = Obj.getSymbol(Symb); + const ELFFile &EF = *Obj.getELFFile(); + const Elf_Shdr *ESec = EF.getSection(ESym); + + if (ESec) { + switch (ESec->sh_type) { + case ELF::SHT_PROGBITS: + case ELF::SHT_DYNAMIC: + switch (ESec->sh_flags) { + 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'; + } + } + + if (ESym->getType() == ELF::STT_SECTION) { + StringRef Name; + if (error(SymI->getName(Name))) + return '?'; + return StringSwitch(Name) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n') + .Default('?'); } - return '?'; + + return '?'; } -static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { - // Private linkage and available_externally linkage don't exist in symtab. - if (GV.hasPrivateLinkage() || - GV.hasLinkerPrivateLinkage() || - GV.hasLinkerPrivateWeakLinkage() || - GV.hasAvailableExternallyLinkage()) - return; - char TypeChar = TypeCharForSymbol(GV); - if (GV.hasLocalLinkage () && ExternalOnly) - return; +static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { + const coff_symbol *Symb = Obj.getCOFFSymbol(*I); + // OK, this is COFF. + symbol_iterator SymI(I); - NMSymbol s; - s.Address = object::UnknownAddressOrSize; - s.Size = object::UnknownAddressOrSize; - s.TypeChar = TypeChar; - s.Name = GV.getName(); - SymbolList.push_back(s); + StringRef Name; + if (error(SymI->getName(Name))) + return '?'; + + char Ret = StringSwitch(Name) + .StartsWith(".debug", 'N') + .StartsWith(".sxdata", 'N') + .Default('?'); + + if (Ret != '?') + return Ret; + + uint32_t Characteristics = 0; + if (!COFF::isReservedSectionNumber(Symb->SectionNumber)) { + section_iterator SecI = Obj.section_end(); + if (error(SymI->getSection(SecI))) + return '?'; + const coff_section *Section = Obj.getCOFFSection(*SecI); + Characteristics = Section->Characteristics; + } + + switch (Symb->SectionNumber) { + case COFF::IMAGE_SYM_DEBUG: + return 'n'; + default: + // Check section type. + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + return 't'; + else if (Characteristics & COFF::IMAGE_SCN_MEM_READ && + ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + return 'r'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + return 'd'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + return 'b'; + else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) + return 'i'; + + // Check for section symbol. + else if (Symb->isSectionDefinition()) + return 's'; + } + + return '?'; +} + +static uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) { + if (Obj.is64Bit()) { + MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb); + return STE.n_type; + } + MachO::nlist STE = Obj.getSymbolTableEntry(Symb); + return STE.n_type; } -static void DumpSymbolNamesFromModule(Module *M) { - CurrentFilename = M->getModuleIdentifier(); - std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); - std::for_each (M->global_begin(), M->global_end(), - DumpSymbolNameForGlobalValue); - if (!WithoutAliases) - std::for_each (M->alias_begin(), M->alias_end(), - DumpSymbolNameForGlobalValue); +static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { + DataRefImpl Symb = I->getRawDataRefImpl(); + uint8_t NType = getNType(Obj, Symb); - SortAndPrintSymbolList(); + switch (NType & MachO::N_TYPE) { + case MachO::N_ABS: + return 's'; + case MachO::N_INDR: + return 'i'; + case MachO::N_SECT: { + section_iterator Sec = Obj.section_end(); + Obj.getSymbolSection(Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + Obj.getSectionName(Ref, SectionName); + StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); + if (SegmentName == "__TEXT" && SectionName == "__text") + return 't'; + else if (SegmentName == "__DATA" && SectionName == "__data") + return 'd'; + else if (SegmentName == "__DATA" && SectionName == "__bss") + return 'b'; + else + return 's'; + } + } + + return '?'; +} + +static char getSymbolNMTypeChar(const GlobalValue &GV) { + if (GV.getType()->getElementType()->isFunctionTy()) + return 't'; + // 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. + return 'd'; } -static void DumpSymbolNamesFromObject(ObjectFile *obj) { - error_code ec; - symbol_iterator ibegin = obj->begin_symbols(); - symbol_iterator iend = obj->end_symbols(); +static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { + const GlobalValue *GV = Obj.getSymbolGV(I->getRawDataRefImpl()); + if (!GV) + return 't'; + return getSymbolNMTypeChar(*GV); +} + +template +static bool isObject(ELFObjectFile &Obj, symbol_iterator I) { + typedef typename ELFObjectFile::Elf_Sym Elf_Sym; + + DataRefImpl Symb = I->getRawDataRefImpl(); + const Elf_Sym *ESym = Obj.getSymbol(Symb); + + return ESym->getType() == ELF::STT_OBJECT; +} + +static bool isObject(SymbolicFile *Obj, basic_symbol_iterator I) { + if (ELF32LEObjectFile *ELF = dyn_cast(Obj)) + return isObject(*ELF, I); + if (ELF64LEObjectFile *ELF = dyn_cast(Obj)) + return isObject(*ELF, I); + if (ELF32BEObjectFile *ELF = dyn_cast(Obj)) + return isObject(*ELF, I); + if (ELF64BEObjectFile *ELF = dyn_cast(Obj)) + return isObject(*ELF, I); + return false; +} + +static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) { + uint32_t Symflags = I->getFlags(); + if ((Symflags & object::SymbolRef::SF_Weak) && !isa(Obj)) { + char Ret = isObject(Obj, I) ? 'v' : 'w'; + if (!(Symflags & object::SymbolRef::SF_Undefined)) + Ret = toupper(Ret); + return 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(Obj)) + Ret = getSymbolNMTypeChar(*IR, I); + else if (COFFObjectFile *COFF = dyn_cast(Obj)) + Ret = getSymbolNMTypeChar(*COFF, I); + else if (MachOObjectFile *MachO = dyn_cast(Obj)) + Ret = getSymbolNMTypeChar(*MachO, I); + else if (ELF32LEObjectFile *ELF = dyn_cast(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else if (ELF64LEObjectFile *ELF = dyn_cast(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else if (ELF32BEObjectFile *ELF = dyn_cast(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else + Ret = getSymbolNMTypeChar(*cast(Obj), I); + + if (Symflags & object::SymbolRef::SF_Global) + Ret = toupper(Ret); + + return Ret; +} + +static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) { + basic_symbol_iterator IBegin = Obj->symbol_begin(); + basic_symbol_iterator IEnd = Obj->symbol_end(); if (DynamicSyms) { - ibegin = obj->begin_dynamic_symbols(); - iend = obj->end_dynamic_symbols(); + if (!Obj->isELF()) { + error("File format has no dynamic symbol table", Obj->getFileName()); + return; + } + std::pair IDyn = + getELFDynamicSymbolIterators(Obj); + IBegin = IDyn.first; + IEnd = IDyn.second; } - for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) { - if (error(ec)) break; - uint32_t symflags; - if (error(i->getFlags(symflags))) break; - if (!DebugSyms && (symflags & SymbolRef::SF_FormatSpecific)) + std::string NameBuffer; + raw_string_ostream OS(NameBuffer); + for (basic_symbol_iterator I = IBegin; I != IEnd; ++I) { + uint32_t SymFlags = I->getFlags(); + if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) continue; - NMSymbol s; - s.Size = object::UnknownAddressOrSize; - s.Address = object::UnknownAddressOrSize; - if (PrintSize || SizeSort) { - if (error(i->getSize(s.Size))) break; + if (WithoutAliases) { + if (IRObjectFile *IR = dyn_cast(Obj)) { + const GlobalValue *GV = IR->getSymbolGV(I->getRawDataRefImpl()); + if (GV && isa(GV)) + continue; + } } - if (PrintAddress) - if (error(i->getAddress(s.Address))) break; - if (error(i->getNMTypeChar(s.TypeChar))) break; - if (error(i->getName(s.Name))) break; - SymbolList.push_back(s); + NMSymbol S; + S.Size = UnknownAddressOrSize; + S.Address = UnknownAddressOrSize; + if ((PrintSize || SizeSort) && isa(Obj)) { + symbol_iterator SymI = I; + if (error(SymI->getSize(S.Size))) + break; + } + if (PrintAddress && isa(Obj)) + if (error(symbol_iterator(I)->getAddress(S.Address))) + break; + S.TypeChar = getNMTypeChar(Obj, I); + if (error(I->printName(OS))) + break; + OS << '\0'; + S.Symb = I->getRawDataRefImpl(); + SymbolList.push_back(S); + } + + OS.flush(); + const char *P = NameBuffer.c_str(); + for (unsigned I = 0; I < SymbolList.size(); ++I) { + SymbolList[I].Name = P; + P += strlen(P) + 1; } - CurrentFilename = obj->getFileName(); - SortAndPrintSymbolList(); + CurrentFilename = Obj->getFileName(); + sortAndPrintSymbolList(Obj, printName); } -static void DumpSymbolNamesFromFile(std::string &Filename) { - if (Filename != "-" && !sys::fs::exists(Filename)) { - errs() << ToolName << ": '" << Filename << "': " << "No such file\n"; - return; +// 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) { + if (isa(O) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast(O); + bool ArchFound = false; + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + } + unsigned i; + for (i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == T.getArchName()) + ArchFound = true; + break; + } + if (!ArchFound) { + error(ArchFlags[i], + "file: " + Filename + " does not contain architecture"); + return false; + } } + return true; +} - OwningPtr Buffer; - if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename)) +static void dumpSymbolNamesFromFile(std::string &Filename) { + ErrorOr> BufferOrErr = + MemoryBuffer::getFileOrSTDIN(Filename); + if (error(BufferOrErr.getError(), Filename)) return; - - sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); + std::unique_ptr Buffer = std::move(BufferOrErr.get()); LLVMContext &Context = getGlobalContext(); - std::string ErrorMessage; - if (magic == sys::fs::file_magic::bitcode) { - Module *Result = 0; - Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - if (Result) { - DumpSymbolNamesFromModule(Result); - delete Result; - } else { - error(ErrorMessage, Filename); - return; - } - } else if (magic == sys::fs::file_magic::archive) { - OwningPtr arch; - if (error(object::createBinary(Buffer.take(), arch), Filename)) - return; + ErrorOr BinaryOrErr = createBinary(Buffer, &Context); + if (error(BinaryOrErr.getError(), Filename)) + return; + Buffer.release(); + std::unique_ptr Bin(BinaryOrErr.get()); - if (object::Archive *a = dyn_cast(arch.get())) { - if (ArchiveMap) { - outs() << "Archive map" << "\n"; - for (object::Archive::symbol_iterator i = a->begin_symbols(), - e = a->end_symbols(); i != e; ++i) { - object::Archive::child_iterator c; - StringRef symname; - StringRef filename; - if (error(i->getMember(c))) - return; - if (error(i->getName(symname))) - return; - if (error(c->getName(filename))) - return; - outs() << symname << " in " << filename << "\n"; + if (Archive *A = dyn_cast(Bin.get())) { + 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) { + ErrorOr C = I->getMember(); + if (error(C.getError())) + return; + ErrorOr FileNameOrErr = C.get()->getName(); + if (error(FileNameOrErr.getError())) + return; + StringRef SymName = I->getName(); + outs() << SymName << " in " << FileNameOrErr.get() << "\n"; } outs() << "\n"; } + } - for (object::Archive::child_iterator i = a->begin_children(), - e = a->end_children(); i != e; ++i) { - OwningPtr child; - if (i->getAsBinary(child)) { - // Try opening it as a bitcode file. - OwningPtr buff; - if (error(i->getMemoryBuffer(buff))) - return; - Module *Result = 0; - if (buff) - Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage); - - if (Result) { - DumpSymbolNamesFromModule(Result); - delete Result; + for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); + I != E; ++I) { + ErrorOr> ChildOrErr = I->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + outs() << "\n"; + if (isa(O)) { + outs() << Filename << "(" << O->getFileName() << ")"; + } else + outs() << O->getFileName(); + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + return; + } + if (MachOUniversalBinary *UB = dyn_cast(Bin.get())) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // 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->getArchTypeName()) { + ArchFound = true; + ErrorOr> ObjOrErr = + I->getAsObjectFile(); + std::unique_ptr A; + if (ObjOrErr) { + std::unique_ptr Obj = std::move(ObjOrErr.get()); + if (ArchFlags.size() > 1) { + outs() << "\n" << Obj->getFileName() << " (for architecture " + << I->getArchTypeName() << ")" + << ":\n"; + } + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = + dyn_cast(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName(); + outs() << "(" << O->getFileName() << ")"; + if (ArchFlags.size() > 1) { + outs() << " (for architecture " << I->getArchTypeName() + << ")"; + } + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + } } - continue; } - if (object::ObjectFile *o = dyn_cast(child.get())) { - outs() << o->getFileName() << ":\n"; - DumpSymbolNamesFromObject(o); + 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) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchTypeName()) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::unique_ptr A; + if (ObjOrErr) { + std::unique_ptr Obj = std::move(ObjOrErr.get()); + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = + dyn_cast(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName() << "(" << O->getFileName() + << ")" + << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + } + return; } } } - } else if (magic.is_object()) { - OwningPtr obj; - if (error(object::createBinary(Buffer.take(), obj), 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) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::unique_ptr A; + if (ObjOrErr) { + std::unique_ptr Obj = std::move(ObjOrErr.get()); + if (moreThanOneArch) + outs() << "\n"; + outs() << Obj->getFileName(); + if (isa(Obj.get()) && moreThanOneArch) + outs() << " (for architecture " << I->getArchTypeName() << ")"; + outs() << ":\n"; + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { + for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName(); + if (isa(O)) { + outs() << "(" << O->getFileName() << ")"; + if (moreThanOneArch) + outs() << " (for architecture " << I->getArchTypeName() << ")"; + } else + outs() << ":" << O->getFileName(); + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + } + } + return; + } + if (SymbolicFile *O = dyn_cast(Bin.get())) { + if (!checkMachOAndArchFlags(O, Filename)) return; - if (object::ObjectFile *o = dyn_cast(obj.get())) - DumpSymbolNamesFromObject(o); - } else { - errs() << ToolName << ": " << Filename << ": " - << "unrecognizable file type\n"; + dumpSymbolNamesFromObject(O, true); return; } + error("unrecognizable file type", Filename); + return; } int main(int argc, char **argv) { @@ -421,30 +1000,58 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); // llvm-nm only reads binary files. - if (error(sys::Program::ChangeStdinToBinary())) + if (error(sys::ChangeStdinToBinary())) return 1; + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + ToolName = argv[0]; - if (BSDFormat) OutputFormat = bsd; - if (POSIXFormat) OutputFormat = posix; + 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 (SizeSort && !PrintSize) + PrintAddress = false; + if (OutputFormat == sysv || SizeSort) + PrintSize = true; switch (InputFilenames.size()) { - case 0: InputFilenames.push_back("-"); - case 1: break; - default: MultipleFiles = true; + case 0: + InputFilenames.push_back("a.out"); + case 1: + break; + default: + MultipleFiles = true; + } + + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == "all") { + ArchAll = true; + } else { + Triple T = MachOObjectFile::getArch(ArchFlags[i]); + if (T.getArch() == Triple::UnknownArch) + error("Unknown architecture named '" + ArchFlags[i] + "'", + "for the -arch option"); + } } std::for_each(InputFilenames.begin(), InputFilenames.end(), - DumpSymbolNamesFromFile); + dumpSymbolNamesFromFile); + + if (HadError) + return 1; + return 0; }