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