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//
10239462Sdim// This program is a utility that works like traditional Unix "nm", that is, it
11239462Sdim// prints out the names of symbols in a bitcode or object file, along with some
12239462Sdim// information about each symbol.
13193323Sed//
14239462Sdim// This "nm" supports many of the features of GNU "nm", including its different
15239462Sdim// output formats.
16193323Sed//
17193323Sed//===----------------------------------------------------------------------===//
18193323Sed
19249423Sdim#include "llvm/IR/LLVMContext.h"
20193323Sed#include "llvm/Bitcode/ReaderWriter.h"
21249423Sdim#include "llvm/IR/Module.h"
22226584Sdim#include "llvm/Object/Archive.h"
23263508Sdim#include "llvm/Object/COFF.h"
24263508Sdim#include "llvm/Object/ELFObjectFile.h"
25263508Sdim#include "llvm/Object/MachO.h"
26263508Sdim#include "llvm/Object/MachOUniversal.h"
27218885Sdim#include "llvm/Object/ObjectFile.h"
28193323Sed#include "llvm/Support/CommandLine.h"
29218885Sdim#include "llvm/Support/FileSystem.h"
30249423Sdim#include "llvm/Support/Format.h"
31193323Sed#include "llvm/Support/ManagedStatic.h"
32193323Sed#include "llvm/Support/MemoryBuffer.h"
33193323Sed#include "llvm/Support/PrettyStackTrace.h"
34234353Sdim#include "llvm/Support/Program.h"
35249423Sdim#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
67234353Sdim  cl::opt<bool> DynamicSyms("dynamic",
68234353Sdim                             cl::desc("Display the dynamic symbols instead "
69234353Sdim                                      "of normal symbols."));
70234353Sdim  cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
71234353Sdim                         cl::aliasopt(DynamicSyms));
72234353Sdim
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
116243830Sdim  cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden,
117243830Sdim                               cl::desc("Exclude aliases from output"));
118243830Sdim
119249423Sdim  cl::opt<bool> ArchiveMap("print-armap",
120249423Sdim    cl::desc("Print the archive map"));
121249423Sdim  cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"),
122249423Sdim                                 cl::aliasopt(ArchiveMap));
123218885Sdim  bool PrintAddress = true;
124218885Sdim
125193323Sed  bool MultipleFiles = false;
126193323Sed
127263508Sdim  bool HadError = false;
128263508Sdim
129193323Sed  std::string ToolName;
130193323Sed}
131193323Sed
132234353Sdim
133234353Sdimstatic void error(Twine message, Twine path = Twine()) {
134234353Sdim  errs() << ToolName << ": " << path << ": " << message << ".\n";
135234353Sdim}
136234353Sdim
137234353Sdimstatic bool error(error_code ec, Twine path = Twine()) {
138234353Sdim  if (ec) {
139234353Sdim    error(ec.message(), path);
140263508Sdim    HadError = true;
141234353Sdim    return true;
142234353Sdim  }
143234353Sdim  return false;
144234353Sdim}
145234353Sdim
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;
159249423Sdim    else if (a.Address == b.Address && a.Name == b.Name && a.Size < b.Size)
160249423Sdim      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;
171249423Sdim    else if (a.Size == b.Size && a.Name == b.Name && a.Address < b.Address)
172249423Sdim      return true;
173218885Sdim    else
174218885Sdim      return false;
175218885Sdim  }
176218885Sdim
177218885Sdim  static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) {
178249423Sdim    if (a.Name < b.Name)
179249423Sdim      return true;
180249423Sdim    else if (a.Name == b.Name && a.Size < b.Size)
181249423Sdim      return true;
182249423Sdim    else if (a.Name == b.Name && a.Size == b.Size && a.Address < b.Address)
183249423Sdim      return true;
184249423Sdim    else
185249423Sdim      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)
231234353Sdim      format("%08" PRIx64, i->Address).print(SymbolAddrStr,
232234353Sdim                                             sizeof(SymbolAddrStr));
233218885Sdim    if (i->Size != object::UnknownAddressOrSize)
234234353Sdim      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);
302243830Sdim  if (!WithoutAliases)
303243830Sdim    std::for_each (M->alias_begin(), M->alias_end(),
304243830Sdim		   DumpSymbolNameForGlobalValue);
305218885Sdim
306218885Sdim  SortAndPrintSymbolList();
307193323Sed}
308193323Sed
309263508Sdimtemplate <class ELFT>
310263508Sdimerror_code getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, symbol_iterator I,
311263508Sdim                               char &Result) {
312263508Sdim  typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
313263508Sdim  typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
314263508Sdim
315263508Sdim  DataRefImpl Symb = I->getRawDataRefImpl();
316263508Sdim  const Elf_Sym *ESym = Obj.getSymbol(Symb);
317263508Sdim  const ELFFile<ELFT> &EF = *Obj.getELFFile();
318263508Sdim  const Elf_Shdr *ESec = EF.getSection(ESym);
319263508Sdim
320263508Sdim  char ret = '?';
321263508Sdim
322263508Sdim  if (ESec) {
323263508Sdim    switch (ESec->sh_type) {
324263508Sdim    case ELF::SHT_PROGBITS:
325263508Sdim    case ELF::SHT_DYNAMIC:
326263508Sdim      switch (ESec->sh_flags) {
327263508Sdim      case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) :
328263508Sdim        ret = 't';
329263508Sdim        break;
330263508Sdim      case(ELF::SHF_ALLOC | ELF::SHF_WRITE) :
331263508Sdim        ret = 'd';
332263508Sdim        break;
333263508Sdim      case ELF::SHF_ALLOC:
334263508Sdim      case(ELF::SHF_ALLOC | ELF::SHF_MERGE) :
335263508Sdim      case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) :
336263508Sdim        ret = 'r';
337263508Sdim        break;
338263508Sdim      }
339263508Sdim      break;
340263508Sdim    case ELF::SHT_NOBITS:
341263508Sdim      ret = 'b';
342263508Sdim    }
343263508Sdim  }
344263508Sdim
345263508Sdim  switch (EF.getSymbolTableIndex(ESym)) {
346263508Sdim  case ELF::SHN_UNDEF:
347263508Sdim    if (ret == '?')
348263508Sdim      ret = 'U';
349263508Sdim    break;
350263508Sdim  case ELF::SHN_ABS:
351263508Sdim    ret = 'a';
352263508Sdim    break;
353263508Sdim  case ELF::SHN_COMMON:
354263508Sdim    ret = 'c';
355263508Sdim    break;
356263508Sdim  }
357263508Sdim
358263508Sdim  switch (ESym->getBinding()) {
359263508Sdim  case ELF::STB_GLOBAL:
360263508Sdim    ret = ::toupper(ret);
361263508Sdim    break;
362263508Sdim  case ELF::STB_WEAK:
363263508Sdim    if (EF.getSymbolTableIndex(ESym) == ELF::SHN_UNDEF)
364263508Sdim      ret = 'w';
365263508Sdim    else if (ESym->getType() == ELF::STT_OBJECT)
366263508Sdim      ret = 'V';
367263508Sdim    else
368263508Sdim      ret = 'W';
369263508Sdim  }
370263508Sdim
371263508Sdim  if (ret == '?' && ESym->getType() == ELF::STT_SECTION) {
372263508Sdim    StringRef Name;
373263508Sdim    error_code EC = I->getName(Name);
374263508Sdim    if (EC)
375263508Sdim      return EC;
376263508Sdim    Result = StringSwitch<char>(Name)
377263508Sdim                 .StartsWith(".debug", 'N')
378263508Sdim                 .StartsWith(".note", 'n')
379263508Sdim                 .Default('?');
380263508Sdim    return object_error::success;
381263508Sdim  }
382263508Sdim
383263508Sdim  Result = ret;
384263508Sdim  return object_error::success;
385263508Sdim}
386263508Sdim
387263508Sdimstatic error_code getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I,
388263508Sdim                                      char &Result) {
389263508Sdim  const coff_symbol *symb = Obj.getCOFFSymbol(I);
390263508Sdim  StringRef name;
391263508Sdim  if (error_code ec = I->getName(name))
392263508Sdim    return ec;
393263508Sdim  char ret = StringSwitch<char>(name)
394263508Sdim                 .StartsWith(".debug", 'N')
395263508Sdim                 .StartsWith(".sxdata", 'N')
396263508Sdim                 .Default('?');
397263508Sdim
398263508Sdim  if (ret != '?') {
399263508Sdim    Result = ret;
400263508Sdim    return object_error::success;
401263508Sdim  }
402263508Sdim
403263508Sdim  uint32_t Characteristics = 0;
404263508Sdim  if (symb->SectionNumber > 0) {
405263508Sdim    section_iterator SecI = Obj.end_sections();
406263508Sdim    if (error_code ec = I->getSection(SecI))
407263508Sdim      return ec;
408263508Sdim    const coff_section *Section = Obj.getCOFFSection(SecI);
409263508Sdim    Characteristics = Section->Characteristics;
410263508Sdim  }
411263508Sdim
412263508Sdim  switch (symb->SectionNumber) {
413263508Sdim  case COFF::IMAGE_SYM_UNDEFINED:
414263508Sdim    // Check storage classes.
415263508Sdim    if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
416263508Sdim      Result = 'w';
417263508Sdim      return object_error::success; // Don't do ::toupper.
418263508Sdim    } else if (symb->Value != 0)    // Check for common symbols.
419263508Sdim      ret = 'c';
420263508Sdim    else
421263508Sdim      ret = 'u';
422263508Sdim    break;
423263508Sdim  case COFF::IMAGE_SYM_ABSOLUTE:
424263508Sdim    ret = 'a';
425263508Sdim    break;
426263508Sdim  case COFF::IMAGE_SYM_DEBUG:
427263508Sdim    ret = 'n';
428263508Sdim    break;
429263508Sdim  default:
430263508Sdim    // Check section type.
431263508Sdim    if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
432263508Sdim      ret = 't';
433263508Sdim    else if (Characteristics & COFF::IMAGE_SCN_MEM_READ &&
434263508Sdim             ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only.
435263508Sdim      ret = 'r';
436263508Sdim    else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
437263508Sdim      ret = 'd';
438263508Sdim    else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
439263508Sdim      ret = 'b';
440263508Sdim    else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
441263508Sdim      ret = 'i';
442263508Sdim
443263508Sdim    // Check for section symbol.
444263508Sdim    else if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC &&
445263508Sdim             symb->Value == 0)
446263508Sdim      ret = 's';
447263508Sdim  }
448263508Sdim
449263508Sdim  if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL)
450263508Sdim    ret = ::toupper(static_cast<unsigned char>(ret));
451263508Sdim
452263508Sdim  Result = ret;
453263508Sdim  return object_error::success;
454263508Sdim}
455263508Sdim
456263508Sdimstatic uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) {
457263508Sdim  if (Obj.is64Bit()) {
458263508Sdim    MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
459263508Sdim    return STE.n_type;
460263508Sdim  }
461263508Sdim  MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
462263508Sdim  return STE.n_type;
463263508Sdim}
464263508Sdim
465263508Sdimstatic error_code getSymbolNMTypeChar(MachOObjectFile &Obj, symbol_iterator I,
466263508Sdim                                      char &Res) {
467263508Sdim  DataRefImpl Symb = I->getRawDataRefImpl();
468263508Sdim  uint8_t NType = getNType(Obj, Symb);
469263508Sdim
470263508Sdim  char Char;
471263508Sdim  switch (NType & MachO::N_TYPE) {
472263508Sdim  case MachO::N_UNDF:
473263508Sdim    Char = 'u';
474263508Sdim    break;
475263508Sdim  case MachO::N_ABS:
476263508Sdim    Char = 's';
477263508Sdim    break;
478263508Sdim  case MachO::N_SECT: {
479263508Sdim    section_iterator Sec = Obj.end_sections();
480263508Sdim    Obj.getSymbolSection(Symb, Sec);
481263508Sdim    DataRefImpl Ref = Sec->getRawDataRefImpl();
482263508Sdim    StringRef SectionName;
483263508Sdim    Obj.getSectionName(Ref, SectionName);
484263508Sdim    StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
485263508Sdim    if (SegmentName == "__TEXT" && SectionName == "__text")
486263508Sdim      Char = 't';
487263508Sdim    else
488263508Sdim      Char = 's';
489263508Sdim  } break;
490263508Sdim  default:
491263508Sdim    Char = '?';
492263508Sdim    break;
493263508Sdim  }
494263508Sdim
495263508Sdim  if (NType & (MachO::N_EXT | MachO::N_PEXT))
496263508Sdim    Char = toupper(static_cast<unsigned char>(Char));
497263508Sdim  Res = Char;
498263508Sdim  return object_error::success;
499263508Sdim}
500263508Sdim
501263508Sdimstatic char getNMTypeChar(ObjectFile *Obj, symbol_iterator I) {
502263508Sdim  char Res = '?';
503263508Sdim  if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) {
504263508Sdim    error(getSymbolNMTypeChar(*COFF, I, Res));
505263508Sdim    return Res;
506263508Sdim  }
507263508Sdim  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) {
508263508Sdim    error(getSymbolNMTypeChar(*MachO, I, Res));
509263508Sdim    return Res;
510263508Sdim  }
511263508Sdim
512263508Sdim  if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) {
513263508Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
514263508Sdim    return Res;
515263508Sdim  }
516263508Sdim  if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) {
517263508Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
518263508Sdim    return Res;
519263508Sdim  }
520263508Sdim  if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) {
521263508Sdim    error(getSymbolNMTypeChar(*ELF, I, Res));
522263508Sdim    return Res;
523263508Sdim  }
524263508Sdim  ELF64BEObjectFile *ELF = cast<ELF64BEObjectFile>(Obj);
525263508Sdim  error(getSymbolNMTypeChar(*ELF, I, Res));
526263508Sdim  return Res;
527263508Sdim}
528263508Sdim
529218885Sdimstatic void DumpSymbolNamesFromObject(ObjectFile *obj) {
530224133Sdim  error_code ec;
531234353Sdim  symbol_iterator ibegin = obj->begin_symbols();
532234353Sdim  symbol_iterator iend = obj->end_symbols();
533234353Sdim  if (DynamicSyms) {
534234353Sdim    ibegin = obj->begin_dynamic_symbols();
535234353Sdim    iend = obj->end_dynamic_symbols();
536234353Sdim  }
537234353Sdim  for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
538224133Sdim    if (error(ec)) break;
539234353Sdim    uint32_t symflags;
540234353Sdim    if (error(i->getFlags(symflags))) break;
541234353Sdim    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)
550234353Sdim      if (error(i->getAddress(s.Address))) break;
551263508Sdim    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) {
561234353Sdim  if (Filename != "-" && !sys::fs::exists(Filename)) {
562234353Sdim    errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
563234353Sdim    return;
564234353Sdim  }
565234353Sdim
566234353Sdim  OwningPtr<MemoryBuffer> Buffer;
567234353Sdim  if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename))
568234353Sdim    return;
569234353Sdim
570234353Sdim  sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer());
571234353Sdim
572198090Srdivacky  LLVMContext &Context = getGlobalContext();
573193323Sed  std::string ErrorMessage;
574234353Sdim  if (magic == sys::fs::file_magic::bitcode) {
575193323Sed    Module *Result = 0;
576234353Sdim    Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
577198090Srdivacky    if (Result) {
578193323Sed      DumpSymbolNamesFromModule(Result);
579198090Srdivacky      delete Result;
580234353Sdim    } else {
581234353Sdim      error(ErrorMessage, Filename);
582234353Sdim      return;
583234353Sdim    }
584234353Sdim  } else if (magic == sys::fs::file_magic::archive) {
585226584Sdim    OwningPtr<Binary> arch;
586234353Sdim    if (error(object::createBinary(Buffer.take(), arch), Filename))
587193323Sed      return;
588234353Sdim
589226584Sdim    if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
590249423Sdim      if (ArchiveMap) {
591263508Sdim        object::Archive::symbol_iterator I = a->begin_symbols();
592263508Sdim        object::Archive::symbol_iterator E = a->end_symbols();
593263508Sdim        if (I !=E) {
594263508Sdim          outs() << "Archive map" << "\n";
595263508Sdim          for (; I != E; ++I) {
596263508Sdim            object::Archive::child_iterator c;
597263508Sdim            StringRef symname;
598263508Sdim            StringRef filename;
599263508Sdim            if (error(I->getMember(c)))
600249423Sdim              return;
601263508Sdim            if (error(I->getName(symname)))
602249423Sdim              return;
603263508Sdim            if (error(c->getName(filename)))
604249423Sdim              return;
605263508Sdim            outs() << symname << " in " << filename << "\n";
606263508Sdim          }
607263508Sdim          outs() << "\n";
608249423Sdim        }
609249423Sdim      }
610249423Sdim
611226584Sdim      for (object::Archive::child_iterator i = a->begin_children(),
612226584Sdim                                           e = a->end_children(); i != e; ++i) {
613226584Sdim        OwningPtr<Binary> child;
614234353Sdim        if (i->getAsBinary(child)) {
615226584Sdim          // Try opening it as a bitcode file.
616249423Sdim          OwningPtr<MemoryBuffer> buff;
617249423Sdim          if (error(i->getMemoryBuffer(buff)))
618249423Sdim            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    }
635263508Sdim  } else if (magic == sys::fs::file_magic::macho_universal_binary) {
636263508Sdim    OwningPtr<Binary> Bin;
637263508Sdim    if (error(object::createBinary(Buffer.take(), Bin), Filename))
638263508Sdim      return;
639263508Sdim
640263508Sdim    object::MachOUniversalBinary *UB =
641263508Sdim        cast<object::MachOUniversalBinary>(Bin.get());
642263508Sdim    for (object::MachOUniversalBinary::object_iterator
643263508Sdim             I = UB->begin_objects(),
644263508Sdim             E = UB->end_objects();
645263508Sdim         I != E; ++I) {
646263508Sdim      OwningPtr<ObjectFile> Obj;
647263508Sdim      if (!I->getAsObjectFile(Obj)) {
648263508Sdim        outs() << Obj->getFileName() << ":\n";
649263508Sdim        DumpSymbolNamesFromObject(Obj.get());
650263508Sdim      }
651263508Sdim    }
652234353Sdim  } else if (magic.is_object()) {
653224133Sdim    OwningPtr<Binary> obj;
654234353Sdim    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";
661263508Sdim    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
674234353Sdim  // llvm-nm only reads binary files.
675263508Sdim  if (error(sys::ChangeStdinToBinary()))
676234353Sdim    return 1;
677234353Sdim
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);
696263508Sdim
697263508Sdim  if (HadError)
698263508Sdim    return 1;
699263508Sdim
700193323Sed  return 0;
701193323Sed}
702