1193323Sed//===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10245431Sdim// This program is a utility that works like traditional Unix "nm", that is, it
11245431Sdim// prints out the names of symbols in a bitcode or object file, along with some
12245431Sdim// information about each symbol.
13193323Sed//
14245431Sdim// This "nm" supports many of the features of GNU "nm", including its different
15245431Sdim// output formats.
16193323Sed//
17193323Sed//===----------------------------------------------------------------------===//
18193323Sed
19252723Sdim#include "llvm/IR/LLVMContext.h"
20193323Sed#include "llvm/Bitcode/ReaderWriter.h"
21252723Sdim#include "llvm/IR/Module.h"
22226584Sdim#include "llvm/Object/Archive.h"
23263509Sdim#include "llvm/Object/COFF.h"
24263509Sdim#include "llvm/Object/ELFObjectFile.h"
25263509Sdim#include "llvm/Object/MachO.h"
26263509Sdim#include "llvm/Object/MachOUniversal.h"
27218885Sdim#include "llvm/Object/ObjectFile.h"
28193323Sed#include "llvm/Support/CommandLine.h"
29218885Sdim#include "llvm/Support/FileSystem.h"
30252723Sdim#include "llvm/Support/Format.h"
31193323Sed#include "llvm/Support/ManagedStatic.h"
32193323Sed#include "llvm/Support/MemoryBuffer.h"
33193323Sed#include "llvm/Support/PrettyStackTrace.h"
34235633Sdim#include "llvm/Support/Program.h"
35252723Sdim#include "llvm/Support/Signals.h"
36198090Srdivacky#include "llvm/Support/raw_ostream.h"
37218885Sdim#include "llvm/Support/system_error.h"
38193323Sed#include <algorithm>
39193323Sed#include <cctype>
40193323Sed#include <cerrno>
41193323Sed#include <cstring>
42218885Sdim#include <vector>
43193323Sedusing namespace llvm;
44218885Sdimusing namespace object;
45193323Sed
46193323Sednamespace {
47193323Sed  enum OutputFormatTy { bsd, sysv, posix };
48193323Sed  cl::opt<OutputFormatTy>
49193323Sed  OutputFormat("format",
50193323Sed       cl::desc("Specify output format"),
51193323Sed         cl::values(clEnumVal(bsd,   "BSD format"),
52193323Sed                    clEnumVal(sysv,  "System V format"),
53193323Sed                    clEnumVal(posix, "POSIX.2 format"),
54193323Sed                    clEnumValEnd), cl::init(bsd));
55193323Sed  cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
56193323Sed                          cl::aliasopt(OutputFormat));
57193323Sed
58193323Sed  cl::list<std::string>
59193323Sed  InputFilenames(cl::Positional, cl::desc("<input bitcode files>"),
60193323Sed                 cl::ZeroOrMore);
61193323Sed
62193323Sed  cl::opt<bool> UndefinedOnly("undefined-only",
63193323Sed                              cl::desc("Show only undefined symbols"));
64193323Sed  cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
65193323Sed                           cl::aliasopt(UndefinedOnly));
66193323Sed
67235633Sdim  cl::opt<bool> DynamicSyms("dynamic",
68235633Sdim                             cl::desc("Display the dynamic symbols instead "
69235633Sdim                                      "of normal symbols."));
70235633Sdim  cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
71235633Sdim                         cl::aliasopt(DynamicSyms));
72235633Sdim
73193323Sed  cl::opt<bool> DefinedOnly("defined-only",
74193323Sed                            cl::desc("Show only defined symbols"));
75193323Sed
76193323Sed  cl::opt<bool> ExternalOnly("extern-only",
77193323Sed                             cl::desc("Show only external symbols"));
78193323Sed  cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
79193323Sed                          cl::aliasopt(ExternalOnly));
80193323Sed
81193323Sed  cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"));
82193323Sed  cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"));
83193323Sed
84218885Sdim  cl::opt<bool> PrintFileName("print-file-name",
85218885Sdim    cl::desc("Precede each symbol with the object file it came from"));
86218885Sdim
87218885Sdim  cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
88218885Sdim                                cl::aliasopt(PrintFileName));
89218885Sdim  cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
90218885Sdim                                cl::aliasopt(PrintFileName));
91218885Sdim
92218885Sdim  cl::opt<bool> DebugSyms("debug-syms",
93218885Sdim    cl::desc("Show all symbols, even debugger only"));
94218885Sdim  cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
95218885Sdim                            cl::aliasopt(DebugSyms));
96218885Sdim
97218885Sdim  cl::opt<bool> NumericSort("numeric-sort",
98218885Sdim    cl::desc("Sort symbols by address"));
99218885Sdim  cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
100218885Sdim                              cl::aliasopt(NumericSort));
101218885Sdim  cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
102218885Sdim                              cl::aliasopt(NumericSort));
103218885Sdim
104218885Sdim  cl::opt<bool> NoSort("no-sort",
105218885Sdim    cl::desc("Show symbols in order encountered"));
106218885Sdim  cl::alias NoSortp("p", cl::desc("Alias for --no-sort"),
107218885Sdim                         cl::aliasopt(NoSort));
108218885Sdim
109218885Sdim  cl::opt<bool> PrintSize("print-size",
110218885Sdim    cl::desc("Show symbol size instead of address"));
111218885Sdim  cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
112218885Sdim                            cl::aliasopt(PrintSize));
113218885Sdim
114218885Sdim  cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
115218885Sdim
116245431Sdim  cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden,
117245431Sdim                               cl::desc("Exclude aliases from output"));
118245431Sdim
119252723Sdim  cl::opt<bool> ArchiveMap("print-armap",
120252723Sdim    cl::desc("Print the archive map"));
121252723Sdim  cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"),
122252723Sdim                                 cl::aliasopt(ArchiveMap));
123218885Sdim  bool PrintAddress = true;
124218885Sdim
125193323Sed  bool MultipleFiles = false;
126193323Sed
127263509Sdim  bool HadError = false;
128263509Sdim
129193323Sed  std::string ToolName;
130193323Sed}
131193323Sed
132235633Sdim
133235633Sdimstatic void error(Twine message, Twine path = Twine()) {
134235633Sdim  errs() << ToolName << ": " << path << ": " << message << ".\n";
135235633Sdim}
136235633Sdim
137235633Sdimstatic bool error(error_code ec, Twine path = Twine()) {
138235633Sdim  if (ec) {
139235633Sdim    error(ec.message(), path);
140263509Sdim    HadError = true;
141235633Sdim    return true;
142235633Sdim  }
143235633Sdim  return false;
144235633Sdim}
145235633Sdim
146218885Sdimnamespace {
147218885Sdim  struct NMSymbol {
148218885Sdim    uint64_t  Address;
149218885Sdim    uint64_t  Size;
150218885Sdim    char      TypeChar;
151218885Sdim    StringRef Name;
152218885Sdim  };
153218885Sdim
154218885Sdim  static bool CompareSymbolAddress(const NMSymbol &a, const NMSymbol &b) {
155218885Sdim    if (a.Address < b.Address)
156218885Sdim      return true;
157218885Sdim    else if (a.Address == b.Address && a.Name < b.Name)
158218885Sdim      return true;
159252723Sdim    else if (a.Address == b.Address && a.Name == b.Name && a.Size < b.Size)
160252723Sdim      return true;
161218885Sdim    else
162218885Sdim      return false;
163218885Sdim
164218885Sdim  }
165218885Sdim
166218885Sdim  static bool CompareSymbolSize(const NMSymbol &a, const NMSymbol &b) {
167218885Sdim    if (a.Size < b.Size)
168218885Sdim      return true;
169218885Sdim    else if (a.Size == b.Size && a.Name < b.Name)
170218885Sdim      return true;
171252723Sdim    else if (a.Size == b.Size && a.Name == b.Name && a.Address < b.Address)
172252723Sdim      return true;
173218885Sdim    else
174218885Sdim      return false;
175218885Sdim  }
176218885Sdim
177218885Sdim  static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) {
178252723Sdim    if (a.Name < b.Name)
179252723Sdim      return true;
180252723Sdim    else if (a.Name == b.Name && a.Size < b.Size)
181252723Sdim      return true;
182252723Sdim    else if (a.Name == b.Name && a.Size == b.Size && a.Address < b.Address)
183252723Sdim      return true;
184252723Sdim    else
185252723Sdim      return false;
186218885Sdim  }
187218885Sdim
188218885Sdim  StringRef CurrentFilename;
189218885Sdim  typedef std::vector<NMSymbol> SymbolListT;
190218885Sdim  SymbolListT SymbolList;
191218885Sdim}
192218885Sdim
193218885Sdimstatic void SortAndPrintSymbolList() {
194218885Sdim  if (!NoSort) {
195218885Sdim    if (NumericSort)
196218885Sdim      std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolAddress);
197218885Sdim    else if (SizeSort)
198218885Sdim      std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolSize);
199218885Sdim    else
200218885Sdim      std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolName);
201218885Sdim  }
202218885Sdim
203218885Sdim  if (OutputFormat == posix && MultipleFiles) {
204218885Sdim    outs() << '\n' << CurrentFilename << ":\n";
205218885Sdim  } else if (OutputFormat == bsd && MultipleFiles) {
206218885Sdim    outs() << "\n" << CurrentFilename << ":\n";
207218885Sdim  } else if (OutputFormat == sysv) {
208218885Sdim    outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"
209218885Sdim           << "Name                  Value   Class        Type"
210218885Sdim           << "         Size   Line  Section\n";
211218885Sdim  }
212218885Sdim
213218885Sdim  for (SymbolListT::iterator i = SymbolList.begin(),
214218885Sdim                             e = SymbolList.end(); i != e; ++i) {
215218885Sdim    if ((i->TypeChar != 'U') && UndefinedOnly)
216218885Sdim      continue;
217218885Sdim    if ((i->TypeChar == 'U') && DefinedOnly)
218218885Sdim      continue;
219218885Sdim    if (SizeSort && !PrintAddress && i->Size == UnknownAddressOrSize)
220218885Sdim      continue;
221218885Sdim
222218885Sdim    char SymbolAddrStr[10] = "";
223218885Sdim    char SymbolSizeStr[10] = "";
224218885Sdim
225218885Sdim    if (OutputFormat == sysv || i->Address == object::UnknownAddressOrSize)
226218885Sdim      strcpy(SymbolAddrStr, "        ");
227218885Sdim    if (OutputFormat == sysv)
228218885Sdim      strcpy(SymbolSizeStr, "        ");
229218885Sdim
230218885Sdim    if (i->Address != object::UnknownAddressOrSize)
231235633Sdim      format("%08" PRIx64, i->Address).print(SymbolAddrStr,
232235633Sdim                                             sizeof(SymbolAddrStr));
233218885Sdim    if (i->Size != object::UnknownAddressOrSize)
234235633Sdim      format("%08" PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
235218885Sdim
236218885Sdim    if (OutputFormat == posix) {
237218885Sdim      outs() << i->Name << " " << i->TypeChar << " "
238218885Sdim             << SymbolAddrStr << SymbolSizeStr << "\n";
239218885Sdim    } else if (OutputFormat == bsd) {
240218885Sdim      if (PrintAddress)
241218885Sdim        outs() << SymbolAddrStr << ' ';
242218885Sdim      if (PrintSize) {
243218885Sdim        outs() << SymbolSizeStr;
244218885Sdim        if (i->Size != object::UnknownAddressOrSize)
245218885Sdim          outs() << ' ';
246218885Sdim      }
247218885Sdim      outs() << i->TypeChar << " " << i->Name  << "\n";
248218885Sdim    } else if (OutputFormat == sysv) {
249218885Sdim      std::string PaddedName (i->Name);
250218885Sdim      while (PaddedName.length () < 20)
251218885Sdim        PaddedName += " ";
252218885Sdim      outs() << PaddedName << "|" << SymbolAddrStr << "|   "
253218885Sdim             << i->TypeChar
254218885Sdim             << "  |                  |" << SymbolSizeStr << "|     |\n";
255218885Sdim    }
256218885Sdim  }
257218885Sdim
258218885Sdim  SymbolList.clear();
259218885Sdim}
260218885Sdim
261193323Sedstatic char TypeCharForSymbol(GlobalValue &GV) {
262193323Sed  if (GV.isDeclaration())                                  return 'U';
263193323Sed  if (GV.hasLinkOnceLinkage())                             return 'C';
264193323Sed  if (GV.hasCommonLinkage())                               return 'C';
265193323Sed  if (GV.hasWeakLinkage())                                 return 'W';
266193323Sed  if (isa<Function>(GV) && GV.hasInternalLinkage())        return 't';
267193323Sed  if (isa<Function>(GV))                                   return 'T';
268193323Sed  if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage())  return 'd';
269193323Sed  if (isa<GlobalVariable>(GV))                             return 'D';
270193323Sed  if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) {
271193323Sed    const GlobalValue *AliasedGV = GA->getAliasedGlobal();
272193323Sed    if (isa<Function>(AliasedGV))                          return 'T';
273193323Sed    if (isa<GlobalVariable>(AliasedGV))                    return 'D';
274193323Sed  }
275193323Sed                                                           return '?';
276193323Sed}
277193323Sed
278193323Sedstatic void DumpSymbolNameForGlobalValue(GlobalValue &GV) {
279193323Sed  // Private linkage and available_externally linkage don't exist in symtab.
280212793Sdim  if (GV.hasPrivateLinkage() ||
281212793Sdim      GV.hasLinkerPrivateLinkage() ||
282212793Sdim      GV.hasLinkerPrivateWeakLinkage() ||
283212793Sdim      GV.hasAvailableExternallyLinkage())
284210006Srdivacky    return;
285193323Sed  char TypeChar = TypeCharForSymbol(GV);
286193323Sed  if (GV.hasLocalLinkage () && ExternalOnly)
287193323Sed    return;
288218885Sdim
289218885Sdim  NMSymbol s;
290218885Sdim  s.Address = object::UnknownAddressOrSize;
291218885Sdim  s.Size = object::UnknownAddressOrSize;
292218885Sdim  s.TypeChar = TypeChar;
293218885Sdim  s.Name     = GV.getName();
294218885Sdim  SymbolList.push_back(s);
295193323Sed}
296193323Sed
297193323Sedstatic void DumpSymbolNamesFromModule(Module *M) {
298218885Sdim  CurrentFilename = M->getModuleIdentifier();
299193323Sed  std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue);
300193323Sed  std::for_each (M->global_begin(), M->global_end(),
301193323Sed                 DumpSymbolNameForGlobalValue);
302245431Sdim  if (!WithoutAliases)
303245431Sdim    std::for_each (M->alias_begin(), M->alias_end(),
304245431Sdim		   DumpSymbolNameForGlobalValue);
305218885Sdim
306218885Sdim  SortAndPrintSymbolList();
307193323Sed}
308193323Sed
309263509Sdimtemplate <class ELFT>
310263509Sdimerror_code getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, symbol_iterator I,
311263509Sdim                               char &Result) {
312263509Sdim  typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
313263509Sdim  typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
314263509Sdim
315263509Sdim  DataRefImpl Symb = I->getRawDataRefImpl();
316263509Sdim  const Elf_Sym *ESym = Obj.getSymbol(Symb);
317263509Sdim  const ELFFile<ELFT> &EF = *Obj.getELFFile();
318263509Sdim  const Elf_Shdr *ESec = EF.getSection(ESym);
319263509Sdim
320263509Sdim  char ret = '?';
321263509Sdim
322263509Sdim  if (ESec) {
323263509Sdim    switch (ESec->sh_type) {
324263509Sdim    case ELF::SHT_PROGBITS:
325263509Sdim    case ELF::SHT_DYNAMIC:
326263509Sdim      switch (ESec->sh_flags) {
327263509Sdim      case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) :
328263509Sdim        ret = 't';
329263509Sdim        break;
330263509Sdim      case(ELF::SHF_ALLOC | ELF::SHF_WRITE) :
331263509Sdim        ret = 'd';
332263509Sdim        break;
333263509Sdim      case ELF::SHF_ALLOC:
334263509Sdim      case(ELF::SHF_ALLOC | ELF::SHF_MERGE) :
335263509Sdim      case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) :
336263509Sdim        ret = 'r';
337263509Sdim        break;
338263509Sdim      }
339263509Sdim      break;
340263509Sdim    case ELF::SHT_NOBITS:
341263509Sdim      ret = 'b';
342263509Sdim    }
343263509Sdim  }
344263509Sdim
345263509Sdim  switch (EF.getSymbolTableIndex(ESym)) {
346263509Sdim  case ELF::SHN_UNDEF:
347263509Sdim    if (ret == '?')
348263509Sdim      ret = 'U';
349263509Sdim    break;
350263509Sdim  case ELF::SHN_ABS:
351263509Sdim    ret = 'a';
352263509Sdim    break;
353263509Sdim  case ELF::SHN_COMMON:
354263509Sdim    ret = 'c';
355263509Sdim    break;
356263509Sdim  }
357263509Sdim
358263509Sdim  switch (ESym->getBinding()) {
359263509Sdim  case ELF::STB_GLOBAL:
360263509Sdim    ret = ::toupper(ret);
361263509Sdim    break;
362263509Sdim  case ELF::STB_WEAK:
363263509Sdim    if (EF.getSymbolTableIndex(ESym) == ELF::SHN_UNDEF)
364263509Sdim      ret = 'w';
365263509Sdim    else if (ESym->getType() == ELF::STT_OBJECT)
366263509Sdim      ret = 'V';
367263509Sdim    else
368263509Sdim      ret = 'W';
369263509Sdim  }
370263509Sdim
371263509Sdim  if (ret == '?' && ESym->getType() == ELF::STT_SECTION) {
372263509Sdim    StringRef Name;
373263509Sdim    error_code EC = I->getName(Name);
374263509Sdim    if (EC)
375263509Sdim      return EC;
376263509Sdim    Result = StringSwitch<char>(Name)
377263509Sdim                 .StartsWith(".debug", 'N')
378263509Sdim                 .StartsWith(".note", 'n')
379263509Sdim                 .Default('?');
380263509Sdim    return object_error::success;
381263509Sdim  }
382263509Sdim
383263509Sdim  Result = ret;
384263509Sdim  return object_error::success;
385263509Sdim}
386263509Sdim
387263509Sdimstatic error_code getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I,
388263509Sdim                                      char &Result) {
389263509Sdim  const coff_symbol *symb = Obj.getCOFFSymbol(I);
390263509Sdim  StringRef name;
391263509Sdim  if (error_code ec = I->getName(name))
392263509Sdim    return ec;
393263509Sdim  char ret = StringSwitch<char>(name)
394263509Sdim                 .StartsWith(".debug", 'N')
395263509Sdim                 .StartsWith(".sxdata", 'N')
396263509Sdim                 .Default('?');
397263509Sdim
398263509Sdim  if (ret != '?') {
399263509Sdim    Result = ret;
400263509Sdim    return object_error::success;
401263509Sdim  }
402263509Sdim
403263509Sdim  uint32_t Characteristics = 0;
404263509Sdim  if (symb->SectionNumber > 0) {
405263509Sdim    section_iterator SecI = Obj.end_sections();
406263509Sdim    if (error_code ec = I->getSection(SecI))
407263509Sdim      return ec;
408263509Sdim    const coff_section *Section = Obj.getCOFFSection(SecI);
409263509Sdim    Characteristics = Section->Characteristics;
410263509Sdim  }
411263509Sdim
412263509Sdim  switch (symb->SectionNumber) {
413263509Sdim  case COFF::IMAGE_SYM_UNDEFINED:
414263509Sdim    // Check storage classes.
415263509Sdim    if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
416263509Sdim      Result = 'w';
417263509Sdim      return object_error::success; // Don't do ::toupper.
418263509Sdim    } else if (symb->Value != 0)    // Check for common symbols.
419263509Sdim      ret = 'c';
420263509Sdim    else
421263509Sdim      ret = 'u';
422263509Sdim    break;
423263509Sdim  case COFF::IMAGE_SYM_ABSOLUTE:
424263509Sdim    ret = 'a';
425263509Sdim    break;
426263509Sdim  case COFF::IMAGE_SYM_DEBUG:
427263509Sdim    ret = 'n';
428263509Sdim    break;
429263509Sdim  default:
430263509Sdim    // Check section type.
431263509Sdim    if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
432263509Sdim      ret = 't';
433263509Sdim    else if (Characteristics & COFF::IMAGE_SCN_MEM_READ &&
434263509Sdim             ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only.
435263509Sdim      ret = 'r';
436263509Sdim    else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
437263509Sdim      ret = 'd';
438263509Sdim    else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
439263509Sdim      ret = 'b';
440263509Sdim    else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
441263509Sdim      ret = 'i';
442263509Sdim
443263509Sdim    // Check for section symbol.
444263509Sdim    else if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC &&
445263509Sdim             symb->Value == 0)
446263509Sdim      ret = 's';
447263509Sdim  }
448263509Sdim
449263509Sdim  if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL)
450263509Sdim    ret = ::toupper(static_cast<unsigned char>(ret));
451263509Sdim
452263509Sdim  Result = ret;
453263509Sdim  return object_error::success;
454263509Sdim}
455263509Sdim
456263509Sdimstatic uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) {
457263509Sdim  if (Obj.is64Bit()) {
458263509Sdim    MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
459263509Sdim    return STE.n_type;
460263509Sdim  }
461263509Sdim  MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
462263509Sdim  return STE.n_type;
463263509Sdim}
464263509Sdim
465263509Sdimstatic error_code getSymbolNMTypeChar(MachOObjectFile &Obj, symbol_iterator I,
466263509Sdim                                      char &Res) {
467263509Sdim  DataRefImpl Symb = I->getRawDataRefImpl();
468263509Sdim  uint8_t NType = getNType(Obj, Symb);
469263509Sdim
470263509Sdim  char Char;
471263509Sdim  switch (NType & MachO::N_TYPE) {
472263509Sdim  case MachO::N_UNDF:
473263509Sdim    Char = 'u';
474263509Sdim    break;
475263509Sdim  case MachO::N_ABS:
476263509Sdim    Char = 's';
477263509Sdim    break;
478263509Sdim  case MachO::N_SECT: {
479263509Sdim    section_iterator Sec = Obj.end_sections();
480263509Sdim    Obj.getSymbolSection(Symb, Sec);
481263509Sdim    DataRefImpl Ref = Sec->getRawDataRefImpl();
482263509Sdim    StringRef SectionName;
483263509Sdim    Obj.getSectionName(Ref, SectionName);
484263509Sdim    StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
485263509Sdim    if (SegmentName == "__TEXT" && SectionName == "__text")
486263509Sdim      Char = 't';
487263509Sdim    else
488263509Sdim      Char = 's';
489263509Sdim  } break;
490263509Sdim  default:
491263509Sdim    Char = '?';
492263509Sdim    break;
493263509Sdim  }
494263509Sdim
495263509Sdim  if (NType & (MachO::N_EXT | MachO::N_PEXT))
496263509Sdim    Char = toupper(static_cast<unsigned char>(Char));
497263509Sdim  Res = Char;
498263509Sdim  return object_error::success;
499263509Sdim}
500263509Sdim
501263509Sdimstatic char getNMTypeChar(ObjectFile *Obj, symbol_iterator I) {
502263509Sdim  char Res = '?';
503263509Sdim  if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) {
504263509Sdim    error(getSymbolNMTypeChar(*COFF, I, Res));
505263509Sdim    return Res;
506263509Sdim  }
507263509Sdim  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) {
508263509Sdim    error(getSymbolNMTypeChar(*MachO, I, Res));
509263509Sdim    return Res;
510263509Sdim  }
511263509Sdim
512263509Sdim  if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) {
513263509Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
514263509Sdim    return Res;
515263509Sdim  }
516263509Sdim  if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) {
517263509Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
518263509Sdim    return Res;
519263509Sdim  }
520263509Sdim  if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) {
521263509Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
522263509Sdim    return Res;
523263509Sdim  }
524263509Sdim  ELF64BEObjectFile *ELF = cast<ELF64BEObjectFile>(Obj);
525263509Sdim  error(getSymbolNMTypeChar(*ELF, I, Res));
526263509Sdim  return Res;
527263509Sdim}
528263509Sdim
529218885Sdimstatic void DumpSymbolNamesFromObject(ObjectFile *obj) {
530224133Sdim  error_code ec;
531235633Sdim  symbol_iterator ibegin = obj->begin_symbols();
532235633Sdim  symbol_iterator iend = obj->end_symbols();
533235633Sdim  if (DynamicSyms) {
534235633Sdim    ibegin = obj->begin_dynamic_symbols();
535235633Sdim    iend = obj->end_dynamic_symbols();
536235633Sdim  }
537235633Sdim  for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
538224133Sdim    if (error(ec)) break;
539235633Sdim    uint32_t symflags;
540235633Sdim    if (error(i->getFlags(symflags))) break;
541235633Sdim    if (!DebugSyms && (symflags & SymbolRef::SF_FormatSpecific))
542218885Sdim      continue;
543218885Sdim    NMSymbol s;
544218885Sdim    s.Size = object::UnknownAddressOrSize;
545218885Sdim    s.Address = object::UnknownAddressOrSize;
546224133Sdim    if (PrintSize || SizeSort) {
547224133Sdim      if (error(i->getSize(s.Size))) break;
548224133Sdim    }
549218885Sdim    if (PrintAddress)
550235633Sdim      if (error(i->getAddress(s.Address))) break;
551263509Sdim    s.TypeChar = getNMTypeChar(obj, i);
552224133Sdim    if (error(i->getName(s.Name))) break;
553218885Sdim    SymbolList.push_back(s);
554218885Sdim  }
555218885Sdim
556224133Sdim  CurrentFilename = obj->getFileName();
557218885Sdim  SortAndPrintSymbolList();
558218885Sdim}
559218885Sdim
560193323Sedstatic void DumpSymbolNamesFromFile(std::string &Filename) {
561235633Sdim  if (Filename != "-" && !sys::fs::exists(Filename)) {
562235633Sdim    errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
563235633Sdim    return;
564235633Sdim  }
565235633Sdim
566235633Sdim  OwningPtr<MemoryBuffer> Buffer;
567235633Sdim  if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename))
568235633Sdim    return;
569235633Sdim
570235633Sdim  sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer());
571235633Sdim
572198090Srdivacky  LLVMContext &Context = getGlobalContext();
573193323Sed  std::string ErrorMessage;
574235633Sdim  if (magic == sys::fs::file_magic::bitcode) {
575193323Sed    Module *Result = 0;
576235633Sdim    Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
577198090Srdivacky    if (Result) {
578193323Sed      DumpSymbolNamesFromModule(Result);
579198090Srdivacky      delete Result;
580235633Sdim    } else {
581235633Sdim      error(ErrorMessage, Filename);
582235633Sdim      return;
583235633Sdim    }
584235633Sdim  } else if (magic == sys::fs::file_magic::archive) {
585226584Sdim    OwningPtr<Binary> arch;
586235633Sdim    if (error(object::createBinary(Buffer.take(), arch), Filename))
587193323Sed      return;
588235633Sdim
589226584Sdim    if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
590252723Sdim      if (ArchiveMap) {
591263509Sdim        object::Archive::symbol_iterator I = a->begin_symbols();
592263509Sdim        object::Archive::symbol_iterator E = a->end_symbols();
593263509Sdim        if (I !=E) {
594263509Sdim          outs() << "Archive map" << "\n";
595263509Sdim          for (; I != E; ++I) {
596263509Sdim            object::Archive::child_iterator c;
597263509Sdim            StringRef symname;
598263509Sdim            StringRef filename;
599263509Sdim            if (error(I->getMember(c)))
600252723Sdim              return;
601263509Sdim            if (error(I->getName(symname)))
602252723Sdim              return;
603263509Sdim            if (error(c->getName(filename)))
604252723Sdim              return;
605263509Sdim            outs() << symname << " in " << filename << "\n";
606263509Sdim          }
607263509Sdim          outs() << "\n";
608252723Sdim        }
609252723Sdim      }
610252723Sdim
611226584Sdim      for (object::Archive::child_iterator i = a->begin_children(),
612226584Sdim                                           e = a->end_children(); i != e; ++i) {
613226584Sdim        OwningPtr<Binary> child;
614235633Sdim        if (i->getAsBinary(child)) {
615226584Sdim          // Try opening it as a bitcode file.
616252723Sdim          OwningPtr<MemoryBuffer> buff;
617252723Sdim          if (error(i->getMemoryBuffer(buff)))
618252723Sdim            return;
619226584Sdim          Module *Result = 0;
620226584Sdim          if (buff)
621226584Sdim            Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage);
622226584Sdim
623226584Sdim          if (Result) {
624226584Sdim            DumpSymbolNamesFromModule(Result);
625226584Sdim            delete Result;
626226584Sdim          }
627226584Sdim          continue;
628226584Sdim        }
629226584Sdim        if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
630226584Sdim          outs() << o->getFileName() << ":\n";
631226584Sdim          DumpSymbolNamesFromObject(o);
632226584Sdim        }
633226584Sdim      }
634226584Sdim    }
635263509Sdim  } else if (magic == sys::fs::file_magic::macho_universal_binary) {
636263509Sdim    OwningPtr<Binary> Bin;
637263509Sdim    if (error(object::createBinary(Buffer.take(), Bin), Filename))
638263509Sdim      return;
639263509Sdim
640263509Sdim    object::MachOUniversalBinary *UB =
641263509Sdim        cast<object::MachOUniversalBinary>(Bin.get());
642263509Sdim    for (object::MachOUniversalBinary::object_iterator
643263509Sdim             I = UB->begin_objects(),
644263509Sdim             E = UB->end_objects();
645263509Sdim         I != E; ++I) {
646263509Sdim      OwningPtr<ObjectFile> Obj;
647263509Sdim      if (!I->getAsObjectFile(Obj)) {
648263509Sdim        outs() << Obj->getFileName() << ":\n";
649263509Sdim        DumpSymbolNamesFromObject(Obj.get());
650263509Sdim      }
651263509Sdim    }
652235633Sdim  } else if (magic.is_object()) {
653224133Sdim    OwningPtr<Binary> obj;
654235633Sdim    if (error(object::createBinary(Buffer.take(), obj), Filename))
655218885Sdim      return;
656224133Sdim    if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get()))
657224133Sdim      DumpSymbolNamesFromObject(o);
658193323Sed  } else {
659198090Srdivacky    errs() << ToolName << ": " << Filename << ": "
660198090Srdivacky           << "unrecognizable file type\n";
661263509Sdim    HadError = true;
662193323Sed    return;
663193323Sed  }
664193323Sed}
665193323Sed
666193323Sedint main(int argc, char **argv) {
667193323Sed  // Print a stack trace if we signal out.
668193323Sed  sys::PrintStackTraceOnErrorSignal();
669193323Sed  PrettyStackTraceProgram X(argc, argv);
670212793Sdim
671193323Sed  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
672193323Sed  cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
673193323Sed
674235633Sdim  // llvm-nm only reads binary files.
675263509Sdim  if (error(sys::ChangeStdinToBinary()))
676235633Sdim    return 1;
677235633Sdim
678193323Sed  ToolName = argv[0];
679193323Sed  if (BSDFormat) OutputFormat = bsd;
680193323Sed  if (POSIXFormat) OutputFormat = posix;
681193323Sed
682218885Sdim  // The relative order of these is important. If you pass --size-sort it should
683218885Sdim  // only print out the size. However, if you pass -S --size-sort, it should
684218885Sdim  // print out both the size and address.
685218885Sdim  if (SizeSort && !PrintSize) PrintAddress = false;
686218885Sdim  if (OutputFormat == sysv || SizeSort) PrintSize = true;
687218885Sdim
688193323Sed  switch (InputFilenames.size()) {
689193323Sed  case 0: InputFilenames.push_back("-");
690193323Sed  case 1: break;
691193323Sed  default: MultipleFiles = true;
692193323Sed  }
693193323Sed
694193323Sed  std::for_each(InputFilenames.begin(), InputFilenames.end(),
695193323Sed                DumpSymbolNamesFromFile);
696263509Sdim
697263509Sdim  if (HadError)
698263509Sdim    return 1;
699263509Sdim
700193323Sed  return 0;
701193323Sed}
702