1//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
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/// \file
11/// \brief This file implements the COFF-specific dumper for llvm-readobj.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm-readobj.h"
16#include "ARMWinEHPrinter.h"
17#include "Error.h"
18#include "ObjDumper.h"
19#include "StreamWriter.h"
20#include "Win64EHDumper.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/Object/COFF.h"
24#include "llvm/Object/ObjectFile.h"
25#include "llvm/Support/COFF.h"
26#include "llvm/Support/Casting.h"
27#include "llvm/Support/Compiler.h"
28#include "llvm/Support/DataExtractor.h"
29#include "llvm/Support/Format.h"
30#include "llvm/Support/SourceMgr.h"
31#include "llvm/Support/Win64EH.h"
32#include "llvm/Support/raw_ostream.h"
33#include <algorithm>
34#include <cstring>
35#include <system_error>
36#include <time.h>
37
38using namespace llvm;
39using namespace llvm::object;
40using namespace llvm::Win64EH;
41
42namespace {
43
44class COFFDumper : public ObjDumper {
45public:
46  COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
47    : ObjDumper(Writer)
48    , Obj(Obj) {
49    cacheRelocations();
50  }
51
52  virtual void printFileHeaders() override;
53  virtual void printSections() override;
54  virtual void printRelocations() override;
55  virtual void printSymbols() override;
56  virtual void printDynamicSymbols() override;
57  virtual void printUnwindInfo() override;
58
59private:
60  void printSymbol(const SymbolRef &Sym);
61  void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
62  void printDataDirectory(uint32_t Index, const std::string &FieldName);
63
64  template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
65  void printBaseOfDataField(const pe32_header *Hdr);
66  void printBaseOfDataField(const pe32plus_header *Hdr);
67
68  void printCodeViewLineTables(const SectionRef &Section);
69
70  void cacheRelocations();
71
72  std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
73                                SymbolRef &Sym);
74  std::error_code resolveSymbolName(const coff_section *Section,
75                                    uint64_t Offset, StringRef &Name);
76
77  typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
78
79  const llvm::object::COFFObjectFile *Obj;
80  RelocMapTy RelocMap;
81};
82
83} // namespace
84
85
86namespace llvm {
87
88std::error_code createCOFFDumper(const object::ObjectFile *Obj,
89                                 StreamWriter &Writer,
90                                 std::unique_ptr<ObjDumper> &Result) {
91  const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
92  if (!COFFObj)
93    return readobj_error::unsupported_obj_file_format;
94
95  Result.reset(new COFFDumper(COFFObj, Writer));
96  return readobj_error::success;
97}
98
99} // namespace llvm
100
101// Given a a section and an offset into this section the function returns the
102// symbol used for the relocation at the offset.
103std::error_code COFFDumper::resolveSymbol(const coff_section *Section,
104                                          uint64_t Offset, SymbolRef &Sym) {
105  const auto &Relocations = RelocMap[Section];
106  for (const auto &Relocation : Relocations) {
107    uint64_t RelocationOffset;
108    if (std::error_code EC = Relocation.getOffset(RelocationOffset))
109      return EC;
110
111    if (RelocationOffset == Offset) {
112      Sym = *Relocation.getSymbol();
113      return readobj_error::success;
114    }
115  }
116  return readobj_error::unknown_symbol;
117}
118
119// Given a section and an offset into this section the function returns the name
120// of the symbol used for the relocation at the offset.
121std::error_code COFFDumper::resolveSymbolName(const coff_section *Section,
122                                              uint64_t Offset,
123                                              StringRef &Name) {
124  SymbolRef Symbol;
125  if (std::error_code EC = resolveSymbol(Section, Offset, Symbol))
126    return EC;
127  if (std::error_code EC = Symbol.getName(Name))
128    return EC;
129  return object_error::success;
130}
131
132static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
133  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN  ),
134  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33     ),
135  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64    ),
136  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM      ),
137  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT    ),
138  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC      ),
139  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386     ),
140  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64     ),
141  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R     ),
142  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16   ),
143  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU  ),
144  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
145  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC  ),
146  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
147  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000    ),
148  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3      ),
149  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP   ),
150  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4      ),
151  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5      ),
152  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB    ),
153  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
154};
155
156static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
157  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED        ),
158  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE       ),
159  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED     ),
160  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED    ),
161  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM     ),
162  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE    ),
163  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO      ),
164  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE          ),
165  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED         ),
166  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
167  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP      ),
168  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM                 ),
169  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL                    ),
170  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY         ),
171  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI      )
172};
173
174static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
175  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN                ),
176  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE                 ),
177  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI            ),
178  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI            ),
179  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI              ),
180  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI         ),
181  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION        ),
182  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
183  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER     ),
184  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM                ),
185  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX                   ),
186};
187
188static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
189  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA      ),
190  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE         ),
191  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY      ),
192  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT            ),
193  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION         ),
194  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH               ),
195  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND              ),
196  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER         ),
197  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER           ),
198  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF             ),
199  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
200};
201
202static const EnumEntry<COFF::SectionCharacteristics>
203ImageSectionCharacteristics[] = {
204  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD           ),
205  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE              ),
206  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA  ),
207  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
208  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER             ),
209  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO              ),
210  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE            ),
211  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT            ),
212  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL                 ),
213  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE         ),
214  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT             ),
215  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED            ),
216  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD           ),
217  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES          ),
218  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES          ),
219  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES          ),
220  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES          ),
221  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES         ),
222  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES         ),
223  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES         ),
224  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES        ),
225  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES        ),
226  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES        ),
227  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES       ),
228  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES       ),
229  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES       ),
230  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES       ),
231  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL       ),
232  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE       ),
233  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED        ),
234  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED         ),
235  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED            ),
236  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE           ),
237  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ              ),
238  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE             )
239};
240
241static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
242  { "Null"  , COFF::IMAGE_SYM_TYPE_NULL   },
243  { "Void"  , COFF::IMAGE_SYM_TYPE_VOID   },
244  { "Char"  , COFF::IMAGE_SYM_TYPE_CHAR   },
245  { "Short" , COFF::IMAGE_SYM_TYPE_SHORT  },
246  { "Int"   , COFF::IMAGE_SYM_TYPE_INT    },
247  { "Long"  , COFF::IMAGE_SYM_TYPE_LONG   },
248  { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT  },
249  { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
250  { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
251  { "Union" , COFF::IMAGE_SYM_TYPE_UNION  },
252  { "Enum"  , COFF::IMAGE_SYM_TYPE_ENUM   },
253  { "MOE"   , COFF::IMAGE_SYM_TYPE_MOE    },
254  { "Byte"  , COFF::IMAGE_SYM_TYPE_BYTE   },
255  { "Word"  , COFF::IMAGE_SYM_TYPE_WORD   },
256  { "UInt"  , COFF::IMAGE_SYM_TYPE_UINT   },
257  { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD  }
258};
259
260static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
261  { "Null"    , COFF::IMAGE_SYM_DTYPE_NULL     },
262  { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER  },
263  { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
264  { "Array"   , COFF::IMAGE_SYM_DTYPE_ARRAY    }
265};
266
267static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
268  { "EndOfFunction"  , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION  },
269  { "Null"           , COFF::IMAGE_SYM_CLASS_NULL             },
270  { "Automatic"      , COFF::IMAGE_SYM_CLASS_AUTOMATIC        },
271  { "External"       , COFF::IMAGE_SYM_CLASS_EXTERNAL         },
272  { "Static"         , COFF::IMAGE_SYM_CLASS_STATIC           },
273  { "Register"       , COFF::IMAGE_SYM_CLASS_REGISTER         },
274  { "ExternalDef"    , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF     },
275  { "Label"          , COFF::IMAGE_SYM_CLASS_LABEL            },
276  { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL  },
277  { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
278  { "Argument"       , COFF::IMAGE_SYM_CLASS_ARGUMENT         },
279  { "StructTag"      , COFF::IMAGE_SYM_CLASS_STRUCT_TAG       },
280  { "MemberOfUnion"  , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION  },
281  { "UnionTag"       , COFF::IMAGE_SYM_CLASS_UNION_TAG        },
282  { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION  },
283  { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
284  { "EnumTag"        , COFF::IMAGE_SYM_CLASS_ENUM_TAG         },
285  { "MemberOfEnum"   , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM   },
286  { "RegisterParam"  , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM   },
287  { "BitField"       , COFF::IMAGE_SYM_CLASS_BIT_FIELD        },
288  { "Block"          , COFF::IMAGE_SYM_CLASS_BLOCK            },
289  { "Function"       , COFF::IMAGE_SYM_CLASS_FUNCTION         },
290  { "EndOfStruct"    , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT    },
291  { "File"           , COFF::IMAGE_SYM_CLASS_FILE             },
292  { "Section"        , COFF::IMAGE_SYM_CLASS_SECTION          },
293  { "WeakExternal"   , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL    },
294  { "CLRToken"       , COFF::IMAGE_SYM_CLASS_CLR_TOKEN        }
295};
296
297static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
298  { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
299  { "Any"         , COFF::IMAGE_COMDAT_SELECT_ANY          },
300  { "SameSize"    , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE    },
301  { "ExactMatch"  , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH  },
302  { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE  },
303  { "Largest"     , COFF::IMAGE_COMDAT_SELECT_LARGEST      },
304  { "Newest"      , COFF::IMAGE_COMDAT_SELECT_NEWEST       }
305};
306
307static const EnumEntry<COFF::WeakExternalCharacteristics>
308WeakExternalCharacteristics[] = {
309  { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
310  { "Library"  , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY   },
311  { "Alias"    , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS     }
312};
313
314template <typename T>
315static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
316                                        const coff_symbol *Symbol,
317                                        const T *&Aux) {
318  ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
319  Aux = reinterpret_cast<const T*>(AuxData.data());
320  return readobj_error::success;
321}
322
323void COFFDumper::cacheRelocations() {
324  for (const SectionRef &S : Obj->sections()) {
325    const coff_section *Section = Obj->getCOFFSection(S);
326
327    for (const RelocationRef &Reloc : S.relocations())
328      RelocMap[Section].push_back(Reloc);
329
330    // Sort relocations by address.
331    std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
332              relocAddressLess);
333  }
334}
335
336void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
337  const data_directory *Data;
338  if (Obj->getDataDirectory(Index, Data))
339    return;
340  W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
341  W.printHex(FieldName + "Size", Data->Size);
342}
343
344void COFFDumper::printFileHeaders() {
345  // Print COFF header
346  const coff_file_header *COFFHeader = nullptr;
347  if (error(Obj->getCOFFHeader(COFFHeader)))
348    return;
349
350  time_t TDS = COFFHeader->TimeDateStamp;
351  char FormattedTime[20] = { };
352  strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
353
354  {
355    DictScope D(W, "ImageFileHeader");
356    W.printEnum  ("Machine", COFFHeader->Machine,
357                    makeArrayRef(ImageFileMachineType));
358    W.printNumber("SectionCount", COFFHeader->NumberOfSections);
359    W.printHex   ("TimeDateStamp", FormattedTime, COFFHeader->TimeDateStamp);
360    W.printHex   ("PointerToSymbolTable", COFFHeader->PointerToSymbolTable);
361    W.printNumber("SymbolCount", COFFHeader->NumberOfSymbols);
362    W.printNumber("OptionalHeaderSize", COFFHeader->SizeOfOptionalHeader);
363    W.printFlags ("Characteristics", COFFHeader->Characteristics,
364                    makeArrayRef(ImageFileCharacteristics));
365  }
366
367  // Print PE header. This header does not exist if this is an object file and
368  // not an executable.
369  const pe32_header *PEHeader = nullptr;
370  if (error(Obj->getPE32Header(PEHeader)))
371    return;
372  if (PEHeader)
373    printPEHeader<pe32_header>(PEHeader);
374
375  const pe32plus_header *PEPlusHeader = nullptr;
376  if (error(Obj->getPE32PlusHeader(PEPlusHeader)))
377    return;
378  if (PEPlusHeader)
379    printPEHeader<pe32plus_header>(PEPlusHeader);
380}
381
382template <class PEHeader>
383void COFFDumper::printPEHeader(const PEHeader *Hdr) {
384  DictScope D(W, "ImageOptionalHeader");
385  W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
386  W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
387  W.printNumber("SizeOfCode", Hdr->SizeOfCode);
388  W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData);
389  W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData);
390  W.printHex   ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint);
391  W.printHex   ("BaseOfCode", Hdr->BaseOfCode);
392  printBaseOfDataField(Hdr);
393  W.printHex   ("ImageBase", Hdr->ImageBase);
394  W.printNumber("SectionAlignment", Hdr->SectionAlignment);
395  W.printNumber("FileAlignment", Hdr->FileAlignment);
396  W.printNumber("MajorOperatingSystemVersion",
397                Hdr->MajorOperatingSystemVersion);
398  W.printNumber("MinorOperatingSystemVersion",
399                Hdr->MinorOperatingSystemVersion);
400  W.printNumber("MajorImageVersion", Hdr->MajorImageVersion);
401  W.printNumber("MinorImageVersion", Hdr->MinorImageVersion);
402  W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion);
403  W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
404  W.printNumber("SizeOfImage", Hdr->SizeOfImage);
405  W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
406  W.printEnum  ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
407  W.printFlags ("Subsystem", Hdr->DLLCharacteristics,
408                makeArrayRef(PEDLLCharacteristics));
409  W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
410  W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
411  W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
412  W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit);
413  W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize);
414
415  if (Hdr->NumberOfRvaAndSize > 0) {
416    DictScope D(W, "DataDirectory");
417    static const char * const directory[] = {
418      "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
419      "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
420      "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
421      "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
422    };
423
424    for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
425      printDataDirectory(i, directory[i]);
426    }
427  }
428}
429
430void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
431  W.printHex("BaseOfData", Hdr->BaseOfData);
432}
433
434void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}
435
436void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
437  StringRef Data;
438  if (error(Section.getContents(Data)))
439    return;
440
441  SmallVector<StringRef, 10> FunctionNames;
442  StringMap<StringRef> FunctionLineTables;
443  StringRef FileIndexToStringOffsetTable;
444  StringRef StringTable;
445
446  ListScope D(W, "CodeViewLineTables");
447  {
448    DataExtractor DE(Data, true, 4);
449    uint32_t Offset = 0,
450             Magic = DE.getU32(&Offset);
451    W.printHex("Magic", Magic);
452    if (Magic != COFF::DEBUG_SECTION_MAGIC) {
453      error(object_error::parse_failed);
454      return;
455    }
456
457    bool Finished = false;
458    while (DE.isValidOffset(Offset) && !Finished) {
459      // The section consists of a number of subsection in the following format:
460      // |Type|PayloadSize|Payload...|
461      uint32_t SubSectionType = DE.getU32(&Offset),
462               PayloadSize = DE.getU32(&Offset);
463      ListScope S(W, "Subsection");
464      W.printHex("Type", SubSectionType);
465      W.printHex("PayloadSize", PayloadSize);
466      if (PayloadSize > Data.size() - Offset) {
467        error(object_error::parse_failed);
468        return;
469      }
470
471      // Print the raw contents to simplify debugging if anything goes wrong
472      // afterwards.
473      StringRef Contents = Data.substr(Offset, PayloadSize);
474      W.printBinaryBlock("Contents", Contents);
475
476      switch (SubSectionType) {
477      case COFF::DEBUG_LINE_TABLE_SUBSECTION: {
478        // Holds a PC to file:line table.  Some data to parse this subsection is
479        // stored in the other subsections, so just check sanity and store the
480        // pointers for deferred processing.
481
482        if (PayloadSize < 12) {
483          // There should be at least three words to store two function
484          // relocations and size of the code.
485          error(object_error::parse_failed);
486          return;
487        }
488
489        StringRef FunctionName;
490        if (error(resolveSymbolName(Obj->getCOFFSection(Section), Offset,
491                                    FunctionName)))
492          return;
493        W.printString("FunctionName", FunctionName);
494        if (FunctionLineTables.count(FunctionName) != 0) {
495          // Saw debug info for this function already?
496          error(object_error::parse_failed);
497          return;
498        }
499
500        FunctionLineTables[FunctionName] = Contents;
501        FunctionNames.push_back(FunctionName);
502        break;
503      }
504      case COFF::DEBUG_STRING_TABLE_SUBSECTION:
505        if (PayloadSize == 0 || StringTable.data() != nullptr ||
506            Contents.back() != '\0') {
507          // Empty or duplicate or non-null-terminated subsection.
508          error(object_error::parse_failed);
509          return;
510        }
511        StringTable = Contents;
512        break;
513      case COFF::DEBUG_INDEX_SUBSECTION:
514        // Holds the translation table from file indices
515        // to offsets in the string table.
516
517        if (PayloadSize == 0 ||
518            FileIndexToStringOffsetTable.data() != nullptr) {
519          // Empty or duplicate subsection.
520          error(object_error::parse_failed);
521          return;
522        }
523        FileIndexToStringOffsetTable = Contents;
524        break;
525      }
526      Offset += PayloadSize;
527
528      // Align the reading pointer by 4.
529      Offset += (-Offset) % 4;
530    }
531  }
532
533  // Dump the line tables now that we've read all the subsections and know all
534  // the required information.
535  for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) {
536    StringRef Name = FunctionNames[I];
537    ListScope S(W, "FunctionLineTable");
538    W.printString("FunctionName", Name);
539
540    DataExtractor DE(FunctionLineTables[Name], true, 4);
541    uint32_t Offset = 8;  // Skip relocations.
542    uint32_t FunctionSize = DE.getU32(&Offset);
543    W.printHex("CodeSize", FunctionSize);
544    while (DE.isValidOffset(Offset)) {
545      // For each range of lines with the same filename, we have a segment
546      // in the line table.  The filename string is accessed using double
547      // indirection to the string table subsection using the index subsection.
548      uint32_t OffsetInIndex = DE.getU32(&Offset),
549               SegmentLength   = DE.getU32(&Offset),
550               FullSegmentSize = DE.getU32(&Offset);
551      if (FullSegmentSize != 12 + 8 * SegmentLength) {
552        error(object_error::parse_failed);
553        return;
554      }
555
556      uint32_t FilenameOffset;
557      {
558        DataExtractor SDE(FileIndexToStringOffsetTable, true, 4);
559        uint32_t OffsetInSDE = OffsetInIndex;
560        if (!SDE.isValidOffset(OffsetInSDE)) {
561          error(object_error::parse_failed);
562          return;
563        }
564        FilenameOffset = SDE.getU32(&OffsetInSDE);
565      }
566
567      if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() ||
568          StringTable.data()[FilenameOffset - 1] != '\0') {
569        // Each string in an F3 subsection should be preceded by a null
570        // character.
571        error(object_error::parse_failed);
572        return;
573      }
574
575      StringRef Filename(StringTable.data() + FilenameOffset);
576      ListScope S(W, "FilenameSegment");
577      W.printString("Filename", Filename);
578      for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
579           ++J) {
580        // Then go the (PC, LineNumber) pairs.  The line number is stored in the
581        // least significant 31 bits of the respective word in the table.
582        uint32_t PC = DE.getU32(&Offset),
583                 LineNumber = DE.getU32(&Offset) & 0x7fffffff;
584        if (PC >= FunctionSize) {
585          error(object_error::parse_failed);
586          return;
587        }
588        char Buffer[32];
589        format("+0x%X", PC).snprint(Buffer, 32);
590        W.printNumber(Buffer, LineNumber);
591      }
592    }
593  }
594}
595
596void COFFDumper::printSections() {
597  ListScope SectionsD(W, "Sections");
598  int SectionNumber = 0;
599  for (const SectionRef &Sec : Obj->sections()) {
600    ++SectionNumber;
601    const coff_section *Section = Obj->getCOFFSection(Sec);
602
603    StringRef Name;
604    if (error(Sec.getName(Name)))
605      Name = "";
606
607    DictScope D(W, "Section");
608    W.printNumber("Number", SectionNumber);
609    W.printBinary("Name", Name, Section->Name);
610    W.printHex   ("VirtualSize", Section->VirtualSize);
611    W.printHex   ("VirtualAddress", Section->VirtualAddress);
612    W.printNumber("RawDataSize", Section->SizeOfRawData);
613    W.printHex   ("PointerToRawData", Section->PointerToRawData);
614    W.printHex   ("PointerToRelocations", Section->PointerToRelocations);
615    W.printHex   ("PointerToLineNumbers", Section->PointerToLinenumbers);
616    W.printNumber("RelocationCount", Section->NumberOfRelocations);
617    W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
618    W.printFlags ("Characteristics", Section->Characteristics,
619                    makeArrayRef(ImageSectionCharacteristics),
620                    COFF::SectionCharacteristics(0x00F00000));
621
622    if (opts::SectionRelocations) {
623      ListScope D(W, "Relocations");
624      for (const RelocationRef &Reloc : Sec.relocations())
625        printRelocation(Sec, Reloc);
626    }
627
628    if (opts::SectionSymbols) {
629      ListScope D(W, "Symbols");
630      for (const SymbolRef &Symbol : Obj->symbols()) {
631        bool Contained = false;
632        if (Sec.containsSymbol(Symbol, Contained) || !Contained)
633          continue;
634
635        printSymbol(Symbol);
636      }
637    }
638
639    if (Name == ".debug$S" && opts::CodeViewLineTables)
640      printCodeViewLineTables(Sec);
641
642    if (opts::SectionData) {
643      StringRef Data;
644      if (error(Sec.getContents(Data)))
645        break;
646
647      W.printBinaryBlock("SectionData", Data);
648    }
649  }
650}
651
652void COFFDumper::printRelocations() {
653  ListScope D(W, "Relocations");
654
655  int SectionNumber = 0;
656  for (const SectionRef &Section : Obj->sections()) {
657    ++SectionNumber;
658    StringRef Name;
659    if (error(Section.getName(Name)))
660      continue;
661
662    bool PrintedGroup = false;
663    for (const RelocationRef &Reloc : Section.relocations()) {
664      if (!PrintedGroup) {
665        W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
666        W.indent();
667        PrintedGroup = true;
668      }
669
670      printRelocation(Section, Reloc);
671    }
672
673    if (PrintedGroup) {
674      W.unindent();
675      W.startLine() << "}\n";
676    }
677  }
678}
679
680void COFFDumper::printRelocation(const SectionRef &Section,
681                                 const RelocationRef &Reloc) {
682  uint64_t Offset;
683  uint64_t RelocType;
684  SmallString<32> RelocName;
685  StringRef SymbolName;
686  StringRef Contents;
687  if (error(Reloc.getOffset(Offset)))
688    return;
689  if (error(Reloc.getType(RelocType)))
690    return;
691  if (error(Reloc.getTypeName(RelocName)))
692    return;
693  symbol_iterator Symbol = Reloc.getSymbol();
694  if (error(Symbol->getName(SymbolName)))
695    return;
696  if (error(Section.getContents(Contents)))
697    return;
698
699  if (opts::ExpandRelocs) {
700    DictScope Group(W, "Relocation");
701    W.printHex("Offset", Offset);
702    W.printNumber("Type", RelocName, RelocType);
703    W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
704  } else {
705    raw_ostream& OS = W.startLine();
706    OS << W.hex(Offset)
707       << " " << RelocName
708       << " " << (SymbolName.size() > 0 ? SymbolName : "-")
709       << "\n";
710  }
711}
712
713void COFFDumper::printSymbols() {
714  ListScope Group(W, "Symbols");
715
716  for (const SymbolRef &Symbol : Obj->symbols())
717    printSymbol(Symbol);
718}
719
720void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
721
722void COFFDumper::printSymbol(const SymbolRef &Sym) {
723  DictScope D(W, "Symbol");
724
725  const coff_symbol *Symbol = Obj->getCOFFSymbol(Sym);
726  const coff_section *Section;
727  if (std::error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) {
728    W.startLine() << "Invalid section number: " << EC.message() << "\n";
729    W.flush();
730    return;
731  }
732
733  StringRef SymbolName;
734  if (Obj->getSymbolName(Symbol, SymbolName))
735    SymbolName = "";
736
737  StringRef SectionName = "";
738  if (Section)
739    Obj->getSectionName(Section, SectionName);
740
741  W.printString("Name", SymbolName);
742  W.printNumber("Value", Symbol->Value);
743  W.printNumber("Section", SectionName, Symbol->SectionNumber);
744  W.printEnum  ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType));
745  W.printEnum  ("ComplexType", Symbol->getComplexType(),
746                                                   makeArrayRef(ImageSymDType));
747  W.printEnum  ("StorageClass", Symbol->StorageClass,
748                                                   makeArrayRef(ImageSymClass));
749  W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols);
750
751  for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) {
752    if (Symbol->isFunctionDefinition()) {
753      const coff_aux_function_definition *Aux;
754      if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
755        break;
756
757      DictScope AS(W, "AuxFunctionDef");
758      W.printNumber("TagIndex", Aux->TagIndex);
759      W.printNumber("TotalSize", Aux->TotalSize);
760      W.printHex("PointerToLineNumber", Aux->PointerToLinenumber);
761      W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
762      W.printBinary("Unused", makeArrayRef(Aux->Unused));
763
764    } else if (Symbol->isWeakExternal()) {
765      const coff_aux_weak_external *Aux;
766      if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
767        break;
768
769      const coff_symbol *Linked;
770      StringRef LinkedName;
771      std::error_code EC;
772      if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) ||
773          (EC = Obj->getSymbolName(Linked, LinkedName))) {
774        LinkedName = "";
775        error(EC);
776      }
777
778      DictScope AS(W, "AuxWeakExternal");
779      W.printNumber("Linked", LinkedName, Aux->TagIndex);
780      W.printEnum  ("Search", Aux->Characteristics,
781                    makeArrayRef(WeakExternalCharacteristics));
782      W.printBinary("Unused", makeArrayRef(Aux->Unused));
783
784    } else if (Symbol->isFileRecord()) {
785      const coff_aux_file *Aux;
786      if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
787        break;
788
789      DictScope AS(W, "AuxFileRecord");
790
791      StringRef Name(Aux->FileName,
792                     Symbol->NumberOfAuxSymbols * COFF::SymbolSize);
793      W.printString("FileName", Name.rtrim(StringRef("\0", 1)));
794      break;
795    } else if (Symbol->isSectionDefinition()) {
796      const coff_aux_section_definition *Aux;
797      if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
798        break;
799
800      DictScope AS(W, "AuxSectionDef");
801      W.printNumber("Length", Aux->Length);
802      W.printNumber("RelocationCount", Aux->NumberOfRelocations);
803      W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
804      W.printHex("Checksum", Aux->CheckSum);
805      W.printNumber("Number", Aux->Number);
806      W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
807      W.printBinary("Unused", makeArrayRef(Aux->Unused));
808
809      if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
810          && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
811        const coff_section *Assoc;
812        StringRef AssocName;
813        std::error_code EC;
814        if ((EC = Obj->getSection(Aux->Number, Assoc)) ||
815            (EC = Obj->getSectionName(Assoc, AssocName))) {
816          AssocName = "";
817          error(EC);
818        }
819
820        W.printNumber("AssocSection", AssocName, Aux->Number);
821      }
822    } else if (Symbol->isCLRToken()) {
823      const coff_aux_clr_token *Aux;
824      if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
825        break;
826
827      const coff_symbol *ReferredSym;
828      StringRef ReferredName;
829      std::error_code EC;
830      if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) ||
831          (EC = Obj->getSymbolName(ReferredSym, ReferredName))) {
832        ReferredName = "";
833        error(EC);
834      }
835
836      DictScope AS(W, "AuxCLRToken");
837      W.printNumber("AuxType", Aux->AuxType);
838      W.printNumber("Reserved", Aux->Reserved);
839      W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex);
840      W.printBinary("Unused", makeArrayRef(Aux->Unused));
841
842    } else {
843      W.startLine() << "<unhandled auxiliary record>\n";
844    }
845  }
846}
847
848void COFFDumper::printUnwindInfo() {
849  const coff_file_header *Header;
850  if (error(Obj->getCOFFHeader(Header)))
851    return;
852
853  ListScope D(W, "UnwindInformation");
854  switch (Header->Machine) {
855  case COFF::IMAGE_FILE_MACHINE_AMD64: {
856    Win64EH::Dumper Dumper(W);
857    Win64EH::Dumper::SymbolResolver
858    Resolver = [](const object::coff_section *Section, uint64_t Offset,
859                  SymbolRef &Symbol, void *user_data) -> std::error_code {
860      COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data);
861      return Dumper->resolveSymbol(Section, Offset, Symbol);
862    };
863    Win64EH::Dumper::Context Ctx(*Obj, Resolver, this);
864    Dumper.printData(Ctx);
865    break;
866  }
867  case COFF::IMAGE_FILE_MACHINE_ARMNT: {
868    ARM::WinEH::Decoder Decoder(W);
869    Decoder.dumpProcedureData(*Obj);
870    break;
871  }
872  default:
873    W.printEnum("unsupported Image Machine", Header->Machine,
874                makeArrayRef(ImageFileMachineType));
875    break;
876  }
877}
878
879