1 //===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file implements the COFF-specific dumper for llvm-readobj.
13 //===----------------------------------------------------------------------===//
15 #include "ARMWinEHPrinter.h"
17 #include "ObjDumper.h"
18 #include "StackMapPrinter.h"
19 #include "Win64EHDumper.h"
20 #include "llvm-readobj.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/StringExtras.h"
24 #include "llvm/BinaryFormat/COFF.h"
25 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
26 #include "llvm/DebugInfo/CodeView/CodeView.h"
27 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
28 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
30 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
31 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
32 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
33 #include "llvm/DebugInfo/CodeView/Line.h"
34 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
35 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
36 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
37 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
38 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
39 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
40 #include "llvm/DebugInfo/CodeView/TypeHashing.h"
41 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
42 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
43 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
44 #include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
45 #include "llvm/Object/COFF.h"
46 #include "llvm/Object/ObjectFile.h"
47 #include "llvm/Support/BinaryStreamReader.h"
48 #include "llvm/Support/Casting.h"
49 #include "llvm/Support/Compiler.h"
50 #include "llvm/Support/ConvertUTF.h"
51 #include "llvm/Support/FormatVariadic.h"
52 #include "llvm/Support/ScopedPrinter.h"
53 #include "llvm/Support/Win64EH.h"
54 #include "llvm/Support/raw_ostream.h"
57 using namespace llvm::object
;
58 using namespace llvm::codeview
;
59 using namespace llvm::support
;
60 using namespace llvm::Win64EH
;
64 struct LoadConfigTables
{
65 uint64_t SEHTableVA
= 0;
66 uint64_t SEHTableCount
= 0;
67 uint32_t GuardFlags
= 0;
68 uint64_t GuardFidTableVA
= 0;
69 uint64_t GuardFidTableCount
= 0;
70 uint64_t GuardLJmpTableVA
= 0;
71 uint64_t GuardLJmpTableCount
= 0;
74 class COFFDumper
: public ObjDumper
{
76 friend class COFFObjectDumpDelegate
;
77 COFFDumper(const llvm::object::COFFObjectFile
*Obj
, ScopedPrinter
&Writer
)
78 : ObjDumper(Writer
), Obj(Obj
), Writer(Writer
), Types(100) {}
80 void printFileHeaders() override
;
81 void printSections() override
;
82 void printRelocations() override
;
83 void printSymbols() override
;
84 void printDynamicSymbols() override
;
85 void printUnwindInfo() override
;
87 void printNeededLibraries() override
;
89 void printCOFFImports() override
;
90 void printCOFFExports() override
;
91 void printCOFFDirectives() override
;
92 void printCOFFBaseReloc() override
;
93 void printCOFFDebugDirectory() override
;
94 void printCOFFResources() override
;
95 void printCOFFLoadConfig() override
;
96 void printCodeViewDebugInfo() override
;
98 mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder
&CVIDs
,
99 llvm::codeview::MergingTypeTableBuilder
&CVTypes
) override
;
100 void printStackMap() const override
;
102 void printSymbol(const SymbolRef
&Sym
);
103 void printRelocation(const SectionRef
&Section
, const RelocationRef
&Reloc
,
105 void printDataDirectory(uint32_t Index
, const std::string
&FieldName
);
107 void printDOSHeader(const dos_header
*DH
);
108 template <class PEHeader
> void printPEHeader(const PEHeader
*Hdr
);
109 void printBaseOfDataField(const pe32_header
*Hdr
);
110 void printBaseOfDataField(const pe32plus_header
*Hdr
);
111 template <typename T
>
112 void printCOFFLoadConfig(const T
*Conf
, LoadConfigTables
&Tables
);
113 typedef void (*PrintExtraCB
)(raw_ostream
&, const uint8_t *);
114 void printRVATable(uint64_t TableVA
, uint64_t Count
, uint64_t EntrySize
,
115 PrintExtraCB PrintExtra
= 0);
117 void printCodeViewSymbolSection(StringRef SectionName
, const SectionRef
&Section
);
118 void printCodeViewTypeSection(StringRef SectionName
, const SectionRef
&Section
);
119 StringRef
getTypeName(TypeIndex Ty
);
120 StringRef
getFileNameForFileOffset(uint32_t FileOffset
);
121 void printFileNameForOffset(StringRef Label
, uint32_t FileOffset
);
122 void printTypeIndex(StringRef FieldName
, TypeIndex TI
) {
123 // Forward to CVTypeDumper for simplicity.
124 codeview::printTypeIndex(Writer
, FieldName
, TI
, Types
);
127 void printCodeViewSymbolsSubsection(StringRef Subsection
,
128 const SectionRef
&Section
,
129 StringRef SectionContents
);
131 void printCodeViewFileChecksums(StringRef Subsection
);
133 void printCodeViewInlineeLines(StringRef Subsection
);
135 void printRelocatedField(StringRef Label
, const coff_section
*Sec
,
136 uint32_t RelocOffset
, uint32_t Offset
,
137 StringRef
*RelocSym
= nullptr);
139 uint32_t countTotalTableEntries(ResourceSectionRef RSF
,
140 const coff_resource_dir_table
&Table
,
143 void printResourceDirectoryTable(ResourceSectionRef RSF
,
144 const coff_resource_dir_table
&Table
,
147 void printBinaryBlockWithRelocs(StringRef Label
, const SectionRef
&Sec
,
148 StringRef SectionContents
, StringRef Block
);
150 /// Given a .debug$S section, find the string table and file checksum table.
151 void initializeFileAndStringTables(BinaryStreamReader
&Reader
);
153 void cacheRelocations();
155 std::error_code
resolveSymbol(const coff_section
*Section
, uint64_t Offset
,
157 std::error_code
resolveSymbolName(const coff_section
*Section
,
158 uint64_t Offset
, StringRef
&Name
);
159 std::error_code
resolveSymbolName(const coff_section
*Section
,
160 StringRef SectionContents
,
161 const void *RelocPtr
, StringRef
&Name
);
162 void printImportedSymbols(iterator_range
<imported_symbol_iterator
> Range
);
163 void printDelayImportedSymbols(
164 const DelayImportDirectoryEntryRef
&I
,
165 iterator_range
<imported_symbol_iterator
> Range
);
166 ErrorOr
<const coff_resource_dir_entry
&>
167 getResourceDirectoryTableEntry(const coff_resource_dir_table
&Table
,
170 typedef DenseMap
<const coff_section
*, std::vector
<RelocationRef
> > RelocMapTy
;
172 const llvm::object::COFFObjectFile
*Obj
;
173 bool RelocCached
= false;
176 DebugChecksumsSubsectionRef CVFileChecksumTable
;
178 DebugStringTableSubsectionRef CVStringTable
;
180 ScopedPrinter
&Writer
;
181 BinaryByteStream TypeContents
;
182 LazyRandomTypeCollection Types
;
185 class COFFObjectDumpDelegate
: public SymbolDumpDelegate
{
187 COFFObjectDumpDelegate(COFFDumper
&CD
, const SectionRef
&SR
,
188 const COFFObjectFile
*Obj
, StringRef SectionContents
)
189 : CD(CD
), SR(SR
), SectionContents(SectionContents
) {
190 Sec
= Obj
->getCOFFSection(SR
);
193 uint32_t getRecordOffset(BinaryStreamReader Reader
) override
{
194 ArrayRef
<uint8_t> Data
;
195 if (auto EC
= Reader
.readLongestContiguousChunk(Data
)) {
196 llvm::consumeError(std::move(EC
));
199 return Data
.data() - SectionContents
.bytes_begin();
202 void printRelocatedField(StringRef Label
, uint32_t RelocOffset
,
203 uint32_t Offset
, StringRef
*RelocSym
) override
{
204 CD
.printRelocatedField(Label
, Sec
, RelocOffset
, Offset
, RelocSym
);
207 void printBinaryBlockWithRelocs(StringRef Label
,
208 ArrayRef
<uint8_t> Block
) override
{
209 StringRef
SBlock(reinterpret_cast<const char *>(Block
.data()),
211 if (opts::CodeViewSubsectionBytes
)
212 CD
.printBinaryBlockWithRelocs(Label
, SR
, SectionContents
, SBlock
);
215 StringRef
getFileNameForFileOffset(uint32_t FileOffset
) override
{
216 return CD
.getFileNameForFileOffset(FileOffset
);
219 DebugStringTableSubsectionRef
getStringTable() override
{
220 return CD
.CVStringTable
;
225 const SectionRef
&SR
;
226 const coff_section
*Sec
;
227 StringRef SectionContents
;
234 std::error_code
createCOFFDumper(const object::ObjectFile
*Obj
,
235 ScopedPrinter
&Writer
,
236 std::unique_ptr
<ObjDumper
> &Result
) {
237 const COFFObjectFile
*COFFObj
= dyn_cast
<COFFObjectFile
>(Obj
);
239 return readobj_error::unsupported_obj_file_format
;
241 Result
.reset(new COFFDumper(COFFObj
, Writer
));
242 return readobj_error::success
;
247 // Given a section and an offset into this section the function returns the
248 // symbol used for the relocation at the offset.
249 std::error_code
COFFDumper::resolveSymbol(const coff_section
*Section
,
250 uint64_t Offset
, SymbolRef
&Sym
) {
252 const auto &Relocations
= RelocMap
[Section
];
253 auto SymI
= Obj
->symbol_end();
254 for (const auto &Relocation
: Relocations
) {
255 uint64_t RelocationOffset
= Relocation
.getOffset();
257 if (RelocationOffset
== Offset
) {
258 SymI
= Relocation
.getSymbol();
262 if (SymI
== Obj
->symbol_end())
263 return readobj_error::unknown_symbol
;
265 return readobj_error::success
;
268 // Given a section and an offset into this section the function returns the name
269 // of the symbol used for the relocation at the offset.
270 std::error_code
COFFDumper::resolveSymbolName(const coff_section
*Section
,
274 if (std::error_code EC
= resolveSymbol(Section
, Offset
, Symbol
))
276 Expected
<StringRef
> NameOrErr
= Symbol
.getName();
278 return errorToErrorCode(NameOrErr
.takeError());
280 return std::error_code();
283 // Helper for when you have a pointer to real data and you want to know about
284 // relocations against it.
285 std::error_code
COFFDumper::resolveSymbolName(const coff_section
*Section
,
286 StringRef SectionContents
,
287 const void *RelocPtr
,
289 assert(SectionContents
.data() < RelocPtr
&&
290 RelocPtr
< SectionContents
.data() + SectionContents
.size() &&
291 "pointer to relocated object is not in section");
292 uint64_t Offset
= ptrdiff_t(reinterpret_cast<const char *>(RelocPtr
) -
293 SectionContents
.data());
294 return resolveSymbolName(Section
, Offset
, Name
);
297 void COFFDumper::printRelocatedField(StringRef Label
, const coff_section
*Sec
,
298 uint32_t RelocOffset
, uint32_t Offset
,
299 StringRef
*RelocSym
) {
300 StringRef SymStorage
;
301 StringRef
&Symbol
= RelocSym
? *RelocSym
: SymStorage
;
302 if (!resolveSymbolName(Sec
, RelocOffset
, Symbol
))
303 W
.printSymbolOffset(Label
, Symbol
, Offset
);
305 W
.printHex(Label
, RelocOffset
);
308 void COFFDumper::printBinaryBlockWithRelocs(StringRef Label
,
309 const SectionRef
&Sec
,
310 StringRef SectionContents
,
312 W
.printBinaryBlock(Label
, Block
);
314 assert(SectionContents
.begin() < Block
.begin() &&
315 SectionContents
.end() >= Block
.end() &&
316 "Block is not contained in SectionContents");
317 uint64_t OffsetStart
= Block
.data() - SectionContents
.data();
318 uint64_t OffsetEnd
= OffsetStart
+ Block
.size();
322 ListScope
D(W
, "BlockRelocations");
323 const coff_section
*Section
= Obj
->getCOFFSection(Sec
);
324 const auto &Relocations
= RelocMap
[Section
];
325 for (const auto &Relocation
: Relocations
) {
326 uint64_t RelocationOffset
= Relocation
.getOffset();
327 if (OffsetStart
<= RelocationOffset
&& RelocationOffset
< OffsetEnd
)
328 printRelocation(Sec
, Relocation
, OffsetStart
);
332 static const EnumEntry
<COFF::MachineTypes
> ImageFileMachineType
[] = {
333 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_UNKNOWN
),
334 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_AM33
),
335 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_AMD64
),
336 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM
),
337 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM64
),
338 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARMNT
),
339 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_EBC
),
340 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_I386
),
341 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_IA64
),
342 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_M32R
),
343 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPS16
),
344 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPSFPU
),
345 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPSFPU16
),
346 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_POWERPC
),
347 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_POWERPCFP
),
348 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_R4000
),
349 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH3
),
350 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH3DSP
),
351 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH4
),
352 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH5
),
353 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_THUMB
),
354 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_WCEMIPSV2
)
357 static const EnumEntry
<COFF::Characteristics
> ImageFileCharacteristics
[] = {
358 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_RELOCS_STRIPPED
),
359 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_EXECUTABLE_IMAGE
),
360 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LINE_NUMS_STRIPPED
),
361 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LOCAL_SYMS_STRIPPED
),
362 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_AGGRESSIVE_WS_TRIM
),
363 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LARGE_ADDRESS_AWARE
),
364 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_BYTES_REVERSED_LO
),
365 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_32BIT_MACHINE
),
366 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_DEBUG_STRIPPED
),
367 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
),
368 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_NET_RUN_FROM_SWAP
),
369 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_SYSTEM
),
370 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_DLL
),
371 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_UP_SYSTEM_ONLY
),
372 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_BYTES_REVERSED_HI
)
375 static const EnumEntry
<COFF::WindowsSubsystem
> PEWindowsSubsystem
[] = {
376 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_UNKNOWN
),
377 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_NATIVE
),
378 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_GUI
),
379 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_CUI
),
380 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_POSIX_CUI
),
381 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
),
382 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_APPLICATION
),
383 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
),
384 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
),
385 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_ROM
),
386 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_XBOX
),
389 static const EnumEntry
<COFF::DLLCharacteristics
> PEDLLCharacteristics
[] = {
390 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
),
391 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
),
392 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
),
393 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
),
394 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
),
395 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_SEH
),
396 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_BIND
),
397 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER
),
398 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER
),
399 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_GUARD_CF
),
400 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
),
403 static const EnumEntry
<COFF::SectionCharacteristics
>
404 ImageSectionCharacteristics
[] = {
405 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_TYPE_NOLOAD
),
406 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_TYPE_NO_PAD
),
407 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_CODE
),
408 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_INITIALIZED_DATA
),
409 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_UNINITIALIZED_DATA
),
410 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_OTHER
),
411 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_INFO
),
412 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_REMOVE
),
413 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_COMDAT
),
414 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_GPREL
),
415 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_PURGEABLE
),
416 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_16BIT
),
417 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_LOCKED
),
418 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_PRELOAD
),
419 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_1BYTES
),
420 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_2BYTES
),
421 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_4BYTES
),
422 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_8BYTES
),
423 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_16BYTES
),
424 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_32BYTES
),
425 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_64BYTES
),
426 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_128BYTES
),
427 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_256BYTES
),
428 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_512BYTES
),
429 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_1024BYTES
),
430 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_2048BYTES
),
431 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_4096BYTES
),
432 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_8192BYTES
),
433 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_NRELOC_OVFL
),
434 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_DISCARDABLE
),
435 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_NOT_CACHED
),
436 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_NOT_PAGED
),
437 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_SHARED
),
438 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_EXECUTE
),
439 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_READ
),
440 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_WRITE
)
443 static const EnumEntry
<COFF::SymbolBaseType
> ImageSymType
[] = {
444 { "Null" , COFF::IMAGE_SYM_TYPE_NULL
},
445 { "Void" , COFF::IMAGE_SYM_TYPE_VOID
},
446 { "Char" , COFF::IMAGE_SYM_TYPE_CHAR
},
447 { "Short" , COFF::IMAGE_SYM_TYPE_SHORT
},
448 { "Int" , COFF::IMAGE_SYM_TYPE_INT
},
449 { "Long" , COFF::IMAGE_SYM_TYPE_LONG
},
450 { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT
},
451 { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE
},
452 { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT
},
453 { "Union" , COFF::IMAGE_SYM_TYPE_UNION
},
454 { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM
},
455 { "MOE" , COFF::IMAGE_SYM_TYPE_MOE
},
456 { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE
},
457 { "Word" , COFF::IMAGE_SYM_TYPE_WORD
},
458 { "UInt" , COFF::IMAGE_SYM_TYPE_UINT
},
459 { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD
}
462 static const EnumEntry
<COFF::SymbolComplexType
> ImageSymDType
[] = {
463 { "Null" , COFF::IMAGE_SYM_DTYPE_NULL
},
464 { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER
},
465 { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION
},
466 { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY
}
469 static const EnumEntry
<COFF::SymbolStorageClass
> ImageSymClass
[] = {
470 { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION
},
471 { "Null" , COFF::IMAGE_SYM_CLASS_NULL
},
472 { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC
},
473 { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL
},
474 { "Static" , COFF::IMAGE_SYM_CLASS_STATIC
},
475 { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER
},
476 { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF
},
477 { "Label" , COFF::IMAGE_SYM_CLASS_LABEL
},
478 { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL
},
479 { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT
},
480 { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT
},
481 { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG
},
482 { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION
},
483 { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG
},
484 { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION
},
485 { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC
},
486 { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG
},
487 { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM
},
488 { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM
},
489 { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD
},
490 { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK
},
491 { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION
},
492 { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT
},
493 { "File" , COFF::IMAGE_SYM_CLASS_FILE
},
494 { "Section" , COFF::IMAGE_SYM_CLASS_SECTION
},
495 { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL
},
496 { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN
}
499 static const EnumEntry
<COFF::COMDATType
> ImageCOMDATSelect
[] = {
500 { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES
},
501 { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY
},
502 { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE
},
503 { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH
},
504 { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
},
505 { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST
},
506 { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST
}
509 static const EnumEntry
<COFF::DebugType
> ImageDebugType
[] = {
510 { "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN
},
511 { "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF
},
512 { "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW
},
513 { "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO
},
514 { "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC
},
515 { "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION
},
516 { "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP
},
517 { "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC
},
518 { "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
},
519 { "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND
},
520 { "Reserved10" , COFF::IMAGE_DEBUG_TYPE_RESERVED10
},
521 { "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID
},
522 { "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE
},
523 { "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO
},
524 { "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG
},
525 { "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX
},
526 { "Repro" , COFF::IMAGE_DEBUG_TYPE_REPRO
},
529 static const EnumEntry
<COFF::WeakExternalCharacteristics
>
530 WeakExternalCharacteristics
[] = {
531 { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY
},
532 { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
},
533 { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
}
536 static const EnumEntry
<uint32_t> SubSectionTypes
[] = {
537 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, Symbols
),
538 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, Lines
),
539 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, StringTable
),
540 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FileChecksums
),
541 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FrameData
),
542 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, InlineeLines
),
543 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CrossScopeImports
),
544 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CrossScopeExports
),
545 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, ILLines
),
546 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FuncMDTokenMap
),
547 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, TypeMDTokenMap
),
548 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, MergedAssemblyInput
),
549 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CoffSymbolRVA
),
552 static const EnumEntry
<uint32_t> FrameDataFlags
[] = {
553 LLVM_READOBJ_ENUM_ENT(FrameData
, HasSEH
),
554 LLVM_READOBJ_ENUM_ENT(FrameData
, HasEH
),
555 LLVM_READOBJ_ENUM_ENT(FrameData
, IsFunctionStart
),
558 static const EnumEntry
<uint8_t> FileChecksumKindNames
[] = {
559 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, None
),
560 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, MD5
),
561 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, SHA1
),
562 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, SHA256
),
565 static const EnumEntry
<COFF::ResourceTypeID
> ResourceTypeNames
[]{
566 {"kRT_CURSOR (ID 1)", COFF::RID_Cursor
},
567 {"kRT_BITMAP (ID 2)", COFF::RID_Bitmap
},
568 {"kRT_ICON (ID 3)", COFF::RID_Icon
},
569 {"kRT_MENU (ID 4)", COFF::RID_Menu
},
570 {"kRT_DIALOG (ID 5)", COFF::RID_Dialog
},
571 {"kRT_STRING (ID 6)", COFF::RID_String
},
572 {"kRT_FONTDIR (ID 7)", COFF::RID_FontDir
},
573 {"kRT_FONT (ID 8)", COFF::RID_Font
},
574 {"kRT_ACCELERATOR (ID 9)", COFF::RID_Accelerator
},
575 {"kRT_RCDATA (ID 10)", COFF::RID_RCData
},
576 {"kRT_MESSAGETABLE (ID 11)", COFF::RID_MessageTable
},
577 {"kRT_GROUP_CURSOR (ID 12)", COFF::RID_Group_Cursor
},
578 {"kRT_GROUP_ICON (ID 14)", COFF::RID_Group_Icon
},
579 {"kRT_VERSION (ID 16)", COFF::RID_Version
},
580 {"kRT_DLGINCLUDE (ID 17)", COFF::RID_DLGInclude
},
581 {"kRT_PLUGPLAY (ID 19)", COFF::RID_PlugPlay
},
582 {"kRT_VXD (ID 20)", COFF::RID_VXD
},
583 {"kRT_ANICURSOR (ID 21)", COFF::RID_AniCursor
},
584 {"kRT_ANIICON (ID 22)", COFF::RID_AniIcon
},
585 {"kRT_HTML (ID 23)", COFF::RID_HTML
},
586 {"kRT_MANIFEST (ID 24)", COFF::RID_Manifest
}};
588 template <typename T
>
589 static std::error_code
getSymbolAuxData(const COFFObjectFile
*Obj
,
590 COFFSymbolRef Symbol
,
591 uint8_t AuxSymbolIdx
, const T
*&Aux
) {
592 ArrayRef
<uint8_t> AuxData
= Obj
->getSymbolAuxData(Symbol
);
593 AuxData
= AuxData
.slice(AuxSymbolIdx
* Obj
->getSymbolTableEntrySize());
594 Aux
= reinterpret_cast<const T
*>(AuxData
.data());
595 return readobj_error::success
;
598 void COFFDumper::cacheRelocations() {
603 for (const SectionRef
&S
: Obj
->sections()) {
604 const coff_section
*Section
= Obj
->getCOFFSection(S
);
606 for (const RelocationRef
&Reloc
: S
.relocations())
607 RelocMap
[Section
].push_back(Reloc
);
609 // Sort relocations by address.
610 llvm::sort(RelocMap
[Section
].begin(), RelocMap
[Section
].end(),
615 void COFFDumper::printDataDirectory(uint32_t Index
, const std::string
&FieldName
) {
616 const data_directory
*Data
;
617 if (Obj
->getDataDirectory(Index
, Data
))
619 W
.printHex(FieldName
+ "RVA", Data
->RelativeVirtualAddress
);
620 W
.printHex(FieldName
+ "Size", Data
->Size
);
623 void COFFDumper::printFileHeaders() {
624 time_t TDS
= Obj
->getTimeDateStamp();
625 char FormattedTime
[20] = { };
626 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
629 DictScope
D(W
, "ImageFileHeader");
630 W
.printEnum ("Machine", Obj
->getMachine(),
631 makeArrayRef(ImageFileMachineType
));
632 W
.printNumber("SectionCount", Obj
->getNumberOfSections());
633 W
.printHex ("TimeDateStamp", FormattedTime
, Obj
->getTimeDateStamp());
634 W
.printHex ("PointerToSymbolTable", Obj
->getPointerToSymbolTable());
635 W
.printNumber("SymbolCount", Obj
->getNumberOfSymbols());
636 W
.printNumber("OptionalHeaderSize", Obj
->getSizeOfOptionalHeader());
637 W
.printFlags ("Characteristics", Obj
->getCharacteristics(),
638 makeArrayRef(ImageFileCharacteristics
));
641 // Print PE header. This header does not exist if this is an object file and
642 // not an executable.
643 const pe32_header
*PEHeader
= nullptr;
644 error(Obj
->getPE32Header(PEHeader
));
646 printPEHeader
<pe32_header
>(PEHeader
);
648 const pe32plus_header
*PEPlusHeader
= nullptr;
649 error(Obj
->getPE32PlusHeader(PEPlusHeader
));
651 printPEHeader
<pe32plus_header
>(PEPlusHeader
);
653 if (const dos_header
*DH
= Obj
->getDOSHeader())
657 void COFFDumper::printDOSHeader(const dos_header
*DH
) {
658 DictScope
D(W
, "DOSHeader");
659 W
.printString("Magic", StringRef(DH
->Magic
, sizeof(DH
->Magic
)));
660 W
.printNumber("UsedBytesInTheLastPage", DH
->UsedBytesInTheLastPage
);
661 W
.printNumber("FileSizeInPages", DH
->FileSizeInPages
);
662 W
.printNumber("NumberOfRelocationItems", DH
->NumberOfRelocationItems
);
663 W
.printNumber("HeaderSizeInParagraphs", DH
->HeaderSizeInParagraphs
);
664 W
.printNumber("MinimumExtraParagraphs", DH
->MinimumExtraParagraphs
);
665 W
.printNumber("MaximumExtraParagraphs", DH
->MaximumExtraParagraphs
);
666 W
.printNumber("InitialRelativeSS", DH
->InitialRelativeSS
);
667 W
.printNumber("InitialSP", DH
->InitialSP
);
668 W
.printNumber("Checksum", DH
->Checksum
);
669 W
.printNumber("InitialIP", DH
->InitialIP
);
670 W
.printNumber("InitialRelativeCS", DH
->InitialRelativeCS
);
671 W
.printNumber("AddressOfRelocationTable", DH
->AddressOfRelocationTable
);
672 W
.printNumber("OverlayNumber", DH
->OverlayNumber
);
673 W
.printNumber("OEMid", DH
->OEMid
);
674 W
.printNumber("OEMinfo", DH
->OEMinfo
);
675 W
.printNumber("AddressOfNewExeHeader", DH
->AddressOfNewExeHeader
);
678 template <class PEHeader
>
679 void COFFDumper::printPEHeader(const PEHeader
*Hdr
) {
680 DictScope
D(W
, "ImageOptionalHeader");
681 W
.printHex ("Magic", Hdr
->Magic
);
682 W
.printNumber("MajorLinkerVersion", Hdr
->MajorLinkerVersion
);
683 W
.printNumber("MinorLinkerVersion", Hdr
->MinorLinkerVersion
);
684 W
.printNumber("SizeOfCode", Hdr
->SizeOfCode
);
685 W
.printNumber("SizeOfInitializedData", Hdr
->SizeOfInitializedData
);
686 W
.printNumber("SizeOfUninitializedData", Hdr
->SizeOfUninitializedData
);
687 W
.printHex ("AddressOfEntryPoint", Hdr
->AddressOfEntryPoint
);
688 W
.printHex ("BaseOfCode", Hdr
->BaseOfCode
);
689 printBaseOfDataField(Hdr
);
690 W
.printHex ("ImageBase", Hdr
->ImageBase
);
691 W
.printNumber("SectionAlignment", Hdr
->SectionAlignment
);
692 W
.printNumber("FileAlignment", Hdr
->FileAlignment
);
693 W
.printNumber("MajorOperatingSystemVersion",
694 Hdr
->MajorOperatingSystemVersion
);
695 W
.printNumber("MinorOperatingSystemVersion",
696 Hdr
->MinorOperatingSystemVersion
);
697 W
.printNumber("MajorImageVersion", Hdr
->MajorImageVersion
);
698 W
.printNumber("MinorImageVersion", Hdr
->MinorImageVersion
);
699 W
.printNumber("MajorSubsystemVersion", Hdr
->MajorSubsystemVersion
);
700 W
.printNumber("MinorSubsystemVersion", Hdr
->MinorSubsystemVersion
);
701 W
.printNumber("SizeOfImage", Hdr
->SizeOfImage
);
702 W
.printNumber("SizeOfHeaders", Hdr
->SizeOfHeaders
);
703 W
.printEnum ("Subsystem", Hdr
->Subsystem
, makeArrayRef(PEWindowsSubsystem
));
704 W
.printFlags ("Characteristics", Hdr
->DLLCharacteristics
,
705 makeArrayRef(PEDLLCharacteristics
));
706 W
.printNumber("SizeOfStackReserve", Hdr
->SizeOfStackReserve
);
707 W
.printNumber("SizeOfStackCommit", Hdr
->SizeOfStackCommit
);
708 W
.printNumber("SizeOfHeapReserve", Hdr
->SizeOfHeapReserve
);
709 W
.printNumber("SizeOfHeapCommit", Hdr
->SizeOfHeapCommit
);
710 W
.printNumber("NumberOfRvaAndSize", Hdr
->NumberOfRvaAndSize
);
712 if (Hdr
->NumberOfRvaAndSize
> 0) {
713 DictScope
D(W
, "DataDirectory");
714 static const char * const directory
[] = {
715 "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
716 "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
717 "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
718 "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
721 for (uint32_t i
= 0; i
< Hdr
->NumberOfRvaAndSize
; ++i
)
722 printDataDirectory(i
, directory
[i
]);
726 void COFFDumper::printCOFFDebugDirectory() {
727 ListScope
LS(W
, "DebugDirectory");
728 for (const debug_directory
&D
: Obj
->debug_directories()) {
729 char FormattedTime
[20] = {};
730 time_t TDS
= D
.TimeDateStamp
;
731 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
732 DictScope
S(W
, "DebugEntry");
733 W
.printHex("Characteristics", D
.Characteristics
);
734 W
.printHex("TimeDateStamp", FormattedTime
, D
.TimeDateStamp
);
735 W
.printHex("MajorVersion", D
.MajorVersion
);
736 W
.printHex("MinorVersion", D
.MinorVersion
);
737 W
.printEnum("Type", D
.Type
, makeArrayRef(ImageDebugType
));
738 W
.printHex("SizeOfData", D
.SizeOfData
);
739 W
.printHex("AddressOfRawData", D
.AddressOfRawData
);
740 W
.printHex("PointerToRawData", D
.PointerToRawData
);
741 if (D
.Type
== COFF::IMAGE_DEBUG_TYPE_CODEVIEW
) {
742 const codeview::DebugInfo
*DebugInfo
;
743 StringRef PDBFileName
;
744 error(Obj
->getDebugPDBInfo(&D
, DebugInfo
, PDBFileName
));
745 DictScope
PDBScope(W
, "PDBInfo");
746 W
.printHex("PDBSignature", DebugInfo
->Signature
.CVSignature
);
747 if (DebugInfo
->Signature
.CVSignature
== OMF::Signature::PDB70
) {
748 W
.printBinary("PDBGUID", makeArrayRef(DebugInfo
->PDB70
.Signature
));
749 W
.printNumber("PDBAge", DebugInfo
->PDB70
.Age
);
750 W
.printString("PDBFileName", PDBFileName
);
753 // FIXME: Type values of 12 and 13 are commonly observed but are not in
754 // the documented type enum. Figure out what they mean.
755 ArrayRef
<uint8_t> RawData
;
757 Obj
->getRvaAndSizeAsBytes(D
.AddressOfRawData
, D
.SizeOfData
, RawData
));
758 W
.printBinaryBlock("RawData", RawData
);
763 void COFFDumper::printRVATable(uint64_t TableVA
, uint64_t Count
,
764 uint64_t EntrySize
, PrintExtraCB PrintExtra
) {
765 uintptr_t TableStart
, TableEnd
;
766 error(Obj
->getVaPtr(TableVA
, TableStart
));
767 error(Obj
->getVaPtr(TableVA
+ Count
* EntrySize
- 1, TableEnd
));
769 for (uintptr_t I
= TableStart
; I
< TableEnd
; I
+= EntrySize
) {
770 uint32_t RVA
= *reinterpret_cast<const ulittle32_t
*>(I
);
771 raw_ostream
&OS
= W
.startLine();
772 OS
<< W
.hex(Obj
->getImageBase() + RVA
);
774 PrintExtra(OS
, reinterpret_cast<const uint8_t *>(I
));
779 void COFFDumper::printCOFFLoadConfig() {
780 LoadConfigTables Tables
;
782 printCOFFLoadConfig(Obj
->getLoadConfig64(), Tables
);
784 printCOFFLoadConfig(Obj
->getLoadConfig32(), Tables
);
786 if (Tables
.SEHTableVA
) {
787 ListScope
LS(W
, "SEHTable");
788 printRVATable(Tables
.SEHTableVA
, Tables
.SEHTableCount
, 4);
791 if (Tables
.GuardFidTableVA
) {
792 ListScope
LS(W
, "GuardFidTable");
793 if (Tables
.GuardFlags
& uint32_t(coff_guard_flags::FidTableHasFlags
)) {
794 auto PrintGuardFlags
= [](raw_ostream
&OS
, const uint8_t *Entry
) {
795 uint8_t Flags
= *reinterpret_cast<const uint8_t *>(Entry
+ 4);
797 OS
<< " flags " << utohexstr(Flags
);
799 printRVATable(Tables
.GuardFidTableVA
, Tables
.GuardFidTableCount
, 5,
802 printRVATable(Tables
.GuardFidTableVA
, Tables
.GuardFidTableCount
, 4);
806 if (Tables
.GuardLJmpTableVA
) {
807 ListScope
LS(W
, "GuardLJmpTable");
808 printRVATable(Tables
.GuardLJmpTableVA
, Tables
.GuardLJmpTableCount
, 4);
812 template <typename T
>
813 void COFFDumper::printCOFFLoadConfig(const T
*Conf
, LoadConfigTables
&Tables
) {
817 ListScope
LS(W
, "LoadConfig");
818 char FormattedTime
[20] = {};
819 time_t TDS
= Conf
->TimeDateStamp
;
820 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
821 W
.printHex("Size", Conf
->Size
);
823 // Print everything before SecurityCookie. The vast majority of images today
824 // have all these fields.
825 if (Conf
->Size
< offsetof(T
, SEHandlerTable
))
827 W
.printHex("TimeDateStamp", FormattedTime
, TDS
);
828 W
.printHex("MajorVersion", Conf
->MajorVersion
);
829 W
.printHex("MinorVersion", Conf
->MinorVersion
);
830 W
.printHex("GlobalFlagsClear", Conf
->GlobalFlagsClear
);
831 W
.printHex("GlobalFlagsSet", Conf
->GlobalFlagsSet
);
832 W
.printHex("CriticalSectionDefaultTimeout",
833 Conf
->CriticalSectionDefaultTimeout
);
834 W
.printHex("DeCommitFreeBlockThreshold", Conf
->DeCommitFreeBlockThreshold
);
835 W
.printHex("DeCommitTotalFreeThreshold", Conf
->DeCommitTotalFreeThreshold
);
836 W
.printHex("LockPrefixTable", Conf
->LockPrefixTable
);
837 W
.printHex("MaximumAllocationSize", Conf
->MaximumAllocationSize
);
838 W
.printHex("VirtualMemoryThreshold", Conf
->VirtualMemoryThreshold
);
839 W
.printHex("ProcessHeapFlags", Conf
->ProcessHeapFlags
);
840 W
.printHex("ProcessAffinityMask", Conf
->ProcessAffinityMask
);
841 W
.printHex("CSDVersion", Conf
->CSDVersion
);
842 W
.printHex("DependentLoadFlags", Conf
->DependentLoadFlags
);
843 W
.printHex("EditList", Conf
->EditList
);
844 W
.printHex("SecurityCookie", Conf
->SecurityCookie
);
846 // Print the safe SEH table if present.
847 if (Conf
->Size
< offsetof(coff_load_configuration32
, GuardCFCheckFunction
))
849 W
.printHex("SEHandlerTable", Conf
->SEHandlerTable
);
850 W
.printNumber("SEHandlerCount", Conf
->SEHandlerCount
);
852 Tables
.SEHTableVA
= Conf
->SEHandlerTable
;
853 Tables
.SEHTableCount
= Conf
->SEHandlerCount
;
855 // Print everything before CodeIntegrity. (2015)
856 if (Conf
->Size
< offsetof(T
, CodeIntegrity
))
858 W
.printHex("GuardCFCheckFunction", Conf
->GuardCFCheckFunction
);
859 W
.printHex("GuardCFCheckDispatch", Conf
->GuardCFCheckDispatch
);
860 W
.printHex("GuardCFFunctionTable", Conf
->GuardCFFunctionTable
);
861 W
.printNumber("GuardCFFunctionCount", Conf
->GuardCFFunctionCount
);
862 W
.printHex("GuardFlags", Conf
->GuardFlags
);
864 Tables
.GuardFidTableVA
= Conf
->GuardCFFunctionTable
;
865 Tables
.GuardFidTableCount
= Conf
->GuardCFFunctionCount
;
866 Tables
.GuardFlags
= Conf
->GuardFlags
;
868 // Print the rest. (2017)
869 if (Conf
->Size
< sizeof(T
))
871 W
.printHex("GuardAddressTakenIatEntryTable",
872 Conf
->GuardAddressTakenIatEntryTable
);
873 W
.printNumber("GuardAddressTakenIatEntryCount",
874 Conf
->GuardAddressTakenIatEntryCount
);
875 W
.printHex("GuardLongJumpTargetTable", Conf
->GuardLongJumpTargetTable
);
876 W
.printNumber("GuardLongJumpTargetCount", Conf
->GuardLongJumpTargetCount
);
877 W
.printHex("DynamicValueRelocTable", Conf
->DynamicValueRelocTable
);
878 W
.printHex("CHPEMetadataPointer", Conf
->CHPEMetadataPointer
);
879 W
.printHex("GuardRFFailureRoutine", Conf
->GuardRFFailureRoutine
);
880 W
.printHex("GuardRFFailureRoutineFunctionPointer",
881 Conf
->GuardRFFailureRoutineFunctionPointer
);
882 W
.printHex("DynamicValueRelocTableOffset",
883 Conf
->DynamicValueRelocTableOffset
);
884 W
.printNumber("DynamicValueRelocTableSection",
885 Conf
->DynamicValueRelocTableSection
);
886 W
.printHex("GuardRFVerifyStackPointerFunctionPointer",
887 Conf
->GuardRFVerifyStackPointerFunctionPointer
);
888 W
.printHex("HotPatchTableOffset", Conf
->HotPatchTableOffset
);
890 Tables
.GuardLJmpTableVA
= Conf
->GuardLongJumpTargetTable
;
891 Tables
.GuardLJmpTableCount
= Conf
->GuardLongJumpTargetCount
;
894 void COFFDumper::printBaseOfDataField(const pe32_header
*Hdr
) {
895 W
.printHex("BaseOfData", Hdr
->BaseOfData
);
898 void COFFDumper::printBaseOfDataField(const pe32plus_header
*) {}
900 void COFFDumper::printCodeViewDebugInfo() {
901 // Print types first to build CVUDTNames, then print symbols.
902 for (const SectionRef
&S
: Obj
->sections()) {
903 StringRef SectionName
;
904 error(S
.getName(SectionName
));
905 // .debug$T is a standard CodeView type section, while .debug$P is the same
906 // format but used for MSVC precompiled header object files.
907 if (SectionName
== ".debug$T" || SectionName
== ".debug$P")
908 printCodeViewTypeSection(SectionName
, S
);
910 for (const SectionRef
&S
: Obj
->sections()) {
911 StringRef SectionName
;
912 error(S
.getName(SectionName
));
913 if (SectionName
== ".debug$S")
914 printCodeViewSymbolSection(SectionName
, S
);
918 void COFFDumper::initializeFileAndStringTables(BinaryStreamReader
&Reader
) {
919 while (Reader
.bytesRemaining() > 0 &&
920 (!CVFileChecksumTable
.valid() || !CVStringTable
.valid())) {
921 // The section consists of a number of subsection in the following format:
922 // |SubSectionType|SubSectionSize|Contents...|
923 uint32_t SubType
, SubSectionSize
;
924 error(Reader
.readInteger(SubType
));
925 error(Reader
.readInteger(SubSectionSize
));
928 error(Reader
.readFixedString(Contents
, SubSectionSize
));
930 BinaryStreamRef
ST(Contents
, support::little
);
931 switch (DebugSubsectionKind(SubType
)) {
932 case DebugSubsectionKind::FileChecksums
:
933 error(CVFileChecksumTable
.initialize(ST
));
935 case DebugSubsectionKind::StringTable
:
936 error(CVStringTable
.initialize(ST
));
942 uint32_t PaddedSize
= alignTo(SubSectionSize
, 4);
943 error(Reader
.skip(PaddedSize
- SubSectionSize
));
947 void COFFDumper::printCodeViewSymbolSection(StringRef SectionName
,
948 const SectionRef
&Section
) {
949 StringRef SectionContents
;
950 error(Section
.getContents(SectionContents
));
951 StringRef Data
= SectionContents
;
953 SmallVector
<StringRef
, 10> FunctionNames
;
954 StringMap
<StringRef
> FunctionLineTables
;
956 ListScope
D(W
, "CodeViewDebugInfo");
957 // Print the section to allow correlation with printSections.
958 W
.printNumber("Section", SectionName
, Obj
->getSectionID(Section
));
961 error(consume(Data
, Magic
));
962 W
.printHex("Magic", Magic
);
963 if (Magic
!= COFF::DEBUG_SECTION_MAGIC
)
964 return error(object_error::parse_failed
);
966 BinaryStreamReader
FSReader(Data
, support::little
);
967 initializeFileAndStringTables(FSReader
);
969 // TODO: Convert this over to using ModuleSubstreamVisitor.
970 while (!Data
.empty()) {
971 // The section consists of a number of subsection in the following format:
972 // |SubSectionType|SubSectionSize|Contents...|
973 uint32_t SubType
, SubSectionSize
;
974 error(consume(Data
, SubType
));
975 error(consume(Data
, SubSectionSize
));
977 ListScope
S(W
, "Subsection");
978 W
.printEnum("SubSectionType", SubType
, makeArrayRef(SubSectionTypes
));
979 W
.printHex("SubSectionSize", SubSectionSize
);
981 // Get the contents of the subsection.
982 if (SubSectionSize
> Data
.size())
983 return error(object_error::parse_failed
);
984 StringRef Contents
= Data
.substr(0, SubSectionSize
);
986 // Add SubSectionSize to the current offset and align that offset to find
987 // the next subsection.
988 size_t SectionOffset
= Data
.data() - SectionContents
.data();
989 size_t NextOffset
= SectionOffset
+ SubSectionSize
;
990 NextOffset
= alignTo(NextOffset
, 4);
991 if (NextOffset
> SectionContents
.size())
992 return error(object_error::parse_failed
);
993 Data
= SectionContents
.drop_front(NextOffset
);
995 // Optionally print the subsection bytes in case our parsing gets confused
997 if (opts::CodeViewSubsectionBytes
)
998 printBinaryBlockWithRelocs("SubSectionContents", Section
, SectionContents
,
1001 switch (DebugSubsectionKind(SubType
)) {
1002 case DebugSubsectionKind::Symbols
:
1003 printCodeViewSymbolsSubsection(Contents
, Section
, SectionContents
);
1006 case DebugSubsectionKind::InlineeLines
:
1007 printCodeViewInlineeLines(Contents
);
1010 case DebugSubsectionKind::FileChecksums
:
1011 printCodeViewFileChecksums(Contents
);
1014 case DebugSubsectionKind::Lines
: {
1015 // Holds a PC to file:line table. Some data to parse this subsection is
1016 // stored in the other subsections, so just check sanity and store the
1017 // pointers for deferred processing.
1019 if (SubSectionSize
< 12) {
1020 // There should be at least three words to store two function
1021 // relocations and size of the code.
1022 error(object_error::parse_failed
);
1026 StringRef LinkageName
;
1027 error(resolveSymbolName(Obj
->getCOFFSection(Section
), SectionOffset
,
1029 W
.printString("LinkageName", LinkageName
);
1030 if (FunctionLineTables
.count(LinkageName
) != 0) {
1031 // Saw debug info for this function already?
1032 error(object_error::parse_failed
);
1036 FunctionLineTables
[LinkageName
] = Contents
;
1037 FunctionNames
.push_back(LinkageName
);
1040 case DebugSubsectionKind::FrameData
: {
1041 // First four bytes is a relocation against the function.
1042 BinaryStreamReader
SR(Contents
, llvm::support::little
);
1044 DebugFrameDataSubsectionRef FrameData
;
1045 error(FrameData
.initialize(SR
));
1047 StringRef LinkageName
;
1048 error(resolveSymbolName(Obj
->getCOFFSection(Section
), SectionContents
,
1049 FrameData
.getRelocPtr(), LinkageName
));
1050 W
.printString("LinkageName", LinkageName
);
1052 // To find the active frame description, search this array for the
1053 // smallest PC range that includes the current PC.
1054 for (const auto &FD
: FrameData
) {
1055 StringRef FrameFunc
= error(CVStringTable
.getString(FD
.FrameFunc
));
1057 DictScope
S(W
, "FrameData");
1058 W
.printHex("RvaStart", FD
.RvaStart
);
1059 W
.printHex("CodeSize", FD
.CodeSize
);
1060 W
.printHex("LocalSize", FD
.LocalSize
);
1061 W
.printHex("ParamsSize", FD
.ParamsSize
);
1062 W
.printHex("MaxStackSize", FD
.MaxStackSize
);
1063 W
.printString("FrameFunc", FrameFunc
);
1064 W
.printHex("PrologSize", FD
.PrologSize
);
1065 W
.printHex("SavedRegsSize", FD
.SavedRegsSize
);
1066 W
.printFlags("Flags", FD
.Flags
, makeArrayRef(FrameDataFlags
));
1071 // Do nothing for unrecognized subsections.
1078 // Dump the line tables now that we've read all the subsections and know all
1079 // the required information.
1080 for (unsigned I
= 0, E
= FunctionNames
.size(); I
!= E
; ++I
) {
1081 StringRef Name
= FunctionNames
[I
];
1082 ListScope
S(W
, "FunctionLineTable");
1083 W
.printString("LinkageName", Name
);
1085 BinaryStreamReader
Reader(FunctionLineTables
[Name
], support::little
);
1087 DebugLinesSubsectionRef LineInfo
;
1088 error(LineInfo
.initialize(Reader
));
1090 W
.printHex("Flags", LineInfo
.header()->Flags
);
1091 W
.printHex("CodeSize", LineInfo
.header()->CodeSize
);
1092 for (const auto &Entry
: LineInfo
) {
1094 ListScope
S(W
, "FilenameSegment");
1095 printFileNameForOffset("Filename", Entry
.NameIndex
);
1096 uint32_t ColumnIndex
= 0;
1097 for (const auto &Line
: Entry
.LineNumbers
) {
1098 if (Line
.Offset
>= LineInfo
.header()->CodeSize
) {
1099 error(object_error::parse_failed
);
1103 std::string PC
= formatv("+{0:X}", uint32_t(Line
.Offset
));
1104 ListScope
PCScope(W
, PC
);
1105 codeview::LineInfo
LI(Line
.Flags
);
1107 if (LI
.isAlwaysStepInto())
1108 W
.printString("StepInto", StringRef("Always"));
1109 else if (LI
.isNeverStepInto())
1110 W
.printString("StepInto", StringRef("Never"));
1112 W
.printNumber("LineNumberStart", LI
.getStartLine());
1113 W
.printNumber("LineNumberEndDelta", LI
.getLineDelta());
1114 W
.printBoolean("IsStatement", LI
.isStatement());
1115 if (LineInfo
.hasColumnInfo()) {
1116 W
.printNumber("ColStart", Entry
.Columns
[ColumnIndex
].StartColumn
);
1117 W
.printNumber("ColEnd", Entry
.Columns
[ColumnIndex
].EndColumn
);
1125 void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection
,
1126 const SectionRef
&Section
,
1127 StringRef SectionContents
) {
1128 ArrayRef
<uint8_t> BinaryData(Subsection
.bytes_begin(),
1129 Subsection
.bytes_end());
1130 auto CODD
= llvm::make_unique
<COFFObjectDumpDelegate
>(*this, Section
, Obj
,
1132 CVSymbolDumper
CVSD(W
, Types
, CodeViewContainer::ObjectFile
, std::move(CODD
),
1133 opts::CodeViewSubsectionBytes
);
1134 CVSymbolArray Symbols
;
1135 BinaryStreamReader
Reader(BinaryData
, llvm::support::little
);
1136 if (auto EC
= Reader
.readArray(Symbols
, Reader
.getLength())) {
1137 consumeError(std::move(EC
));
1139 error(object_error::parse_failed
);
1142 if (auto EC
= CVSD
.dump(Symbols
)) {
1144 error(std::move(EC
));
1149 void COFFDumper::printCodeViewFileChecksums(StringRef Subsection
) {
1150 BinaryStreamRef
Stream(Subsection
, llvm::support::little
);
1151 DebugChecksumsSubsectionRef Checksums
;
1152 error(Checksums
.initialize(Stream
));
1154 for (auto &FC
: Checksums
) {
1155 DictScope
S(W
, "FileChecksum");
1157 StringRef Filename
= error(CVStringTable
.getString(FC
.FileNameOffset
));
1158 W
.printHex("Filename", Filename
, FC
.FileNameOffset
);
1159 W
.printHex("ChecksumSize", FC
.Checksum
.size());
1160 W
.printEnum("ChecksumKind", uint8_t(FC
.Kind
),
1161 makeArrayRef(FileChecksumKindNames
));
1163 W
.printBinary("ChecksumBytes", FC
.Checksum
);
1167 void COFFDumper::printCodeViewInlineeLines(StringRef Subsection
) {
1168 BinaryStreamReader
SR(Subsection
, llvm::support::little
);
1169 DebugInlineeLinesSubsectionRef Lines
;
1170 error(Lines
.initialize(SR
));
1172 for (auto &Line
: Lines
) {
1173 DictScope
S(W
, "InlineeSourceLine");
1174 printTypeIndex("Inlinee", Line
.Header
->Inlinee
);
1175 printFileNameForOffset("FileID", Line
.Header
->FileID
);
1176 W
.printNumber("SourceLineNum", Line
.Header
->SourceLineNum
);
1178 if (Lines
.hasExtraFiles()) {
1179 W
.printNumber("ExtraFileCount", Line
.ExtraFiles
.size());
1180 ListScope
ExtraFiles(W
, "ExtraFiles");
1181 for (const auto &FID
: Line
.ExtraFiles
) {
1182 printFileNameForOffset("FileID", FID
);
1188 StringRef
COFFDumper::getFileNameForFileOffset(uint32_t FileOffset
) {
1189 // The file checksum subsection should precede all references to it.
1190 if (!CVFileChecksumTable
.valid() || !CVStringTable
.valid())
1191 error(object_error::parse_failed
);
1193 auto Iter
= CVFileChecksumTable
.getArray().at(FileOffset
);
1195 // Check if the file checksum table offset is valid.
1196 if (Iter
== CVFileChecksumTable
.end())
1197 error(object_error::parse_failed
);
1199 return error(CVStringTable
.getString(Iter
->FileNameOffset
));
1202 void COFFDumper::printFileNameForOffset(StringRef Label
, uint32_t FileOffset
) {
1203 W
.printHex(Label
, getFileNameForFileOffset(FileOffset
), FileOffset
);
1206 void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder
&CVIDs
,
1207 MergingTypeTableBuilder
&CVTypes
) {
1208 for (const SectionRef
&S
: Obj
->sections()) {
1209 StringRef SectionName
;
1210 error(S
.getName(SectionName
));
1211 if (SectionName
== ".debug$T") {
1213 error(S
.getContents(Data
));
1215 error(consume(Data
, Magic
));
1217 error(object_error::parse_failed
);
1220 BinaryStreamReader
Reader(Data
, llvm::support::little
);
1221 if (auto EC
= Reader
.readArray(Types
, Reader
.getLength())) {
1222 consumeError(std::move(EC
));
1224 error(object_error::parse_failed
);
1226 SmallVector
<TypeIndex
, 128> SourceToDest
;
1227 if (auto EC
= mergeTypeAndIdRecords(CVIDs
, CVTypes
, SourceToDest
, Types
))
1228 return error(std::move(EC
));
1233 void COFFDumper::printCodeViewTypeSection(StringRef SectionName
,
1234 const SectionRef
&Section
) {
1235 ListScope
D(W
, "CodeViewTypes");
1236 W
.printNumber("Section", SectionName
, Obj
->getSectionID(Section
));
1239 error(Section
.getContents(Data
));
1240 if (opts::CodeViewSubsectionBytes
)
1241 W
.printBinaryBlock("Data", Data
);
1244 error(consume(Data
, Magic
));
1245 W
.printHex("Magic", Magic
);
1246 if (Magic
!= COFF::DEBUG_SECTION_MAGIC
)
1247 return error(object_error::parse_failed
);
1249 Types
.reset(Data
, 100);
1251 TypeDumpVisitor
TDV(Types
, &W
, opts::CodeViewSubsectionBytes
);
1252 error(codeview::visitTypeStream(Types
, TDV
));
1256 void COFFDumper::printSections() {
1257 ListScope
SectionsD(W
, "Sections");
1258 int SectionNumber
= 0;
1259 for (const SectionRef
&Sec
: Obj
->sections()) {
1261 const coff_section
*Section
= Obj
->getCOFFSection(Sec
);
1264 error(Sec
.getName(Name
));
1266 DictScope
D(W
, "Section");
1267 W
.printNumber("Number", SectionNumber
);
1268 W
.printBinary("Name", Name
, Section
->Name
);
1269 W
.printHex ("VirtualSize", Section
->VirtualSize
);
1270 W
.printHex ("VirtualAddress", Section
->VirtualAddress
);
1271 W
.printNumber("RawDataSize", Section
->SizeOfRawData
);
1272 W
.printHex ("PointerToRawData", Section
->PointerToRawData
);
1273 W
.printHex ("PointerToRelocations", Section
->PointerToRelocations
);
1274 W
.printHex ("PointerToLineNumbers", Section
->PointerToLinenumbers
);
1275 W
.printNumber("RelocationCount", Section
->NumberOfRelocations
);
1276 W
.printNumber("LineNumberCount", Section
->NumberOfLinenumbers
);
1277 W
.printFlags ("Characteristics", Section
->Characteristics
,
1278 makeArrayRef(ImageSectionCharacteristics
),
1279 COFF::SectionCharacteristics(0x00F00000));
1281 if (opts::SectionRelocations
) {
1282 ListScope
D(W
, "Relocations");
1283 for (const RelocationRef
&Reloc
: Sec
.relocations())
1284 printRelocation(Sec
, Reloc
);
1287 if (opts::SectionSymbols
) {
1288 ListScope
D(W
, "Symbols");
1289 for (const SymbolRef
&Symbol
: Obj
->symbols()) {
1290 if (!Sec
.containsSymbol(Symbol
))
1293 printSymbol(Symbol
);
1297 if (opts::SectionData
&&
1298 !(Section
->Characteristics
& COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
)) {
1300 error(Sec
.getContents(Data
));
1302 W
.printBinaryBlock("SectionData", Data
);
1307 void COFFDumper::printRelocations() {
1308 ListScope
D(W
, "Relocations");
1310 int SectionNumber
= 0;
1311 for (const SectionRef
&Section
: Obj
->sections()) {
1314 error(Section
.getName(Name
));
1316 bool PrintedGroup
= false;
1317 for (const RelocationRef
&Reloc
: Section
.relocations()) {
1318 if (!PrintedGroup
) {
1319 W
.startLine() << "Section (" << SectionNumber
<< ") " << Name
<< " {\n";
1321 PrintedGroup
= true;
1324 printRelocation(Section
, Reloc
);
1329 W
.startLine() << "}\n";
1334 void COFFDumper::printRelocation(const SectionRef
&Section
,
1335 const RelocationRef
&Reloc
, uint64_t Bias
) {
1336 uint64_t Offset
= Reloc
.getOffset() - Bias
;
1337 uint64_t RelocType
= Reloc
.getType();
1338 SmallString
<32> RelocName
;
1339 StringRef SymbolName
;
1340 Reloc
.getTypeName(RelocName
);
1341 symbol_iterator Symbol
= Reloc
.getSymbol();
1342 if (Symbol
!= Obj
->symbol_end()) {
1343 Expected
<StringRef
> SymbolNameOrErr
= Symbol
->getName();
1344 error(errorToErrorCode(SymbolNameOrErr
.takeError()));
1345 SymbolName
= *SymbolNameOrErr
;
1348 if (opts::ExpandRelocs
) {
1349 DictScope
Group(W
, "Relocation");
1350 W
.printHex("Offset", Offset
);
1351 W
.printNumber("Type", RelocName
, RelocType
);
1352 W
.printString("Symbol", SymbolName
.empty() ? "-" : SymbolName
);
1354 raw_ostream
& OS
= W
.startLine();
1357 << " " << (SymbolName
.empty() ? "-" : SymbolName
)
1362 void COFFDumper::printSymbols() {
1363 ListScope
Group(W
, "Symbols");
1365 for (const SymbolRef
&Symbol
: Obj
->symbols())
1366 printSymbol(Symbol
);
1369 void COFFDumper::printDynamicSymbols() { ListScope
Group(W
, "DynamicSymbols"); }
1371 static ErrorOr
<StringRef
>
1372 getSectionName(const llvm::object::COFFObjectFile
*Obj
, int32_t SectionNumber
,
1373 const coff_section
*Section
) {
1375 StringRef SectionName
;
1376 if (std::error_code EC
= Obj
->getSectionName(Section
, SectionName
))
1380 if (SectionNumber
== llvm::COFF::IMAGE_SYM_DEBUG
)
1381 return StringRef("IMAGE_SYM_DEBUG");
1382 if (SectionNumber
== llvm::COFF::IMAGE_SYM_ABSOLUTE
)
1383 return StringRef("IMAGE_SYM_ABSOLUTE");
1384 if (SectionNumber
== llvm::COFF::IMAGE_SYM_UNDEFINED
)
1385 return StringRef("IMAGE_SYM_UNDEFINED");
1386 return StringRef("");
1389 void COFFDumper::printSymbol(const SymbolRef
&Sym
) {
1390 DictScope
D(W
, "Symbol");
1392 COFFSymbolRef Symbol
= Obj
->getCOFFSymbol(Sym
);
1393 const coff_section
*Section
;
1394 if (std::error_code EC
= Obj
->getSection(Symbol
.getSectionNumber(), Section
)) {
1395 W
.startLine() << "Invalid section number: " << EC
.message() << "\n";
1400 StringRef SymbolName
;
1401 if (Obj
->getSymbolName(Symbol
, SymbolName
))
1404 StringRef SectionName
= "";
1405 ErrorOr
<StringRef
> Res
=
1406 getSectionName(Obj
, Symbol
.getSectionNumber(), Section
);
1410 W
.printString("Name", SymbolName
);
1411 W
.printNumber("Value", Symbol
.getValue());
1412 W
.printNumber("Section", SectionName
, Symbol
.getSectionNumber());
1413 W
.printEnum ("BaseType", Symbol
.getBaseType(), makeArrayRef(ImageSymType
));
1414 W
.printEnum ("ComplexType", Symbol
.getComplexType(),
1415 makeArrayRef(ImageSymDType
));
1416 W
.printEnum ("StorageClass", Symbol
.getStorageClass(),
1417 makeArrayRef(ImageSymClass
));
1418 W
.printNumber("AuxSymbolCount", Symbol
.getNumberOfAuxSymbols());
1420 for (uint8_t I
= 0; I
< Symbol
.getNumberOfAuxSymbols(); ++I
) {
1421 if (Symbol
.isFunctionDefinition()) {
1422 const coff_aux_function_definition
*Aux
;
1423 error(getSymbolAuxData(Obj
, Symbol
, I
, Aux
));
1425 DictScope
AS(W
, "AuxFunctionDef");
1426 W
.printNumber("TagIndex", Aux
->TagIndex
);
1427 W
.printNumber("TotalSize", Aux
->TotalSize
);
1428 W
.printHex("PointerToLineNumber", Aux
->PointerToLinenumber
);
1429 W
.printHex("PointerToNextFunction", Aux
->PointerToNextFunction
);
1431 } else if (Symbol
.isAnyUndefined()) {
1432 const coff_aux_weak_external
*Aux
;
1433 error(getSymbolAuxData(Obj
, Symbol
, I
, Aux
));
1435 Expected
<COFFSymbolRef
> Linked
= Obj
->getSymbol(Aux
->TagIndex
);
1436 StringRef LinkedName
;
1437 std::error_code EC
= errorToErrorCode(Linked
.takeError());
1438 if (EC
|| (EC
= Obj
->getSymbolName(*Linked
, LinkedName
))) {
1443 DictScope
AS(W
, "AuxWeakExternal");
1444 W
.printNumber("Linked", LinkedName
, Aux
->TagIndex
);
1445 W
.printEnum ("Search", Aux
->Characteristics
,
1446 makeArrayRef(WeakExternalCharacteristics
));
1448 } else if (Symbol
.isFileRecord()) {
1449 const char *FileName
;
1450 error(getSymbolAuxData(Obj
, Symbol
, I
, FileName
));
1452 DictScope
AS(W
, "AuxFileRecord");
1454 StringRef
Name(FileName
, Symbol
.getNumberOfAuxSymbols() *
1455 Obj
->getSymbolTableEntrySize());
1456 W
.printString("FileName", Name
.rtrim(StringRef("\0", 1)));
1458 } else if (Symbol
.isSectionDefinition()) {
1459 const coff_aux_section_definition
*Aux
;
1460 error(getSymbolAuxData(Obj
, Symbol
, I
, Aux
));
1462 int32_t AuxNumber
= Aux
->getNumber(Symbol
.isBigObj());
1464 DictScope
AS(W
, "AuxSectionDef");
1465 W
.printNumber("Length", Aux
->Length
);
1466 W
.printNumber("RelocationCount", Aux
->NumberOfRelocations
);
1467 W
.printNumber("LineNumberCount", Aux
->NumberOfLinenumbers
);
1468 W
.printHex("Checksum", Aux
->CheckSum
);
1469 W
.printNumber("Number", AuxNumber
);
1470 W
.printEnum("Selection", Aux
->Selection
, makeArrayRef(ImageCOMDATSelect
));
1472 if (Section
&& Section
->Characteristics
& COFF::IMAGE_SCN_LNK_COMDAT
1473 && Aux
->Selection
== COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
) {
1474 const coff_section
*Assoc
;
1475 StringRef AssocName
= "";
1476 std::error_code EC
= Obj
->getSection(AuxNumber
, Assoc
);
1477 ErrorOr
<StringRef
> Res
= getSectionName(Obj
, AuxNumber
, Assoc
);
1481 EC
= Res
.getError();
1487 W
.printNumber("AssocSection", AssocName
, AuxNumber
);
1489 } else if (Symbol
.isCLRToken()) {
1490 const coff_aux_clr_token
*Aux
;
1491 error(getSymbolAuxData(Obj
, Symbol
, I
, Aux
));
1493 Expected
<COFFSymbolRef
> ReferredSym
=
1494 Obj
->getSymbol(Aux
->SymbolTableIndex
);
1495 StringRef ReferredName
;
1496 std::error_code EC
= errorToErrorCode(ReferredSym
.takeError());
1497 if (EC
|| (EC
= Obj
->getSymbolName(*ReferredSym
, ReferredName
))) {
1502 DictScope
AS(W
, "AuxCLRToken");
1503 W
.printNumber("AuxType", Aux
->AuxType
);
1504 W
.printNumber("Reserved", Aux
->Reserved
);
1505 W
.printNumber("SymbolTableIndex", ReferredName
, Aux
->SymbolTableIndex
);
1508 W
.startLine() << "<unhandled auxiliary record>\n";
1513 void COFFDumper::printUnwindInfo() {
1514 ListScope
D(W
, "UnwindInformation");
1515 switch (Obj
->getMachine()) {
1516 case COFF::IMAGE_FILE_MACHINE_AMD64
: {
1517 Win64EH::Dumper
Dumper(W
);
1518 Win64EH::Dumper::SymbolResolver
1519 Resolver
= [](const object::coff_section
*Section
, uint64_t Offset
,
1520 SymbolRef
&Symbol
, void *user_data
) -> std::error_code
{
1521 COFFDumper
*Dumper
= reinterpret_cast<COFFDumper
*>(user_data
);
1522 return Dumper
->resolveSymbol(Section
, Offset
, Symbol
);
1524 Win64EH::Dumper::Context
Ctx(*Obj
, Resolver
, this);
1525 Dumper
.printData(Ctx
);
1528 case COFF::IMAGE_FILE_MACHINE_ARMNT
: {
1529 ARM::WinEH::Decoder
Decoder(W
);
1530 Decoder
.dumpProcedureData(*Obj
);
1534 W
.printEnum("unsupported Image Machine", Obj
->getMachine(),
1535 makeArrayRef(ImageFileMachineType
));
1540 void COFFDumper::printNeededLibraries() {
1541 ListScope
D(W
, "NeededLibraries");
1543 using LibsTy
= std::vector
<StringRef
>;
1546 for (const ImportDirectoryEntryRef
&DirRef
: Obj
->import_directories()) {
1548 if (!DirRef
.getName(Name
))
1549 Libs
.push_back(Name
);
1552 std::stable_sort(Libs
.begin(), Libs
.end());
1554 for (const auto &L
: Libs
) {
1555 outs() << " " << L
<< "\n";
1559 void COFFDumper::printImportedSymbols(
1560 iterator_range
<imported_symbol_iterator
> Range
) {
1561 for (const ImportedSymbolRef
&I
: Range
) {
1563 error(I
.getSymbolName(Sym
));
1565 error(I
.getOrdinal(Ordinal
));
1566 W
.printNumber("Symbol", Sym
, Ordinal
);
1570 void COFFDumper::printDelayImportedSymbols(
1571 const DelayImportDirectoryEntryRef
&I
,
1572 iterator_range
<imported_symbol_iterator
> Range
) {
1574 for (const ImportedSymbolRef
&S
: Range
) {
1575 DictScope
Import(W
, "Import");
1577 error(S
.getSymbolName(Sym
));
1579 error(S
.getOrdinal(Ordinal
));
1580 W
.printNumber("Symbol", Sym
, Ordinal
);
1582 error(I
.getImportAddress(Index
++, Addr
));
1583 W
.printHex("Address", Addr
);
1587 void COFFDumper::printCOFFImports() {
1589 for (const ImportDirectoryEntryRef
&I
: Obj
->import_directories()) {
1590 DictScope
Import(W
, "Import");
1592 error(I
.getName(Name
));
1593 W
.printString("Name", Name
);
1595 error(I
.getImportLookupTableRVA(ILTAddr
));
1596 W
.printHex("ImportLookupTableRVA", ILTAddr
);
1598 error(I
.getImportAddressTableRVA(IATAddr
));
1599 W
.printHex("ImportAddressTableRVA", IATAddr
);
1600 // The import lookup table can be missing with certain older linkers, so
1601 // fall back to the import address table in that case.
1603 printImportedSymbols(I
.lookup_table_symbols());
1605 printImportedSymbols(I
.imported_symbols());
1609 for (const DelayImportDirectoryEntryRef
&I
: Obj
->delay_import_directories()) {
1610 DictScope
Import(W
, "DelayImport");
1612 error(I
.getName(Name
));
1613 W
.printString("Name", Name
);
1614 const delay_import_directory_table_entry
*Table
;
1615 error(I
.getDelayImportTable(Table
));
1616 W
.printHex("Attributes", Table
->Attributes
);
1617 W
.printHex("ModuleHandle", Table
->ModuleHandle
);
1618 W
.printHex("ImportAddressTable", Table
->DelayImportAddressTable
);
1619 W
.printHex("ImportNameTable", Table
->DelayImportNameTable
);
1620 W
.printHex("BoundDelayImportTable", Table
->BoundDelayImportTable
);
1621 W
.printHex("UnloadDelayImportTable", Table
->UnloadDelayImportTable
);
1622 printDelayImportedSymbols(I
, I
.imported_symbols());
1626 void COFFDumper::printCOFFExports() {
1627 for (const ExportDirectoryEntryRef
&E
: Obj
->export_directories()) {
1628 DictScope
Export(W
, "Export");
1631 uint32_t Ordinal
, RVA
;
1633 error(E
.getSymbolName(Name
));
1634 error(E
.getOrdinal(Ordinal
));
1635 error(E
.getExportRVA(RVA
));
1637 W
.printNumber("Ordinal", Ordinal
);
1638 W
.printString("Name", Name
);
1639 W
.printHex("RVA", RVA
);
1643 void COFFDumper::printCOFFDirectives() {
1644 for (const SectionRef
&Section
: Obj
->sections()) {
1648 error(Section
.getName(Name
));
1649 if (Name
!= ".drectve")
1652 error(Section
.getContents(Contents
));
1654 W
.printString("Directive(s)", Contents
);
1658 static std::string
getBaseRelocTypeName(uint8_t Type
) {
1660 case COFF::IMAGE_REL_BASED_ABSOLUTE
: return "ABSOLUTE";
1661 case COFF::IMAGE_REL_BASED_HIGH
: return "HIGH";
1662 case COFF::IMAGE_REL_BASED_LOW
: return "LOW";
1663 case COFF::IMAGE_REL_BASED_HIGHLOW
: return "HIGHLOW";
1664 case COFF::IMAGE_REL_BASED_HIGHADJ
: return "HIGHADJ";
1665 case COFF::IMAGE_REL_BASED_ARM_MOV32T
: return "ARM_MOV32(T)";
1666 case COFF::IMAGE_REL_BASED_DIR64
: return "DIR64";
1667 default: return "unknown (" + llvm::utostr(Type
) + ")";
1671 void COFFDumper::printCOFFBaseReloc() {
1672 ListScope
D(W
, "BaseReloc");
1673 for (const BaseRelocRef
&I
: Obj
->base_relocs()) {
1676 error(I
.getRVA(RVA
));
1677 error(I
.getType(Type
));
1678 DictScope
Import(W
, "Entry");
1679 W
.printString("Type", getBaseRelocTypeName(Type
));
1680 W
.printHex("Address", RVA
);
1684 void COFFDumper::printCOFFResources() {
1685 ListScope
ResourcesD(W
, "Resources");
1686 for (const SectionRef
&S
: Obj
->sections()) {
1688 error(S
.getName(Name
));
1689 if (!Name
.startswith(".rsrc"))
1693 error(S
.getContents(Ref
));
1695 if ((Name
== ".rsrc") || (Name
== ".rsrc$01")) {
1696 ResourceSectionRef
RSF(Ref
);
1697 auto &BaseTable
= unwrapOrError(RSF
.getBaseTable());
1698 W
.printNumber("Total Number of Resources",
1699 countTotalTableEntries(RSF
, BaseTable
, "Type"));
1700 W
.printHex("Base Table Address",
1701 Obj
->getCOFFSection(S
)->PointerToRawData
);
1702 W
.startLine() << "\n";
1703 printResourceDirectoryTable(RSF
, BaseTable
, "Type");
1705 if (opts::SectionData
)
1706 W
.printBinaryBlock(Name
.str() + " Data", Ref
);
1711 COFFDumper::countTotalTableEntries(ResourceSectionRef RSF
,
1712 const coff_resource_dir_table
&Table
,
1714 uint32_t TotalEntries
= 0;
1715 for (int i
= 0; i
< Table
.NumberOfNameEntries
+ Table
.NumberOfIDEntries
;
1717 auto Entry
= unwrapOrError(getResourceDirectoryTableEntry(Table
, i
));
1718 if (Entry
.Offset
.isSubDir()) {
1719 StringRef NextLevel
;
1720 if (Level
== "Name")
1721 NextLevel
= "Language";
1724 auto &NextTable
= unwrapOrError(RSF
.getEntrySubDir(Entry
));
1725 TotalEntries
+= countTotalTableEntries(RSF
, NextTable
, NextLevel
);
1730 return TotalEntries
;
1733 void COFFDumper::printResourceDirectoryTable(
1734 ResourceSectionRef RSF
, const coff_resource_dir_table
&Table
,
1737 W
.printNumber("Number of String Entries", Table
.NumberOfNameEntries
);
1738 W
.printNumber("Number of ID Entries", Table
.NumberOfIDEntries
);
1740 // Iterate through level in resource directory tree.
1741 for (int i
= 0; i
< Table
.NumberOfNameEntries
+ Table
.NumberOfIDEntries
;
1743 auto Entry
= unwrapOrError(getResourceDirectoryTableEntry(Table
, i
));
1745 SmallString
<20> IDStr
;
1746 raw_svector_ostream
OS(IDStr
);
1747 if (i
< Table
.NumberOfNameEntries
) {
1748 ArrayRef
<UTF16
> RawEntryNameString
= unwrapOrError(RSF
.getEntryNameString(Entry
));
1749 std::vector
<UTF16
> EndianCorrectedNameString
;
1750 if (llvm::sys::IsBigEndianHost
) {
1751 EndianCorrectedNameString
.resize(RawEntryNameString
.size() + 1);
1752 std::copy(RawEntryNameString
.begin(), RawEntryNameString
.end(),
1753 EndianCorrectedNameString
.begin() + 1);
1754 EndianCorrectedNameString
[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
;
1755 RawEntryNameString
= makeArrayRef(EndianCorrectedNameString
);
1757 std::string EntryNameString
;
1758 if (!llvm::convertUTF16ToUTF8String(RawEntryNameString
, EntryNameString
))
1759 error(object_error::parse_failed
);
1761 OS
<< EntryNameString
;
1763 if (Level
== "Type") {
1764 ScopedPrinter
Printer(OS
);
1765 Printer
.printEnum("", Entry
.Identifier
.ID
,
1766 makeArrayRef(ResourceTypeNames
));
1767 IDStr
= IDStr
.slice(0, IDStr
.find_first_of(")", 0) + 1);
1769 OS
<< ": (ID " << Entry
.Identifier
.ID
<< ")";
1772 Name
= StringRef(IDStr
);
1773 ListScope
ResourceType(W
, Level
.str() + Name
.str());
1774 if (Entry
.Offset
.isSubDir()) {
1775 W
.printHex("Table Offset", Entry
.Offset
.value());
1776 StringRef NextLevel
;
1777 if (Level
== "Name")
1778 NextLevel
= "Language";
1781 auto &NextTable
= unwrapOrError(RSF
.getEntrySubDir(Entry
));
1782 printResourceDirectoryTable(RSF
, NextTable
, NextLevel
);
1784 W
.printHex("Entry Offset", Entry
.Offset
.value());
1785 char FormattedTime
[20] = {};
1786 time_t TDS
= time_t(Table
.TimeDateStamp
);
1787 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
1788 W
.printHex("Time/Date Stamp", FormattedTime
, Table
.TimeDateStamp
);
1789 W
.printNumber("Major Version", Table
.MajorVersion
);
1790 W
.printNumber("Minor Version", Table
.MinorVersion
);
1791 W
.printNumber("Characteristics", Table
.Characteristics
);
1796 ErrorOr
<const coff_resource_dir_entry
&>
1797 COFFDumper::getResourceDirectoryTableEntry(const coff_resource_dir_table
&Table
,
1799 if (Index
>= (uint32_t)(Table
.NumberOfNameEntries
+ Table
.NumberOfIDEntries
))
1800 return object_error::parse_failed
;
1801 auto TablePtr
= reinterpret_cast<const coff_resource_dir_entry
*>(&Table
+ 1);
1802 return TablePtr
[Index
];
1805 void COFFDumper::printStackMap() const {
1806 object::SectionRef StackMapSection
;
1807 for (auto Sec
: Obj
->sections()) {
1810 if (Name
== ".llvm_stackmaps") {
1811 StackMapSection
= Sec
;
1816 if (StackMapSection
== object::SectionRef())
1819 StringRef StackMapContents
;
1820 StackMapSection
.getContents(StackMapContents
);
1821 ArrayRef
<uint8_t> StackMapContentsArray(
1822 reinterpret_cast<const uint8_t*>(StackMapContents
.data()),
1823 StackMapContents
.size());
1825 if (Obj
->isLittleEndian())
1826 prettyPrintStackMap(
1827 W
, StackMapV2Parser
<support::little
>(StackMapContentsArray
));
1829 prettyPrintStackMap(W
,
1830 StackMapV2Parser
<support::big
>(StackMapContentsArray
));
1833 void llvm::dumpCodeViewMergedTypes(
1834 ScopedPrinter
&Writer
, llvm::codeview::MergingTypeTableBuilder
&IDTable
,
1835 llvm::codeview::MergingTypeTableBuilder
&CVTypes
) {
1836 // Flatten it first, then run our dumper on it.
1837 SmallString
<0> TypeBuf
;
1838 CVTypes
.ForEachRecord([&](TypeIndex TI
, const CVType
&Record
) {
1839 TypeBuf
.append(Record
.RecordData
.begin(), Record
.RecordData
.end());
1842 TypeTableCollection
TpiTypes(CVTypes
.records());
1844 ListScope
S(Writer
, "MergedTypeStream");
1845 TypeDumpVisitor
TDV(TpiTypes
, &Writer
, opts::CodeViewSubsectionBytes
);
1846 error(codeview::visitTypeStream(TpiTypes
, TDV
));
1850 // Flatten the id stream and print it next. The ID stream refers to names from
1852 TypeTableCollection
IpiTypes(IDTable
.records());
1854 ListScope
S(Writer
, "MergedIDStream");
1855 TypeDumpVisitor
TDV(TpiTypes
, &Writer
, opts::CodeViewSubsectionBytes
);
1856 TDV
.setIpiTypes(IpiTypes
);
1857 error(codeview::visitTypeStream(IpiTypes
, TDV
));