diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-nm/llvm-nm.cpp')
-rw-r--r-- | contrib/llvm/tools/llvm-nm/llvm-nm.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp new file mode 100644 index 0000000..2baf532 --- /dev/null +++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp @@ -0,0 +1,195 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like traditional Unix "nm", +// that is, it prints out the names of symbols in a bitcode file, +// along with some information about each symbol. +// +// This "nm" does not print symbols' addresses. It supports many of +// the features of GNU "nm", including its different output formats. +// +//===----------------------------------------------------------------------===// + +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Bitcode/Archive.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Signals.h" +#include <algorithm> +#include <cctype> +#include <cerrno> +#include <cstring> +using namespace llvm; + +namespace { + enum OutputFormatTy { bsd, sysv, posix }; + 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"), + clEnumValEnd), cl::init(bsd)); + cl::alias OutputFormat2("f", cl::desc("Alias for --format"), + cl::aliasopt(OutputFormat)); + + cl::list<std::string> + InputFilenames(cl::Positional, cl::desc("<input bitcode files>"), + cl::ZeroOrMore); + + cl::opt<bool> UndefinedOnly("undefined-only", + cl::desc("Show only undefined symbols")); + cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), + cl::aliasopt(UndefinedOnly)); + + cl::opt<bool> DefinedOnly("defined-only", + cl::desc("Show only defined symbols")); + + cl::opt<bool> ExternalOnly("extern-only", + cl::desc("Show only external symbols")); + cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), + cl::aliasopt(ExternalOnly)); + + cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); + cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); + + bool MultipleFiles = false; + + std::string ToolName; +} + +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<Function>(GV) && GV.hasInternalLinkage()) return 't'; + if (isa<Function>(GV)) return 'T'; + if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage()) return 'd'; + if (isa<GlobalVariable>(GV)) return 'D'; + if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) { + const GlobalValue *AliasedGV = GA->getAliasedGlobal(); + if (isa<Function>(AliasedGV)) return 'T'; + if (isa<GlobalVariable>(AliasedGV)) return 'D'; + } + return '?'; +} + +static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { + // Private linkage and available_externally linkage don't exist in symtab. + if (GV.hasPrivateLinkage() || GV.hasLinkerPrivateLinkage() || + GV.hasAvailableExternallyLinkage()) return; + + const std::string SymbolAddrStr = " "; // Not used yet... + char TypeChar = TypeCharForSymbol(GV); + if ((TypeChar != 'U') && UndefinedOnly) + return; + if ((TypeChar == 'U') && DefinedOnly) + return; + if (GV.hasLocalLinkage () && ExternalOnly) + return; + if (OutputFormat == posix) { + outs() << GV.getName () << " " << TypeCharForSymbol(GV) << " " + << SymbolAddrStr << "\n"; + } else if (OutputFormat == bsd) { + outs() << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " " + << GV.getName () << "\n"; + } else if (OutputFormat == sysv) { + std::string PaddedName (GV.getName ()); + while (PaddedName.length () < 20) + PaddedName += " "; + outs() << PaddedName << "|" << SymbolAddrStr << "| " + << TypeCharForSymbol(GV) + << " | | | |\n"; + } +} + +static void DumpSymbolNamesFromModule(Module *M) { + const std::string &Filename = M->getModuleIdentifier (); + if (OutputFormat == posix && MultipleFiles) { + outs() << Filename << ":\n"; + } else if (OutputFormat == bsd && MultipleFiles) { + outs() << "\n" << Filename << ":\n"; + } else if (OutputFormat == sysv) { + outs() << "\n\nSymbols from " << Filename << ":\n\n" + << "Name Value Class Type" + << " Size Line Section\n"; + } + std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); + std::for_each (M->global_begin(), M->global_end(), + DumpSymbolNameForGlobalValue); + std::for_each (M->alias_begin(), M->alias_end(), + DumpSymbolNameForGlobalValue); +} + +static void DumpSymbolNamesFromFile(std::string &Filename) { + LLVMContext &Context = getGlobalContext(); + std::string ErrorMessage; + sys::Path aPath(Filename); + // Note: Currently we do not support reading an archive from stdin. + if (Filename == "-" || aPath.isBitcodeFile()) { + std::auto_ptr<MemoryBuffer> Buffer( + MemoryBuffer::getFileOrSTDIN(Filename, &ErrorMessage)); + Module *Result = 0; + if (Buffer.get()) + Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); + + if (Result) { + DumpSymbolNamesFromModule(Result); + delete Result; + } else + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + + } else if (aPath.isArchive()) { + std::string ErrMsg; + Archive* archive = Archive::OpenAndLoad(sys::Path(Filename), Context, + &ErrorMessage); + if (!archive) + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + std::vector<Module *> Modules; + if (archive->getAllModules(Modules, &ErrorMessage)) { + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + return; + } + MultipleFiles = true; + std::for_each (Modules.begin(), Modules.end(), DumpSymbolNamesFromModule); + } else { + errs() << ToolName << ": " << Filename << ": " + << "unrecognizable file type\n"; + return; + } +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); + + ToolName = argv[0]; + if (BSDFormat) OutputFormat = bsd; + if (POSIXFormat) OutputFormat = posix; + + switch (InputFilenames.size()) { + case 0: InputFilenames.push_back("-"); + case 1: break; + default: MultipleFiles = true; + } + + std::for_each(InputFilenames.begin(), InputFilenames.end(), + DumpSymbolNamesFromFile); + return 0; +} |