Home | History | Annotate | Download | only in llvm-nm
      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/Object/Archive.h"
     24 #include "llvm/Object/ObjectFile.h"
     25 #include "llvm/Support/CommandLine.h"
     26 #include "llvm/Support/FileSystem.h"
     27 #include "llvm/Support/ManagedStatic.h"
     28 #include "llvm/Support/MemoryBuffer.h"
     29 #include "llvm/Support/PrettyStackTrace.h"
     30 #include "llvm/Support/raw_ostream.h"
     31 #include "llvm/Support/Signals.h"
     32 #include "llvm/Support/Format.h"
     33 #include "llvm/Support/system_error.h"
     34 #include <algorithm>
     35 #include <cctype>
     36 #include <cerrno>
     37 #include <cstring>
     38 #include <vector>
     39 using namespace llvm;
     40 using namespace object;
     41 
     42 namespace {
     43   enum OutputFormatTy { bsd, sysv, posix };
     44   cl::opt<OutputFormatTy>
     45   OutputFormat("format",
     46        cl::desc("Specify output format"),
     47          cl::values(clEnumVal(bsd,   "BSD format"),
     48                     clEnumVal(sysv,  "System V format"),
     49                     clEnumVal(posix, "POSIX.2 format"),
     50                     clEnumValEnd), cl::init(bsd));
     51   cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
     52                           cl::aliasopt(OutputFormat));
     53 
     54   cl::list<std::string>
     55   InputFilenames(cl::Positional, cl::desc("<input bitcode files>"),
     56                  cl::ZeroOrMore);
     57 
     58   cl::opt<bool> UndefinedOnly("undefined-only",
     59                               cl::desc("Show only undefined symbols"));
     60   cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
     61                            cl::aliasopt(UndefinedOnly));
     62 
     63   cl::opt<bool> DefinedOnly("defined-only",
     64                             cl::desc("Show only defined symbols"));
     65 
     66   cl::opt<bool> ExternalOnly("extern-only",
     67                              cl::desc("Show only external symbols"));
     68   cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
     69                           cl::aliasopt(ExternalOnly));
     70 
     71   cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"));
     72   cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"));
     73 
     74   cl::opt<bool> PrintFileName("print-file-name",
     75     cl::desc("Precede each symbol with the object file it came from"));
     76 
     77   cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
     78                                 cl::aliasopt(PrintFileName));
     79   cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
     80                                 cl::aliasopt(PrintFileName));
     81 
     82   cl::opt<bool> DebugSyms("debug-syms",
     83     cl::desc("Show all symbols, even debugger only"));
     84   cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
     85                             cl::aliasopt(DebugSyms));
     86 
     87   cl::opt<bool> NumericSort("numeric-sort",
     88     cl::desc("Sort symbols by address"));
     89   cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
     90                               cl::aliasopt(NumericSort));
     91   cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
     92                               cl::aliasopt(NumericSort));
     93 
     94   cl::opt<bool> NoSort("no-sort",
     95     cl::desc("Show symbols in order encountered"));
     96   cl::alias NoSortp("p", cl::desc("Alias for --no-sort"),
     97                          cl::aliasopt(NoSort));
     98 
     99   cl::opt<bool> PrintSize("print-size",
    100     cl::desc("Show symbol size instead of address"));
    101   cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
    102                             cl::aliasopt(PrintSize));
    103 
    104   cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
    105 
    106   bool PrintAddress = true;
    107 
    108   bool MultipleFiles = false;
    109 
    110   std::string ToolName;
    111 }
    112 
    113 namespace {
    114   struct NMSymbol {
    115     uint64_t  Address;
    116     uint64_t  Size;
    117     char      TypeChar;
    118     StringRef Name;
    119   };
    120 
    121   static bool CompareSymbolAddress(const NMSymbol &a, const NMSymbol &b) {
    122     if (a.Address < b.Address)
    123       return true;
    124     else if (a.Address == b.Address && a.Name < b.Name)
    125       return true;
    126     else
    127       return false;
    128 
    129   }
    130 
    131   static bool CompareSymbolSize(const NMSymbol &a, const NMSymbol &b) {
    132     if (a.Size < b.Size)
    133       return true;
    134     else if (a.Size == b.Size && a.Name < b.Name)
    135       return true;
    136     else
    137       return false;
    138   }
    139 
    140   static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) {
    141     return a.Name < b.Name;
    142   }
    143 
    144   StringRef CurrentFilename;
    145   typedef std::vector<NMSymbol> SymbolListT;
    146   SymbolListT SymbolList;
    147 
    148   bool error(error_code ec) {
    149     if (!ec) return false;
    150 
    151     outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
    152     outs().flush();
    153     return true;
    154   }
    155 }
    156 
    157 static void SortAndPrintSymbolList() {
    158   if (!NoSort) {
    159     if (NumericSort)
    160       std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolAddress);
    161     else if (SizeSort)
    162       std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolSize);
    163     else
    164       std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolName);
    165   }
    166 
    167   if (OutputFormat == posix && MultipleFiles) {
    168     outs() << '\n' << CurrentFilename << ":\n";
    169   } else if (OutputFormat == bsd && MultipleFiles) {
    170     outs() << "\n" << CurrentFilename << ":\n";
    171   } else if (OutputFormat == sysv) {
    172     outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"
    173            << "Name                  Value   Class        Type"
    174            << "         Size   Line  Section\n";
    175   }
    176 
    177   for (SymbolListT::iterator i = SymbolList.begin(),
    178                              e = SymbolList.end(); i != e; ++i) {
    179     if ((i->TypeChar != 'U') && UndefinedOnly)
    180       continue;
    181     if ((i->TypeChar == 'U') && DefinedOnly)
    182       continue;
    183     if (SizeSort && !PrintAddress && i->Size == UnknownAddressOrSize)
    184       continue;
    185 
    186     char SymbolAddrStr[10] = "";
    187     char SymbolSizeStr[10] = "";
    188 
    189     if (OutputFormat == sysv || i->Address == object::UnknownAddressOrSize)
    190       strcpy(SymbolAddrStr, "        ");
    191     if (OutputFormat == sysv)
    192       strcpy(SymbolSizeStr, "        ");
    193 
    194     if (i->Address != object::UnknownAddressOrSize)
    195       format("%08"PRIx64, i->Address).print(SymbolAddrStr, sizeof(SymbolAddrStr));
    196     if (i->Size != object::UnknownAddressOrSize)
    197       format("%08"PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
    198 
    199     if (OutputFormat == posix) {
    200       outs() << i->Name << " " << i->TypeChar << " "
    201              << SymbolAddrStr << SymbolSizeStr << "\n";
    202     } else if (OutputFormat == bsd) {
    203       if (PrintAddress)
    204         outs() << SymbolAddrStr << ' ';
    205       if (PrintSize) {
    206         outs() << SymbolSizeStr;
    207         if (i->Size != object::UnknownAddressOrSize)
    208           outs() << ' ';
    209       }
    210       outs() << i->TypeChar << " " << i->Name  << "\n";
    211     } else if (OutputFormat == sysv) {
    212       std::string PaddedName (i->Name);
    213       while (PaddedName.length () < 20)
    214         PaddedName += " ";
    215       outs() << PaddedName << "|" << SymbolAddrStr << "|   "
    216              << i->TypeChar
    217              << "  |                  |" << SymbolSizeStr << "|     |\n";
    218     }
    219   }
    220 
    221   SymbolList.clear();
    222 }
    223 
    224 static char TypeCharForSymbol(GlobalValue &GV) {
    225   if (GV.isDeclaration())                                  return 'U';
    226   if (GV.hasLinkOnceLinkage())                             return 'C';
    227   if (GV.hasCommonLinkage())                               return 'C';
    228   if (GV.hasWeakLinkage())                                 return 'W';
    229   if (isa<Function>(GV) && GV.hasInternalLinkage())        return 't';
    230   if (isa<Function>(GV))                                   return 'T';
    231   if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage())  return 'd';
    232   if (isa<GlobalVariable>(GV))                             return 'D';
    233   if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) {
    234     const GlobalValue *AliasedGV = GA->getAliasedGlobal();
    235     if (isa<Function>(AliasedGV))                          return 'T';
    236     if (isa<GlobalVariable>(AliasedGV))                    return 'D';
    237   }
    238                                                            return '?';
    239 }
    240 
    241 static void DumpSymbolNameForGlobalValue(GlobalValue &GV) {
    242   // Private linkage and available_externally linkage don't exist in symtab.
    243   if (GV.hasPrivateLinkage() ||
    244       GV.hasLinkerPrivateLinkage() ||
    245       GV.hasLinkerPrivateWeakLinkage() ||
    246       GV.hasLinkerPrivateWeakDefAutoLinkage() ||
    247       GV.hasAvailableExternallyLinkage())
    248     return;
    249   char TypeChar = TypeCharForSymbol(GV);
    250   if (GV.hasLocalLinkage () && ExternalOnly)
    251     return;
    252 
    253   NMSymbol s;
    254   s.Address = object::UnknownAddressOrSize;
    255   s.Size = object::UnknownAddressOrSize;
    256   s.TypeChar = TypeChar;
    257   s.Name     = GV.getName();
    258   SymbolList.push_back(s);
    259 }
    260 
    261 static void DumpSymbolNamesFromModule(Module *M) {
    262   CurrentFilename = M->getModuleIdentifier();
    263   std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue);
    264   std::for_each (M->global_begin(), M->global_end(),
    265                  DumpSymbolNameForGlobalValue);
    266   std::for_each (M->alias_begin(), M->alias_end(),
    267                  DumpSymbolNameForGlobalValue);
    268 
    269   SortAndPrintSymbolList();
    270 }
    271 
    272 static void DumpSymbolNamesFromObject(ObjectFile *obj) {
    273   error_code ec;
    274   for (symbol_iterator i = obj->begin_symbols(),
    275                        e = obj->end_symbols();
    276                        i != e; i.increment(ec)) {
    277     if (error(ec)) break;
    278     bool internal;
    279     if (error(i->isInternal(internal))) break;
    280     if (!DebugSyms && internal)
    281       continue;
    282     NMSymbol s;
    283     s.Size = object::UnknownAddressOrSize;
    284     s.Address = object::UnknownAddressOrSize;
    285     if (PrintSize || SizeSort) {
    286       if (error(i->getSize(s.Size))) break;
    287     }
    288     if (PrintAddress)
    289       if (error(i->getOffset(s.Address))) break;
    290     if (error(i->getNMTypeChar(s.TypeChar))) break;
    291     if (error(i->getName(s.Name))) break;
    292     SymbolList.push_back(s);
    293   }
    294 
    295   CurrentFilename = obj->getFileName();
    296   SortAndPrintSymbolList();
    297 }
    298 
    299 static void DumpSymbolNamesFromFile(std::string &Filename) {
    300   LLVMContext &Context = getGlobalContext();
    301   std::string ErrorMessage;
    302   sys::Path aPath(Filename);
    303   bool exists;
    304   if (sys::fs::exists(aPath.str(), exists) || !exists)
    305     errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
    306   // Note: Currently we do not support reading an archive from stdin.
    307   if (Filename == "-" || aPath.isBitcodeFile()) {
    308     OwningPtr<MemoryBuffer> Buffer;
    309     if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buffer))
    310       ErrorMessage = ec.message();
    311     Module *Result = 0;
    312     if (Buffer.get())
    313       Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
    314 
    315     if (Result) {
    316       DumpSymbolNamesFromModule(Result);
    317       delete Result;
    318     } else
    319       errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n";
    320 
    321   } else if (aPath.isArchive()) {
    322     OwningPtr<Binary> arch;
    323     if (error_code ec = object::createBinary(aPath.str(), arch)) {
    324       errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
    325       return;
    326     }
    327     if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
    328       for (object::Archive::child_iterator i = a->begin_children(),
    329                                            e = a->end_children(); i != e; ++i) {
    330         OwningPtr<Binary> child;
    331         if (error_code ec = i->getAsBinary(child)) {
    332           // Try opening it as a bitcode file.
    333           OwningPtr<MemoryBuffer> buff(i->getBuffer());
    334           Module *Result = 0;
    335           if (buff)
    336             Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage);
    337 
    338           if (Result) {
    339             DumpSymbolNamesFromModule(Result);
    340             delete Result;
    341           }
    342           continue;
    343         }
    344         if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
    345           outs() << o->getFileName() << ":\n";
    346           DumpSymbolNamesFromObject(o);
    347         }
    348       }
    349     }
    350   } else if (aPath.isObjectFile()) {
    351     OwningPtr<Binary> obj;
    352     if (error_code ec = object::createBinary(aPath.str(), obj)) {
    353       errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
    354       return;
    355     }
    356     if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get()))
    357       DumpSymbolNamesFromObject(o);
    358   } else {
    359     errs() << ToolName << ": " << Filename << ": "
    360            << "unrecognizable file type\n";
    361     return;
    362   }
    363 }
    364 
    365 int main(int argc, char **argv) {
    366   // Print a stack trace if we signal out.
    367   sys::PrintStackTraceOnErrorSignal();
    368   PrettyStackTraceProgram X(argc, argv);
    369 
    370   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
    371   cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
    372 
    373   ToolName = argv[0];
    374   if (BSDFormat) OutputFormat = bsd;
    375   if (POSIXFormat) OutputFormat = posix;
    376 
    377   // The relative order of these is important. If you pass --size-sort it should
    378   // only print out the size. However, if you pass -S --size-sort, it should
    379   // print out both the size and address.
    380   if (SizeSort && !PrintSize) PrintAddress = false;
    381   if (OutputFormat == sysv || SizeSort) PrintSize = true;
    382 
    383   switch (InputFilenames.size()) {
    384   case 0: InputFilenames.push_back("-");
    385   case 1: break;
    386   default: MultipleFiles = true;
    387   }
    388 
    389   std::for_each(InputFilenames.begin(), InputFilenames.end(),
    390                 DumpSymbolNamesFromFile);
    391   return 0;
    392 }
    393