1//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
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 is a tool similar to readelf, except it works on multiple object file
11// formats. The main purpose of this tool is to provide detailed output suitable
12// for FileCheck.
13//
14// Flags should be similar to readelf where supported, but the output format
15// does not need to be identical. The point is to not make users learn yet
16// another set of flags.
17//
18// Output should be specialized for each format where appropriate.
19//
20//===----------------------------------------------------------------------===//
21
22#include "llvm-readobj.h"
23#include "Error.h"
24#include "ObjDumper.h"
25#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
26#include "llvm/Object/Archive.h"
27#include "llvm/Object/COFFImportFile.h"
28#include "llvm/Object/ELFObjectFile.h"
29#include "llvm/Object/MachOUniversal.h"
30#include "llvm/Object/ObjectFile.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/CommandLine.h"
33#include "llvm/Support/DataTypes.h"
34#include "llvm/Support/Debug.h"
35#include "llvm/Support/FileSystem.h"
36#include "llvm/Support/ManagedStatic.h"
37#include "llvm/Support/PrettyStackTrace.h"
38#include "llvm/Support/ScopedPrinter.h"
39#include "llvm/Support/Signals.h"
40#include "llvm/Support/TargetRegistry.h"
41#include "llvm/Support/TargetSelect.h"
42#include <string>
43#include <system_error>
44
45using namespace llvm;
46using namespace llvm::object;
47
48namespace opts {
49  cl::list<std::string> InputFilenames(cl::Positional,
50    cl::desc("<input object files>"),
51    cl::ZeroOrMore);
52
53  // -file-headers, -h
54  cl::opt<bool> FileHeaders("file-headers",
55    cl::desc("Display file headers "));
56  cl::alias FileHeadersShort("h",
57    cl::desc("Alias for --file-headers"),
58    cl::aliasopt(FileHeaders));
59
60  // -sections, -s
61  cl::opt<bool> Sections("sections",
62    cl::desc("Display all sections."));
63  cl::alias SectionsShort("s",
64    cl::desc("Alias for --sections"),
65    cl::aliasopt(Sections));
66
67  // -section-relocations, -sr
68  cl::opt<bool> SectionRelocations("section-relocations",
69    cl::desc("Display relocations for each section shown."));
70  cl::alias SectionRelocationsShort("sr",
71    cl::desc("Alias for --section-relocations"),
72    cl::aliasopt(SectionRelocations));
73
74  // -section-symbols, -st
75  cl::opt<bool> SectionSymbols("section-symbols",
76    cl::desc("Display symbols for each section shown."));
77  cl::alias SectionSymbolsShort("st",
78    cl::desc("Alias for --section-symbols"),
79    cl::aliasopt(SectionSymbols));
80
81  // -section-data, -sd
82  cl::opt<bool> SectionData("section-data",
83    cl::desc("Display section data for each section shown."));
84  cl::alias SectionDataShort("sd",
85    cl::desc("Alias for --section-data"),
86    cl::aliasopt(SectionData));
87
88  // -relocations, -r
89  cl::opt<bool> Relocations("relocations",
90    cl::desc("Display the relocation entries in the file"));
91  cl::alias RelocationsShort("r",
92    cl::desc("Alias for --relocations"),
93    cl::aliasopt(Relocations));
94
95  // -dyn-relocations
96  cl::opt<bool> DynRelocs("dyn-relocations",
97    cl::desc("Display the dynamic relocation entries in the file"));
98
99  // -symbols, -t
100  cl::opt<bool> Symbols("symbols",
101    cl::desc("Display the symbol table"));
102  cl::alias SymbolsShort("t",
103    cl::desc("Alias for --symbols"),
104    cl::aliasopt(Symbols));
105
106  // -dyn-symbols, -dt
107  cl::opt<bool> DynamicSymbols("dyn-symbols",
108    cl::desc("Display the dynamic symbol table"));
109  cl::alias DynamicSymbolsShort("dt",
110    cl::desc("Alias for --dyn-symbols"),
111    cl::aliasopt(DynamicSymbols));
112
113  // -unwind, -u
114  cl::opt<bool> UnwindInfo("unwind",
115    cl::desc("Display unwind information"));
116  cl::alias UnwindInfoShort("u",
117    cl::desc("Alias for --unwind"),
118    cl::aliasopt(UnwindInfo));
119
120  // -dynamic-table
121  cl::opt<bool> DynamicTable("dynamic-table",
122    cl::desc("Display the ELF .dynamic section table"));
123
124  // -needed-libs
125  cl::opt<bool> NeededLibraries("needed-libs",
126    cl::desc("Display the needed libraries"));
127
128  // -program-headers
129  cl::opt<bool> ProgramHeaders("program-headers",
130    cl::desc("Display ELF program headers"));
131
132  // -hash-table
133  cl::opt<bool> HashTable("hash-table",
134    cl::desc("Display ELF hash table"));
135
136  // -gnu-hash-table
137  cl::opt<bool> GnuHashTable("gnu-hash-table",
138    cl::desc("Display ELF .gnu.hash section"));
139
140  // -expand-relocs
141  cl::opt<bool> ExpandRelocs("expand-relocs",
142    cl::desc("Expand each shown relocation to multiple lines"));
143
144  // -codeview
145  cl::opt<bool> CodeView("codeview",
146                         cl::desc("Display CodeView debug information"));
147
148  // -codeview-merged-types
149  cl::opt<bool>
150      CodeViewMergedTypes("codeview-merged-types",
151                          cl::desc("Display the merged CodeView type stream"));
152
153  // -codeview-subsection-bytes
154  cl::opt<bool> CodeViewSubsectionBytes(
155      "codeview-subsection-bytes",
156      cl::desc("Dump raw contents of codeview debug sections and records"));
157
158  // -arm-attributes, -a
159  cl::opt<bool> ARMAttributes("arm-attributes",
160                              cl::desc("Display the ARM attributes section"));
161  cl::alias ARMAttributesShort("-a", cl::desc("Alias for --arm-attributes"),
162                               cl::aliasopt(ARMAttributes));
163
164  // -mips-plt-got
165  cl::opt<bool>
166  MipsPLTGOT("mips-plt-got",
167             cl::desc("Display the MIPS GOT and PLT GOT sections"));
168
169  // -mips-abi-flags
170  cl::opt<bool> MipsABIFlags("mips-abi-flags",
171                             cl::desc("Display the MIPS.abiflags section"));
172
173  // -mips-reginfo
174  cl::opt<bool> MipsReginfo("mips-reginfo",
175                            cl::desc("Display the MIPS .reginfo section"));
176
177  // -mips-options
178  cl::opt<bool> MipsOptions("mips-options",
179                            cl::desc("Display the MIPS .MIPS.options section"));
180
181  // -coff-imports
182  cl::opt<bool>
183  COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
184
185  // -coff-exports
186  cl::opt<bool>
187  COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
188
189  // -coff-directives
190  cl::opt<bool>
191  COFFDirectives("coff-directives",
192                 cl::desc("Display the PE/COFF .drectve section"));
193
194  // -coff-basereloc
195  cl::opt<bool>
196  COFFBaseRelocs("coff-basereloc",
197                 cl::desc("Display the PE/COFF .reloc section"));
198
199  // -coff-debug-directory
200  cl::opt<bool>
201  COFFDebugDirectory("coff-debug-directory",
202                     cl::desc("Display the PE/COFF debug directory"));
203
204  // -macho-data-in-code
205  cl::opt<bool>
206  MachODataInCode("macho-data-in-code",
207                  cl::desc("Display MachO Data in Code command"));
208
209  // -macho-indirect-symbols
210  cl::opt<bool>
211  MachOIndirectSymbols("macho-indirect-symbols",
212                  cl::desc("Display MachO indirect symbols"));
213
214  // -macho-linker-options
215  cl::opt<bool>
216  MachOLinkerOptions("macho-linker-options",
217                  cl::desc("Display MachO linker options"));
218
219  // -macho-segment
220  cl::opt<bool>
221  MachOSegment("macho-segment",
222                  cl::desc("Display MachO Segment command"));
223
224  // -macho-version-min
225  cl::opt<bool>
226  MachOVersionMin("macho-version-min",
227                  cl::desc("Display MachO version min command"));
228
229  // -macho-dysymtab
230  cl::opt<bool>
231  MachODysymtab("macho-dysymtab",
232                  cl::desc("Display MachO Dysymtab command"));
233
234  // -stackmap
235  cl::opt<bool>
236  PrintStackMap("stackmap",
237                cl::desc("Display contents of stackmap section"));
238
239  // -version-info
240  cl::opt<bool>
241      VersionInfo("version-info",
242                  cl::desc("Display ELF version sections (if present)"));
243  cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"),
244                             cl::aliasopt(VersionInfo));
245
246  cl::opt<bool> SectionGroups("elf-section-groups",
247                              cl::desc("Display ELF section group contents"));
248  cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
249                               cl::aliasopt(SectionGroups));
250  cl::opt<bool> HashHistogram(
251      "elf-hash-histogram",
252      cl::desc("Display bucket list histogram for hash sections"));
253  cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"),
254                               cl::aliasopt(HashHistogram));
255
256  cl::opt<OutputStyleTy>
257      Output("elf-output-style", cl::desc("Specify ELF dump style"),
258             cl::values(clEnumVal(LLVM, "LLVM default style"),
259                        clEnumVal(GNU, "GNU readelf style"), clEnumValEnd),
260             cl::init(LLVM));
261} // namespace opts
262
263namespace llvm {
264
265LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
266  errs() << "\nError reading file: " << Msg << ".\n";
267  errs().flush();
268  exit(1);
269}
270
271void error(std::error_code EC) {
272  if (!EC)
273    return;
274
275  reportError(EC.message());
276}
277
278bool relocAddressLess(RelocationRef a, RelocationRef b) {
279  return a.getOffset() < b.getOffset();
280}
281
282} // namespace llvm
283
284static void reportError(StringRef Input, std::error_code EC) {
285  if (Input == "-")
286    Input = "<stdin>";
287
288  reportError(Twine(Input) + ": " + EC.message());
289}
290
291static void reportError(StringRef Input, StringRef Message) {
292  if (Input == "-")
293    Input = "<stdin>";
294
295  reportError(Twine(Input) + ": " + Message);
296}
297
298static void reportError(StringRef Input, Error Err) {
299  if (Input == "-")
300    Input = "<stdin>";
301  std::string ErrMsg;
302  {
303    raw_string_ostream ErrStream(ErrMsg);
304    logAllUnhandledErrors(std::move(Err), ErrStream, Input + ": ");
305  }
306  reportError(ErrMsg);
307}
308
309static bool isMipsArch(unsigned Arch) {
310  switch (Arch) {
311  case llvm::Triple::mips:
312  case llvm::Triple::mipsel:
313  case llvm::Triple::mips64:
314  case llvm::Triple::mips64el:
315    return true;
316  default:
317    return false;
318  }
319}
320
321static llvm::codeview::MemoryTypeTableBuilder CVTypes;
322
323/// @brief Creates an format-specific object file dumper.
324static std::error_code createDumper(const ObjectFile *Obj,
325                                    ScopedPrinter &Writer,
326                                    std::unique_ptr<ObjDumper> &Result) {
327  if (!Obj)
328    return readobj_error::unsupported_file_format;
329
330  if (Obj->isCOFF())
331    return createCOFFDumper(Obj, Writer, Result);
332  if (Obj->isELF())
333    return createELFDumper(Obj, Writer, Result);
334  if (Obj->isMachO())
335    return createMachODumper(Obj, Writer, Result);
336
337  return readobj_error::unsupported_obj_file_format;
338}
339
340/// @brief Dumps the specified object file.
341static void dumpObject(const ObjectFile *Obj) {
342  ScopedPrinter Writer(outs());
343  std::unique_ptr<ObjDumper> Dumper;
344  if (std::error_code EC = createDumper(Obj, Writer, Dumper))
345    reportError(Obj->getFileName(), EC);
346
347  if (opts::Output == opts::LLVM) {
348    outs() << '\n';
349    outs() << "File: " << Obj->getFileName() << "\n";
350    outs() << "Format: " << Obj->getFileFormatName() << "\n";
351    outs() << "Arch: " << Triple::getArchTypeName(
352                              (llvm::Triple::ArchType)Obj->getArch()) << "\n";
353    outs() << "AddressSize: " << (8 * Obj->getBytesInAddress()) << "bit\n";
354    Dumper->printLoadName();
355  }
356
357  if (opts::FileHeaders)
358    Dumper->printFileHeaders();
359  if (opts::Sections)
360    Dumper->printSections();
361  if (opts::Relocations)
362    Dumper->printRelocations();
363  if (opts::DynRelocs)
364    Dumper->printDynamicRelocations();
365  if (opts::Symbols)
366    Dumper->printSymbols();
367  if (opts::DynamicSymbols)
368    Dumper->printDynamicSymbols();
369  if (opts::UnwindInfo)
370    Dumper->printUnwindInfo();
371  if (opts::DynamicTable)
372    Dumper->printDynamicTable();
373  if (opts::NeededLibraries)
374    Dumper->printNeededLibraries();
375  if (opts::ProgramHeaders)
376    Dumper->printProgramHeaders();
377  if (opts::HashTable)
378    Dumper->printHashTable();
379  if (opts::GnuHashTable)
380    Dumper->printGnuHashTable();
381  if (opts::VersionInfo)
382    Dumper->printVersionInfo();
383  if (Obj->isELF()) {
384    if (Obj->getArch() == llvm::Triple::arm)
385      if (opts::ARMAttributes)
386        Dumper->printAttributes();
387    if (isMipsArch(Obj->getArch())) {
388      if (opts::MipsPLTGOT)
389        Dumper->printMipsPLTGOT();
390      if (opts::MipsABIFlags)
391        Dumper->printMipsABIFlags();
392      if (opts::MipsReginfo)
393        Dumper->printMipsReginfo();
394      if (opts::MipsOptions)
395        Dumper->printMipsOptions();
396    }
397    if (opts::SectionGroups)
398      Dumper->printGroupSections();
399    if (opts::HashHistogram)
400      Dumper->printHashHistogram();
401  }
402  if (Obj->isCOFF()) {
403    if (opts::COFFImports)
404      Dumper->printCOFFImports();
405    if (opts::COFFExports)
406      Dumper->printCOFFExports();
407    if (opts::COFFDirectives)
408      Dumper->printCOFFDirectives();
409    if (opts::COFFBaseRelocs)
410      Dumper->printCOFFBaseReloc();
411    if (opts::COFFDebugDirectory)
412      Dumper->printCOFFDebugDirectory();
413    if (opts::CodeView)
414      Dumper->printCodeViewDebugInfo();
415    if (opts::CodeViewMergedTypes)
416      Dumper->mergeCodeViewTypes(CVTypes);
417  }
418  if (Obj->isMachO()) {
419    if (opts::MachODataInCode)
420      Dumper->printMachODataInCode();
421    if (opts::MachOIndirectSymbols)
422      Dumper->printMachOIndirectSymbols();
423    if (opts::MachOLinkerOptions)
424      Dumper->printMachOLinkerOptions();
425    if (opts::MachOSegment)
426      Dumper->printMachOSegment();
427    if (opts::MachOVersionMin)
428      Dumper->printMachOVersionMin();
429    if (opts::MachODysymtab)
430      Dumper->printMachODysymtab();
431  }
432  if (opts::PrintStackMap)
433    Dumper->printStackMap();
434}
435
436/// @brief Dumps each object file in \a Arc;
437static void dumpArchive(const Archive *Arc) {
438  Error Err;
439  for (auto &Child : Arc->children(Err)) {
440    Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
441    if (!ChildOrErr) {
442      if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
443        std::string Buf;
444        raw_string_ostream OS(Buf);
445        logAllUnhandledErrors(ChildOrErr.takeError(), OS, "");
446        OS.flush();
447        reportError(Arc->getFileName(), Buf);
448      }
449      continue;
450    }
451    if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
452      dumpObject(Obj);
453    else
454      reportError(Arc->getFileName(), readobj_error::unrecognized_file_format);
455  }
456  if (Err)
457    reportError(Arc->getFileName(), std::move(Err));
458}
459
460/// @brief Dumps each object file in \a MachO Universal Binary;
461static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) {
462  for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
463    Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
464    if (ObjOrErr)
465      dumpObject(&*ObjOrErr.get());
466    else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
467      std::string Buf;
468      raw_string_ostream OS(Buf);
469      logAllUnhandledErrors(ObjOrErr.takeError(), OS, "");
470      OS.flush();
471      reportError(UBinary->getFileName(), Buf);
472    }
473    else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
474      dumpArchive(&*AOrErr.get());
475  }
476}
477
478/// @brief Opens \a File and dumps it.
479static void dumpInput(StringRef File) {
480
481  // Attempt to open the binary.
482  Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
483  if (!BinaryOrErr)
484    reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
485  Binary &Binary = *BinaryOrErr.get().getBinary();
486
487  if (Archive *Arc = dyn_cast<Archive>(&Binary))
488    dumpArchive(Arc);
489  else if (MachOUniversalBinary *UBinary =
490               dyn_cast<MachOUniversalBinary>(&Binary))
491    dumpMachOUniversalBinary(UBinary);
492  else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
493    dumpObject(Obj);
494  else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
495    dumpCOFFImportFile(Import);
496  else
497    reportError(File, readobj_error::unrecognized_file_format);
498}
499
500int main(int argc, const char *argv[]) {
501  sys::PrintStackTraceOnErrorSignal(argv[0]);
502  PrettyStackTraceProgram X(argc, argv);
503  llvm_shutdown_obj Y;
504
505  // Register the target printer for --version.
506  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
507
508  cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
509
510  // Default to stdin if no filename is specified.
511  if (opts::InputFilenames.size() == 0)
512    opts::InputFilenames.push_back("-");
513
514  std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
515                dumpInput);
516
517  if (opts::CodeViewMergedTypes) {
518    ScopedPrinter W(outs());
519    dumpCodeViewMergedTypes(W, CVTypes);
520  }
521
522  return 0;
523}
524