1 //===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This program is a utility that works like traditional Unix "nm", 11 // that is, it prints out the names of symbols in a bitcode file, 12 // along with some information about each symbol. 13 // 14 // This "nm" does not print symbols' addresses. It supports many of 15 // the features of GNU "nm", including its different output formats. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "llvm/LLVMContext.h" 20 #include "llvm/Module.h" 21 #include "llvm/Bitcode/ReaderWriter.h" 22 #include "llvm/Bitcode/Archive.h" 23 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/ManagedStatic.h" 25 #include "llvm/Support/MemoryBuffer.h" 26 #include "llvm/Support/PrettyStackTrace.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include "llvm/System/Signals.h" 29 #include <algorithm> 30 #include <cctype> 31 #include <cerrno> 32 #include <cstring> 33 using namespace llvm; 34 35 namespace { 36 enum OutputFormatTy { bsd, sysv, posix }; 37 cl::opt<OutputFormatTy> 38 OutputFormat("format", 39 cl::desc("Specify output format"), 40 cl::values(clEnumVal(bsd, "BSD format"), 41 clEnumVal(sysv, "System V format"), 42 clEnumVal(posix, "POSIX.2 format"), 43 clEnumValEnd), cl::init(bsd)); 44 cl::alias OutputFormat2("f", cl::desc("Alias for --format"), 45 cl::aliasopt(OutputFormat)); 46 47 cl::list<std::string> 48 InputFilenames(cl::Positional, cl::desc("<input bitcode files>"), 49 cl::ZeroOrMore); 50 51 cl::opt<bool> UndefinedOnly("undefined-only", 52 cl::desc("Show only undefined symbols")); 53 cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), 54 cl::aliasopt(UndefinedOnly)); 55 56 cl::opt<bool> DefinedOnly("defined-only", 57 cl::desc("Show only defined symbols")); 58 59 cl::opt<bool> ExternalOnly("extern-only", 60 cl::desc("Show only external symbols")); 61 cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), 62 cl::aliasopt(ExternalOnly)); 63 64 cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); 65 cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); 66 67 bool MultipleFiles = false; 68 69 std::string ToolName; 70 } 71 72 static char TypeCharForSymbol(GlobalValue &GV) { 73 if (GV.isDeclaration()) return 'U'; 74 if (GV.hasLinkOnceLinkage()) return 'C'; 75 if (GV.hasCommonLinkage()) return 'C'; 76 if (GV.hasWeakLinkage()) return 'W'; 77 if (isa<Function>(GV) && GV.hasInternalLinkage()) return 't'; 78 if (isa<Function>(GV)) return 'T'; 79 if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage()) return 'd'; 80 if (isa<GlobalVariable>(GV)) return 'D'; 81 if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) { 82 const GlobalValue *AliasedGV = GA->getAliasedGlobal(); 83 if (isa<Function>(AliasedGV)) return 'T'; 84 if (isa<GlobalVariable>(AliasedGV)) return 'D'; 85 } 86 return '?'; 87 } 88 89 static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { 90 // Private linkage and available_externally linkage don't exist in symtab. 91 if (GV.hasPrivateLinkage() || GV.hasLinkerPrivateLinkage() || 92 GV.hasAvailableExternallyLinkage()) return; 93 94 const std::string SymbolAddrStr = " "; // Not used yet... 95 char TypeChar = TypeCharForSymbol(GV); 96 if ((TypeChar != 'U') && UndefinedOnly) 97 return; 98 if ((TypeChar == 'U') && DefinedOnly) 99 return; 100 if (GV.hasLocalLinkage () && ExternalOnly) 101 return; 102 if (OutputFormat == posix) { 103 outs() << GV.getName () << " " << TypeCharForSymbol(GV) << " " 104 << SymbolAddrStr << "\n"; 105 } else if (OutputFormat == bsd) { 106 outs() << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " " 107 << GV.getName () << "\n"; 108 } else if (OutputFormat == sysv) { 109 std::string PaddedName (GV.getName ()); 110 while (PaddedName.length () < 20) 111 PaddedName += " "; 112 outs() << PaddedName << "|" << SymbolAddrStr << "| " 113 << TypeCharForSymbol(GV) 114 << " | | | |\n"; 115 } 116 } 117 118 static void DumpSymbolNamesFromModule(Module *M) { 119 const std::string &Filename = M->getModuleIdentifier (); 120 if (OutputFormat == posix && MultipleFiles) { 121 outs() << Filename << ":\n"; 122 } else if (OutputFormat == bsd && MultipleFiles) { 123 outs() << "\n" << Filename << ":\n"; 124 } else if (OutputFormat == sysv) { 125 outs() << "\n\nSymbols from " << Filename << ":\n\n" 126 << "Name Value Class Type" 127 << " Size Line Section\n"; 128 } 129 std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); 130 std::for_each (M->global_begin(), M->global_end(), 131 DumpSymbolNameForGlobalValue); 132 std::for_each (M->alias_begin(), M->alias_end(), 133 DumpSymbolNameForGlobalValue); 134 } 135 136 static void DumpSymbolNamesFromFile(std::string &Filename) { 137 LLVMContext &Context = getGlobalContext(); 138 std::string ErrorMessage; 139 sys::Path aPath(Filename); 140 // Note: Currently we do not support reading an archive from stdin. 141 if (Filename == "-" || aPath.isBitcodeFile()) { 142 std::auto_ptr<MemoryBuffer> Buffer( 143 MemoryBuffer::getFileOrSTDIN(Filename, &ErrorMessage)); 144 Module *Result = 0; 145 if (Buffer.get()) 146 Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); 147 148 if (Result) 149 DumpSymbolNamesFromModule(Result); 150 else { 151 errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; 152 return; 153 } 154 155 } else if (aPath.isArchive()) { 156 std::string ErrMsg; 157 Archive* archive = Archive::OpenAndLoad(sys::Path(Filename), Context, 158 &ErrorMessage); 159 if (!archive) 160 errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; 161 std::vector<Module *> Modules; 162 if (archive->getAllModules(Modules, &ErrorMessage)) { 163 errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; 164 return; 165 } 166 MultipleFiles = true; 167 std::for_each (Modules.begin(), Modules.end(), DumpSymbolNamesFromModule); 168 } else { 169 errs() << ToolName << ": " << Filename << ": " 170 << "unrecognizable file type\n"; 171 return; 172 } 173 } 174 175 int main(int argc, char **argv) { 176 // Print a stack trace if we signal out. 177 sys::PrintStackTraceOnErrorSignal(); 178 PrettyStackTraceProgram X(argc, argv); 179 180 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 181 cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); 182 183 ToolName = argv[0]; 184 if (BSDFormat) OutputFormat = bsd; 185 if (POSIXFormat) OutputFormat = posix; 186 187 switch (InputFilenames.size()) { 188 case 0: InputFilenames.push_back("-"); 189 case 1: break; 190 default: MultipleFiles = true; 191 } 192 193 std::for_each(InputFilenames.begin(), InputFilenames.end(), 194 DumpSymbolNamesFromFile); 195 return 0; 196 } 197