1 //===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements the COFF-specific dumper for llvm-readobj.
12 //===----------------------------------------------------------------------===//
14 #include "ARMWinEHPrinter.h"
15 #include "ObjDumper.h"
16 #include "StackMapPrinter.h"
17 #include "Win64EHDumper.h"
18 #include "llvm-readobj.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/BinaryFormat/COFF.h"
23 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
24 #include "llvm/DebugInfo/CodeView/CodeView.h"
25 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
28 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
30 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
31 #include "llvm/DebugInfo/CodeView/Line.h"
32 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
33 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
34 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
35 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
36 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
37 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
38 #include "llvm/DebugInfo/CodeView/TypeHashing.h"
39 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
40 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
41 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
42 #include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
43 #include "llvm/Object/COFF.h"
44 #include "llvm/Object/ObjectFile.h"
45 #include "llvm/Object/WindowsResource.h"
46 #include "llvm/Support/BinaryStreamReader.h"
47 #include "llvm/Support/Casting.h"
48 #include "llvm/Support/Compiler.h"
49 #include "llvm/Support/ConvertUTF.h"
50 #include "llvm/Support/FormatVariadic.h"
51 #include "llvm/Support/LEB128.h"
52 #include "llvm/Support/ScopedPrinter.h"
53 #include "llvm/Support/Win64EH.h"
54 #include "llvm/Support/raw_ostream.h"
58 using namespace llvm::object
;
59 using namespace llvm::codeview
;
60 using namespace llvm::support
;
61 using namespace llvm::Win64EH
;
65 struct LoadConfigTables
{
66 uint64_t SEHTableVA
= 0;
67 uint64_t SEHTableCount
= 0;
68 uint32_t GuardFlags
= 0;
69 uint64_t GuardFidTableVA
= 0;
70 uint64_t GuardFidTableCount
= 0;
71 uint64_t GuardIatTableVA
= 0;
72 uint64_t GuardIatTableCount
= 0;
73 uint64_t GuardLJmpTableVA
= 0;
74 uint64_t GuardLJmpTableCount
= 0;
75 uint64_t GuardEHContTableVA
= 0;
76 uint64_t GuardEHContTableCount
= 0;
79 class COFFDumper
: public ObjDumper
{
81 friend class COFFObjectDumpDelegate
;
82 COFFDumper(const llvm::object::COFFObjectFile
*Obj
, ScopedPrinter
&Writer
)
83 : ObjDumper(Writer
, Obj
->getFileName()), Obj(Obj
), Writer(Writer
),
86 void printFileHeaders() override
;
87 void printSectionHeaders() override
;
88 void printRelocations() override
;
89 void printUnwindInfo() override
;
91 void printNeededLibraries() override
;
93 void printCOFFImports() override
;
94 void printCOFFExports() override
;
95 void printCOFFDirectives() override
;
96 void printCOFFBaseReloc() override
;
97 void printCOFFDebugDirectory() override
;
98 void printCOFFTLSDirectory() override
;
99 void printCOFFResources() override
;
100 void printCOFFLoadConfig() override
;
101 void printCodeViewDebugInfo() override
;
102 void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder
&CVIDs
,
103 llvm::codeview::MergingTypeTableBuilder
&CVTypes
,
104 llvm::codeview::GlobalTypeTableBuilder
&GlobalCVIDs
,
105 llvm::codeview::GlobalTypeTableBuilder
&GlobalCVTypes
,
106 bool GHash
) override
;
107 void printStackMap() const override
;
108 void printAddrsig() override
;
109 void printCGProfile() override
;
112 StringRef
getSymbolName(uint32_t Index
);
113 void printSymbols(bool ExtraSymInfo
) override
;
114 void printDynamicSymbols() override
;
115 void printSymbol(const SymbolRef
&Sym
);
116 void printRelocation(const SectionRef
&Section
, const RelocationRef
&Reloc
,
118 void printDataDirectory(uint32_t Index
, const std::string
&FieldName
);
120 void printDOSHeader(const dos_header
*DH
);
121 template <class PEHeader
> void printPEHeader(const PEHeader
*Hdr
);
122 void printBaseOfDataField(const pe32_header
*Hdr
);
123 void printBaseOfDataField(const pe32plus_header
*Hdr
);
124 template <typename T
>
125 void printCOFFLoadConfig(const T
*Conf
, LoadConfigTables
&Tables
);
126 template <typename IntTy
>
127 void printCOFFTLSDirectory(const coff_tls_directory
<IntTy
> *TlsTable
);
128 typedef void (*PrintExtraCB
)(raw_ostream
&, const uint8_t *);
129 void printRVATable(uint64_t TableVA
, uint64_t Count
, uint64_t EntrySize
,
130 PrintExtraCB PrintExtra
= nullptr);
132 void printCodeViewSymbolSection(StringRef SectionName
, const SectionRef
&Section
);
133 void printCodeViewTypeSection(StringRef SectionName
, const SectionRef
&Section
);
134 StringRef
getFileNameForFileOffset(uint32_t FileOffset
);
135 void printFileNameForOffset(StringRef Label
, uint32_t FileOffset
);
136 void printTypeIndex(StringRef FieldName
, TypeIndex TI
) {
137 // Forward to CVTypeDumper for simplicity.
138 codeview::printTypeIndex(Writer
, FieldName
, TI
, Types
);
141 void printCodeViewSymbolsSubsection(StringRef Subsection
,
142 const SectionRef
&Section
,
143 StringRef SectionContents
);
145 void printCodeViewFileChecksums(StringRef Subsection
);
147 void printCodeViewInlineeLines(StringRef Subsection
);
149 void printRelocatedField(StringRef Label
, const coff_section
*Sec
,
150 uint32_t RelocOffset
, uint32_t Offset
,
151 StringRef
*RelocSym
= nullptr);
153 uint32_t countTotalTableEntries(ResourceSectionRef RSF
,
154 const coff_resource_dir_table
&Table
,
157 void printResourceDirectoryTable(ResourceSectionRef RSF
,
158 const coff_resource_dir_table
&Table
,
161 void printBinaryBlockWithRelocs(StringRef Label
, const SectionRef
&Sec
,
162 StringRef SectionContents
, StringRef Block
);
164 /// Given a .debug$S section, find the string table and file checksum table.
165 void initializeFileAndStringTables(BinaryStreamReader
&Reader
);
167 void cacheRelocations();
169 std::error_code
resolveSymbol(const coff_section
*Section
, uint64_t Offset
,
171 std::error_code
resolveSymbolName(const coff_section
*Section
,
172 uint64_t Offset
, StringRef
&Name
);
173 std::error_code
resolveSymbolName(const coff_section
*Section
,
174 StringRef SectionContents
,
175 const void *RelocPtr
, StringRef
&Name
);
176 void printImportedSymbols(iterator_range
<imported_symbol_iterator
> Range
);
177 void printDelayImportedSymbols(
178 const DelayImportDirectoryEntryRef
&I
,
179 iterator_range
<imported_symbol_iterator
> Range
);
181 typedef DenseMap
<const coff_section
*, std::vector
<RelocationRef
> > RelocMapTy
;
183 const llvm::object::COFFObjectFile
*Obj
;
184 bool RelocCached
= false;
187 DebugChecksumsSubsectionRef CVFileChecksumTable
;
189 DebugStringTableSubsectionRef CVStringTable
;
191 /// Track the compilation CPU type. S_COMPILE3 symbol records typically come
192 /// first, but if we don't see one, just assume an X64 CPU type. It is common.
193 CPUType CompilationCPUType
= CPUType::X64
;
195 ScopedPrinter
&Writer
;
196 LazyRandomTypeCollection Types
;
199 class COFFObjectDumpDelegate
: public SymbolDumpDelegate
{
201 COFFObjectDumpDelegate(COFFDumper
&CD
, const SectionRef
&SR
,
202 const COFFObjectFile
*Obj
, StringRef SectionContents
)
203 : CD(CD
), SR(SR
), SectionContents(SectionContents
) {
204 Sec
= Obj
->getCOFFSection(SR
);
207 uint32_t getRecordOffset(BinaryStreamReader Reader
) override
{
208 ArrayRef
<uint8_t> Data
;
209 if (auto EC
= Reader
.readLongestContiguousChunk(Data
)) {
210 llvm::consumeError(std::move(EC
));
213 return Data
.data() - SectionContents
.bytes_begin();
216 void printRelocatedField(StringRef Label
, uint32_t RelocOffset
,
217 uint32_t Offset
, StringRef
*RelocSym
) override
{
218 CD
.printRelocatedField(Label
, Sec
, RelocOffset
, Offset
, RelocSym
);
221 void printBinaryBlockWithRelocs(StringRef Label
,
222 ArrayRef
<uint8_t> Block
) override
{
223 StringRef
SBlock(reinterpret_cast<const char *>(Block
.data()),
225 if (opts::CodeViewSubsectionBytes
)
226 CD
.printBinaryBlockWithRelocs(Label
, SR
, SectionContents
, SBlock
);
229 StringRef
getFileNameForFileOffset(uint32_t FileOffset
) override
{
230 return CD
.getFileNameForFileOffset(FileOffset
);
233 DebugStringTableSubsectionRef
getStringTable() override
{
234 return CD
.CVStringTable
;
239 const SectionRef
&SR
;
240 const coff_section
*Sec
;
241 StringRef SectionContents
;
248 std::unique_ptr
<ObjDumper
> createCOFFDumper(const object::COFFObjectFile
&Obj
,
249 ScopedPrinter
&Writer
) {
250 return std::make_unique
<COFFDumper
>(&Obj
, Writer
);
255 // Given a section and an offset into this section the function returns the
256 // symbol used for the relocation at the offset.
257 std::error_code
COFFDumper::resolveSymbol(const coff_section
*Section
,
258 uint64_t Offset
, SymbolRef
&Sym
) {
260 const auto &Relocations
= RelocMap
[Section
];
261 auto SymI
= Obj
->symbol_end();
262 for (const auto &Relocation
: Relocations
) {
263 uint64_t RelocationOffset
= Relocation
.getOffset();
265 if (RelocationOffset
== Offset
) {
266 SymI
= Relocation
.getSymbol();
270 if (SymI
== Obj
->symbol_end())
271 return inconvertibleErrorCode();
273 return std::error_code();
276 // Given a section and an offset into this section the function returns the name
277 // of the symbol used for the relocation at the offset.
278 std::error_code
COFFDumper::resolveSymbolName(const coff_section
*Section
,
282 if (std::error_code EC
= resolveSymbol(Section
, Offset
, Symbol
))
284 Expected
<StringRef
> NameOrErr
= Symbol
.getName();
286 return errorToErrorCode(NameOrErr
.takeError());
288 return std::error_code();
291 // Helper for when you have a pointer to real data and you want to know about
292 // relocations against it.
293 std::error_code
COFFDumper::resolveSymbolName(const coff_section
*Section
,
294 StringRef SectionContents
,
295 const void *RelocPtr
,
297 assert(SectionContents
.data() < RelocPtr
&&
298 RelocPtr
< SectionContents
.data() + SectionContents
.size() &&
299 "pointer to relocated object is not in section");
300 uint64_t Offset
= ptrdiff_t(reinterpret_cast<const char *>(RelocPtr
) -
301 SectionContents
.data());
302 return resolveSymbolName(Section
, Offset
, Name
);
305 void COFFDumper::printRelocatedField(StringRef Label
, const coff_section
*Sec
,
306 uint32_t RelocOffset
, uint32_t Offset
,
307 StringRef
*RelocSym
) {
308 StringRef SymStorage
;
309 StringRef
&Symbol
= RelocSym
? *RelocSym
: SymStorage
;
310 if (!resolveSymbolName(Sec
, RelocOffset
, Symbol
))
311 W
.printSymbolOffset(Label
, Symbol
, Offset
);
313 W
.printHex(Label
, RelocOffset
);
316 void COFFDumper::printBinaryBlockWithRelocs(StringRef Label
,
317 const SectionRef
&Sec
,
318 StringRef SectionContents
,
320 W
.printBinaryBlock(Label
, Block
);
322 assert(SectionContents
.begin() < Block
.begin() &&
323 SectionContents
.end() >= Block
.end() &&
324 "Block is not contained in SectionContents");
325 uint64_t OffsetStart
= Block
.data() - SectionContents
.data();
326 uint64_t OffsetEnd
= OffsetStart
+ Block
.size();
330 ListScope
D(W
, "BlockRelocations");
331 const coff_section
*Section
= Obj
->getCOFFSection(Sec
);
332 const auto &Relocations
= RelocMap
[Section
];
333 for (const auto &Relocation
: Relocations
) {
334 uint64_t RelocationOffset
= Relocation
.getOffset();
335 if (OffsetStart
<= RelocationOffset
&& RelocationOffset
< OffsetEnd
)
336 printRelocation(Sec
, Relocation
, OffsetStart
);
340 const EnumEntry
<COFF::MachineTypes
> ImageFileMachineType
[] = {
341 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_UNKNOWN
),
342 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_AM33
),
343 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_AMD64
),
344 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM
),
345 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM64
),
346 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM64EC
),
347 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARM64X
),
348 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_ARMNT
),
349 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_EBC
),
350 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_I386
),
351 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_IA64
),
352 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_M32R
),
353 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPS16
),
354 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPSFPU
),
355 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_MIPSFPU16
),
356 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_POWERPC
),
357 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_POWERPCFP
),
358 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_R4000
),
359 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH3
),
360 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH3DSP
),
361 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH4
),
362 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_SH5
),
363 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_THUMB
),
364 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_MACHINE_WCEMIPSV2
)
367 const EnumEntry
<COFF::Characteristics
> ImageFileCharacteristics
[] = {
368 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_RELOCS_STRIPPED
),
369 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_EXECUTABLE_IMAGE
),
370 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LINE_NUMS_STRIPPED
),
371 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LOCAL_SYMS_STRIPPED
),
372 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_AGGRESSIVE_WS_TRIM
),
373 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_LARGE_ADDRESS_AWARE
),
374 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_BYTES_REVERSED_LO
),
375 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_32BIT_MACHINE
),
376 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_DEBUG_STRIPPED
),
377 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
),
378 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_NET_RUN_FROM_SWAP
),
379 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_SYSTEM
),
380 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_DLL
),
381 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_UP_SYSTEM_ONLY
),
382 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_FILE_BYTES_REVERSED_HI
)
385 const EnumEntry
<COFF::WindowsSubsystem
> PEWindowsSubsystem
[] = {
386 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_UNKNOWN
),
387 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_NATIVE
),
388 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_GUI
),
389 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_CUI
),
390 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_POSIX_CUI
),
391 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
),
392 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_APPLICATION
),
393 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
),
394 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
),
395 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_EFI_ROM
),
396 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SUBSYSTEM_XBOX
),
399 const EnumEntry
<COFF::DLLCharacteristics
> PEDLLCharacteristics
[] = {
400 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
),
401 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
),
402 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
),
403 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
),
404 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
),
405 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_SEH
),
406 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_NO_BIND
),
407 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER
),
408 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER
),
409 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_GUARD_CF
),
410 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
),
413 static const EnumEntry
<COFF::ExtendedDLLCharacteristics
>
414 PEExtendedDLLCharacteristics
[] = {
415 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT
),
418 static const EnumEntry
<COFF::SectionCharacteristics
>
419 ImageSectionCharacteristics
[] = {
420 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_TYPE_NOLOAD
),
421 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_TYPE_NO_PAD
),
422 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_CODE
),
423 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_INITIALIZED_DATA
),
424 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_CNT_UNINITIALIZED_DATA
),
425 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_OTHER
),
426 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_INFO
),
427 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_REMOVE
),
428 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_COMDAT
),
429 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_GPREL
),
430 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_PURGEABLE
),
431 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_16BIT
),
432 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_LOCKED
),
433 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_PRELOAD
),
434 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_1BYTES
),
435 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_2BYTES
),
436 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_4BYTES
),
437 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_8BYTES
),
438 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_16BYTES
),
439 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_32BYTES
),
440 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_64BYTES
),
441 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_128BYTES
),
442 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_256BYTES
),
443 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_512BYTES
),
444 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_1024BYTES
),
445 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_2048BYTES
),
446 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_4096BYTES
),
447 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_ALIGN_8192BYTES
),
448 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_LNK_NRELOC_OVFL
),
449 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_DISCARDABLE
),
450 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_NOT_CACHED
),
451 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_NOT_PAGED
),
452 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_SHARED
),
453 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_EXECUTE
),
454 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_READ
),
455 LLVM_READOBJ_ENUM_ENT(COFF
, IMAGE_SCN_MEM_WRITE
)
458 const EnumEntry
<COFF::SymbolBaseType
> ImageSymType
[] = {
459 { "Null" , COFF::IMAGE_SYM_TYPE_NULL
},
460 { "Void" , COFF::IMAGE_SYM_TYPE_VOID
},
461 { "Char" , COFF::IMAGE_SYM_TYPE_CHAR
},
462 { "Short" , COFF::IMAGE_SYM_TYPE_SHORT
},
463 { "Int" , COFF::IMAGE_SYM_TYPE_INT
},
464 { "Long" , COFF::IMAGE_SYM_TYPE_LONG
},
465 { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT
},
466 { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE
},
467 { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT
},
468 { "Union" , COFF::IMAGE_SYM_TYPE_UNION
},
469 { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM
},
470 { "MOE" , COFF::IMAGE_SYM_TYPE_MOE
},
471 { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE
},
472 { "Word" , COFF::IMAGE_SYM_TYPE_WORD
},
473 { "UInt" , COFF::IMAGE_SYM_TYPE_UINT
},
474 { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD
}
477 const EnumEntry
<COFF::SymbolComplexType
> ImageSymDType
[] = {
478 { "Null" , COFF::IMAGE_SYM_DTYPE_NULL
},
479 { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER
},
480 { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION
},
481 { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY
}
484 const EnumEntry
<COFF::SymbolStorageClass
> ImageSymClass
[] = {
485 { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION
},
486 { "Null" , COFF::IMAGE_SYM_CLASS_NULL
},
487 { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC
},
488 { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL
},
489 { "Static" , COFF::IMAGE_SYM_CLASS_STATIC
},
490 { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER
},
491 { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF
},
492 { "Label" , COFF::IMAGE_SYM_CLASS_LABEL
},
493 { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL
},
494 { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT
},
495 { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT
},
496 { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG
},
497 { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION
},
498 { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG
},
499 { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION
},
500 { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC
},
501 { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG
},
502 { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM
},
503 { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM
},
504 { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD
},
505 { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK
},
506 { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION
},
507 { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT
},
508 { "File" , COFF::IMAGE_SYM_CLASS_FILE
},
509 { "Section" , COFF::IMAGE_SYM_CLASS_SECTION
},
510 { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL
},
511 { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN
}
514 const EnumEntry
<COFF::COMDATType
> ImageCOMDATSelect
[] = {
515 { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES
},
516 { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY
},
517 { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE
},
518 { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH
},
519 { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
},
520 { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST
},
521 { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST
}
524 const EnumEntry
<COFF::DebugType
> ImageDebugType
[] = {
525 {"Unknown", COFF::IMAGE_DEBUG_TYPE_UNKNOWN
},
526 {"COFF", COFF::IMAGE_DEBUG_TYPE_COFF
},
527 {"CodeView", COFF::IMAGE_DEBUG_TYPE_CODEVIEW
},
528 {"FPO", COFF::IMAGE_DEBUG_TYPE_FPO
},
529 {"Misc", COFF::IMAGE_DEBUG_TYPE_MISC
},
530 {"Exception", COFF::IMAGE_DEBUG_TYPE_EXCEPTION
},
531 {"Fixup", COFF::IMAGE_DEBUG_TYPE_FIXUP
},
532 {"OmapToSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC
},
533 {"OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
},
534 {"Borland", COFF::IMAGE_DEBUG_TYPE_BORLAND
},
535 {"Reserved10", COFF::IMAGE_DEBUG_TYPE_RESERVED10
},
536 {"CLSID", COFF::IMAGE_DEBUG_TYPE_CLSID
},
537 {"VCFeature", COFF::IMAGE_DEBUG_TYPE_VC_FEATURE
},
538 {"POGO", COFF::IMAGE_DEBUG_TYPE_POGO
},
539 {"ILTCG", COFF::IMAGE_DEBUG_TYPE_ILTCG
},
540 {"MPX", COFF::IMAGE_DEBUG_TYPE_MPX
},
541 {"Repro", COFF::IMAGE_DEBUG_TYPE_REPRO
},
542 {"ExtendedDLLCharacteristics",
543 COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS
},
546 static const EnumEntry
<COFF::WeakExternalCharacteristics
>
547 WeakExternalCharacteristics
[] = {
548 { "NoLibrary" , COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY
},
549 { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
},
550 { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
},
551 { "AntiDependency" , COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY
},
554 const EnumEntry
<uint32_t> SubSectionTypes
[] = {
555 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, Symbols
),
556 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, Lines
),
557 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, StringTable
),
558 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FileChecksums
),
559 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FrameData
),
560 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, InlineeLines
),
561 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CrossScopeImports
),
562 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CrossScopeExports
),
563 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, ILLines
),
564 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, FuncMDTokenMap
),
565 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, TypeMDTokenMap
),
566 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, MergedAssemblyInput
),
567 LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind
, CoffSymbolRVA
),
570 const EnumEntry
<uint32_t> FrameDataFlags
[] = {
571 LLVM_READOBJ_ENUM_ENT(FrameData
, HasSEH
),
572 LLVM_READOBJ_ENUM_ENT(FrameData
, HasEH
),
573 LLVM_READOBJ_ENUM_ENT(FrameData
, IsFunctionStart
),
576 const EnumEntry
<uint8_t> FileChecksumKindNames
[] = {
577 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, None
),
578 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, MD5
),
579 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, SHA1
),
580 LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind
, SHA256
),
583 const EnumEntry
<uint32_t> PELoadConfigGuardFlags
[] = {
584 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, CF_INSTRUMENTED
),
585 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, CFW_INSTRUMENTED
),
586 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, CF_FUNCTION_TABLE_PRESENT
),
587 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, SECURITY_COOKIE_UNUSED
),
588 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, PROTECT_DELAYLOAD_IAT
),
589 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
590 DELAYLOAD_IAT_IN_ITS_OWN_SECTION
),
591 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
592 CF_EXPORT_SUPPRESSION_INFO_PRESENT
),
593 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, CF_ENABLE_EXPORT_SUPPRESSION
),
594 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
, CF_LONGJUMP_TABLE_PRESENT
),
595 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
596 EH_CONTINUATION_TABLE_PRESENT
),
597 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
598 CF_FUNCTION_TABLE_SIZE_5BYTES
),
599 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
600 CF_FUNCTION_TABLE_SIZE_6BYTES
),
601 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
602 CF_FUNCTION_TABLE_SIZE_7BYTES
),
603 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
604 CF_FUNCTION_TABLE_SIZE_8BYTES
),
605 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
606 CF_FUNCTION_TABLE_SIZE_9BYTES
),
607 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
608 CF_FUNCTION_TABLE_SIZE_10BYTES
),
609 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
610 CF_FUNCTION_TABLE_SIZE_11BYTES
),
611 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
612 CF_FUNCTION_TABLE_SIZE_12BYTES
),
613 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
614 CF_FUNCTION_TABLE_SIZE_13BYTES
),
615 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
616 CF_FUNCTION_TABLE_SIZE_14BYTES
),
617 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
618 CF_FUNCTION_TABLE_SIZE_15BYTES
),
619 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
620 CF_FUNCTION_TABLE_SIZE_16BYTES
),
621 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
622 CF_FUNCTION_TABLE_SIZE_17BYTES
),
623 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
624 CF_FUNCTION_TABLE_SIZE_18BYTES
),
625 LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags
,
626 CF_FUNCTION_TABLE_SIZE_19BYTES
),
629 template <typename T
>
630 static std::error_code
getSymbolAuxData(const COFFObjectFile
*Obj
,
631 COFFSymbolRef Symbol
,
632 uint8_t AuxSymbolIdx
, const T
*&Aux
) {
633 ArrayRef
<uint8_t> AuxData
= Obj
->getSymbolAuxData(Symbol
);
634 AuxData
= AuxData
.slice(AuxSymbolIdx
* Obj
->getSymbolTableEntrySize());
635 Aux
= reinterpret_cast<const T
*>(AuxData
.data());
636 return std::error_code();
639 void COFFDumper::cacheRelocations() {
644 for (const SectionRef
&S
: Obj
->sections()) {
645 const coff_section
*Section
= Obj
->getCOFFSection(S
);
647 append_range(RelocMap
[Section
], S
.relocations());
649 // Sort relocations by address.
650 llvm::sort(RelocMap
[Section
], [](RelocationRef L
, RelocationRef R
) {
651 return L
.getOffset() < R
.getOffset();
656 void COFFDumper::printDataDirectory(uint32_t Index
,
657 const std::string
&FieldName
) {
658 const data_directory
*Data
= Obj
->getDataDirectory(Index
);
661 W
.printHex(FieldName
+ "RVA", Data
->RelativeVirtualAddress
);
662 W
.printHex(FieldName
+ "Size", Data
->Size
);
665 void COFFDumper::printFileHeaders() {
666 time_t TDS
= Obj
->getTimeDateStamp();
667 char FormattedTime
[20] = { };
668 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
671 DictScope
D(W
, "ImageFileHeader");
672 W
.printEnum("Machine", Obj
->getMachine(), ArrayRef(ImageFileMachineType
));
673 W
.printNumber("SectionCount", Obj
->getNumberOfSections());
674 W
.printHex ("TimeDateStamp", FormattedTime
, Obj
->getTimeDateStamp());
675 W
.printHex ("PointerToSymbolTable", Obj
->getPointerToSymbolTable());
676 W
.printNumber("SymbolCount", Obj
->getNumberOfSymbols());
677 W
.printNumber("StringTableSize", Obj
->getStringTableSize());
678 W
.printNumber("OptionalHeaderSize", Obj
->getSizeOfOptionalHeader());
679 W
.printFlags("Characteristics", Obj
->getCharacteristics(),
680 ArrayRef(ImageFileCharacteristics
));
683 // Print PE header. This header does not exist if this is an object file and
684 // not an executable.
685 if (const pe32_header
*PEHeader
= Obj
->getPE32Header())
686 printPEHeader
<pe32_header
>(PEHeader
);
688 if (const pe32plus_header
*PEPlusHeader
= Obj
->getPE32PlusHeader())
689 printPEHeader
<pe32plus_header
>(PEPlusHeader
);
691 if (const dos_header
*DH
= Obj
->getDOSHeader())
695 void COFFDumper::printDOSHeader(const dos_header
*DH
) {
696 DictScope
D(W
, "DOSHeader");
697 W
.printString("Magic", StringRef(DH
->Magic
, sizeof(DH
->Magic
)));
698 W
.printNumber("UsedBytesInTheLastPage", DH
->UsedBytesInTheLastPage
);
699 W
.printNumber("FileSizeInPages", DH
->FileSizeInPages
);
700 W
.printNumber("NumberOfRelocationItems", DH
->NumberOfRelocationItems
);
701 W
.printNumber("HeaderSizeInParagraphs", DH
->HeaderSizeInParagraphs
);
702 W
.printNumber("MinimumExtraParagraphs", DH
->MinimumExtraParagraphs
);
703 W
.printNumber("MaximumExtraParagraphs", DH
->MaximumExtraParagraphs
);
704 W
.printNumber("InitialRelativeSS", DH
->InitialRelativeSS
);
705 W
.printNumber("InitialSP", DH
->InitialSP
);
706 W
.printNumber("Checksum", DH
->Checksum
);
707 W
.printNumber("InitialIP", DH
->InitialIP
);
708 W
.printNumber("InitialRelativeCS", DH
->InitialRelativeCS
);
709 W
.printNumber("AddressOfRelocationTable", DH
->AddressOfRelocationTable
);
710 W
.printNumber("OverlayNumber", DH
->OverlayNumber
);
711 W
.printNumber("OEMid", DH
->OEMid
);
712 W
.printNumber("OEMinfo", DH
->OEMinfo
);
713 W
.printNumber("AddressOfNewExeHeader", DH
->AddressOfNewExeHeader
);
716 template <class PEHeader
>
717 void COFFDumper::printPEHeader(const PEHeader
*Hdr
) {
718 DictScope
D(W
, "ImageOptionalHeader");
719 W
.printHex ("Magic", Hdr
->Magic
);
720 W
.printNumber("MajorLinkerVersion", Hdr
->MajorLinkerVersion
);
721 W
.printNumber("MinorLinkerVersion", Hdr
->MinorLinkerVersion
);
722 W
.printNumber("SizeOfCode", Hdr
->SizeOfCode
);
723 W
.printNumber("SizeOfInitializedData", Hdr
->SizeOfInitializedData
);
724 W
.printNumber("SizeOfUninitializedData", Hdr
->SizeOfUninitializedData
);
725 W
.printHex ("AddressOfEntryPoint", Hdr
->AddressOfEntryPoint
);
726 W
.printHex ("BaseOfCode", Hdr
->BaseOfCode
);
727 printBaseOfDataField(Hdr
);
728 W
.printHex ("ImageBase", Hdr
->ImageBase
);
729 W
.printNumber("SectionAlignment", Hdr
->SectionAlignment
);
730 W
.printNumber("FileAlignment", Hdr
->FileAlignment
);
731 W
.printNumber("MajorOperatingSystemVersion",
732 Hdr
->MajorOperatingSystemVersion
);
733 W
.printNumber("MinorOperatingSystemVersion",
734 Hdr
->MinorOperatingSystemVersion
);
735 W
.printNumber("MajorImageVersion", Hdr
->MajorImageVersion
);
736 W
.printNumber("MinorImageVersion", Hdr
->MinorImageVersion
);
737 W
.printNumber("MajorSubsystemVersion", Hdr
->MajorSubsystemVersion
);
738 W
.printNumber("MinorSubsystemVersion", Hdr
->MinorSubsystemVersion
);
739 W
.printNumber("SizeOfImage", Hdr
->SizeOfImage
);
740 W
.printNumber("SizeOfHeaders", Hdr
->SizeOfHeaders
);
741 W
.printHex ("CheckSum", Hdr
->CheckSum
);
742 W
.printEnum("Subsystem", Hdr
->Subsystem
, ArrayRef(PEWindowsSubsystem
));
743 W
.printFlags("Characteristics", Hdr
->DLLCharacteristics
,
744 ArrayRef(PEDLLCharacteristics
));
745 W
.printNumber("SizeOfStackReserve", Hdr
->SizeOfStackReserve
);
746 W
.printNumber("SizeOfStackCommit", Hdr
->SizeOfStackCommit
);
747 W
.printNumber("SizeOfHeapReserve", Hdr
->SizeOfHeapReserve
);
748 W
.printNumber("SizeOfHeapCommit", Hdr
->SizeOfHeapCommit
);
749 W
.printNumber("NumberOfRvaAndSize", Hdr
->NumberOfRvaAndSize
);
751 if (Hdr
->NumberOfRvaAndSize
> 0) {
752 DictScope
D(W
, "DataDirectory");
753 static const char * const directory
[] = {
754 "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
755 "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
756 "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
757 "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
760 for (uint32_t i
= 0; i
< Hdr
->NumberOfRvaAndSize
; ++i
)
761 if (i
< std::size(directory
))
762 printDataDirectory(i
, directory
[i
]);
764 printDataDirectory(i
, "Unknown");
768 void COFFDumper::printCOFFDebugDirectory() {
769 ListScope
LS(W
, "DebugDirectory");
770 for (const debug_directory
&D
: Obj
->debug_directories()) {
771 char FormattedTime
[20] = {};
772 time_t TDS
= D
.TimeDateStamp
;
773 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
774 DictScope
S(W
, "DebugEntry");
775 W
.printHex("Characteristics", D
.Characteristics
);
776 W
.printHex("TimeDateStamp", FormattedTime
, D
.TimeDateStamp
);
777 W
.printHex("MajorVersion", D
.MajorVersion
);
778 W
.printHex("MinorVersion", D
.MinorVersion
);
779 W
.printEnum("Type", D
.Type
, ArrayRef(ImageDebugType
));
780 W
.printHex("SizeOfData", D
.SizeOfData
);
781 W
.printHex("AddressOfRawData", D
.AddressOfRawData
);
782 W
.printHex("PointerToRawData", D
.PointerToRawData
);
783 // Ideally, if D.AddressOfRawData == 0, we should try to load the payload
784 // using D.PointerToRawData instead.
785 if (D
.AddressOfRawData
== 0)
787 if (D
.Type
== COFF::IMAGE_DEBUG_TYPE_CODEVIEW
) {
788 const codeview::DebugInfo
*DebugInfo
;
789 StringRef PDBFileName
;
790 if (Error E
= Obj
->getDebugPDBInfo(&D
, DebugInfo
, PDBFileName
))
791 reportError(std::move(E
), Obj
->getFileName());
793 DictScope
PDBScope(W
, "PDBInfo");
794 W
.printHex("PDBSignature", DebugInfo
->Signature
.CVSignature
);
795 if (DebugInfo
->Signature
.CVSignature
== OMF::Signature::PDB70
) {
796 W
.printBinary("PDBGUID", ArrayRef(DebugInfo
->PDB70
.Signature
));
797 W
.printNumber("PDBAge", DebugInfo
->PDB70
.Age
);
798 W
.printString("PDBFileName", PDBFileName
);
800 } else if (D
.SizeOfData
!= 0) {
801 // FIXME: Data visualization for IMAGE_DEBUG_TYPE_VC_FEATURE and
802 // IMAGE_DEBUG_TYPE_POGO?
803 ArrayRef
<uint8_t> RawData
;
804 if (Error E
= Obj
->getRvaAndSizeAsBytes(D
.AddressOfRawData
,
805 D
.SizeOfData
, RawData
))
806 reportError(std::move(E
), Obj
->getFileName());
807 if (D
.Type
== COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS
) {
808 // FIXME right now the only possible value would fit in 8 bits,
809 // but that might change in the future
810 uint16_t Characteristics
= RawData
[0];
811 W
.printFlags("ExtendedCharacteristics", Characteristics
,
812 ArrayRef(PEExtendedDLLCharacteristics
));
814 W
.printBinaryBlock("RawData", RawData
);
819 void COFFDumper::printRVATable(uint64_t TableVA
, uint64_t Count
,
820 uint64_t EntrySize
, PrintExtraCB PrintExtra
) {
821 uintptr_t TableStart
, TableEnd
;
822 if (Error E
= Obj
->getVaPtr(TableVA
, TableStart
))
823 reportError(std::move(E
), Obj
->getFileName());
825 Obj
->getVaPtr(TableVA
+ Count
* EntrySize
- 1, TableEnd
))
826 reportError(std::move(E
), Obj
->getFileName());
828 for (uintptr_t I
= TableStart
; I
< TableEnd
; I
+= EntrySize
) {
829 uint32_t RVA
= *reinterpret_cast<const ulittle32_t
*>(I
);
830 raw_ostream
&OS
= W
.startLine();
831 OS
<< W
.hex(Obj
->getImageBase() + RVA
);
833 PrintExtra(OS
, reinterpret_cast<const uint8_t *>(I
));
838 void COFFDumper::printCOFFLoadConfig() {
839 LoadConfigTables Tables
;
841 printCOFFLoadConfig(Obj
->getLoadConfig64(), Tables
);
843 printCOFFLoadConfig(Obj
->getLoadConfig32(), Tables
);
845 if (auto CHPE
= Obj
->getCHPEMetadata()) {
846 ListScope
LS(W
, "CHPEMetadata");
847 W
.printHex("Version", CHPE
->Version
);
849 if (CHPE
->CodeMapCount
) {
850 ListScope
CMLS(W
, "CodeMap");
852 uintptr_t CodeMapInt
;
853 if (Error E
= Obj
->getRvaPtr(CHPE
->CodeMap
, CodeMapInt
))
854 reportError(std::move(E
), Obj
->getFileName());
855 auto CodeMap
= reinterpret_cast<const chpe_range_entry
*>(CodeMapInt
);
856 for (uint32_t i
= 0; i
< CHPE
->CodeMapCount
; i
++) {
857 uint32_t Start
= CodeMap
[i
].getStart();
858 W
.startLine() << W
.hex(Start
) << " - "
859 << W
.hex(Start
+ CodeMap
[i
].Length
) << " ";
860 switch (CodeMap
[i
].getType()) {
861 case chpe_range_type::Arm64
:
862 W
.getOStream() << "ARM64\n";
864 case chpe_range_type::Arm64EC
:
865 W
.getOStream() << "ARM64EC\n";
867 case chpe_range_type::Amd64
:
868 W
.getOStream() << "X64\n";
871 W
.getOStream() << W
.hex(CodeMap
[i
].StartOffset
& 3) << "\n";
876 W
.printNumber("CodeMap", CHPE
->CodeMap
);
879 if (CHPE
->CodeRangesToEntryPointsCount
) {
880 ListScope
CRLS(W
, "CodeRangesToEntryPoints");
882 uintptr_t CodeRangesInt
;
884 Obj
->getRvaPtr(CHPE
->CodeRangesToEntryPoints
, CodeRangesInt
))
885 reportError(std::move(E
), Obj
->getFileName());
887 reinterpret_cast<const chpe_code_range_entry
*>(CodeRangesInt
);
888 for (uint32_t i
= 0; i
< CHPE
->CodeRangesToEntryPointsCount
; i
++) {
889 W
.startLine() << W
.hex(CodeRanges
[i
].StartRva
) << " - "
890 << W
.hex(CodeRanges
[i
].EndRva
) << " -> "
891 << W
.hex(CodeRanges
[i
].EntryPoint
) << "\n";
894 W
.printNumber("CodeRangesToEntryPoints", CHPE
->CodeRangesToEntryPoints
);
897 if (CHPE
->RedirectionMetadataCount
) {
898 ListScope
RMLS(W
, "RedirectionMetadata");
900 uintptr_t RedirMetadataInt
;
901 if (Error E
= Obj
->getRvaPtr(CHPE
->RedirectionMetadata
, RedirMetadataInt
))
902 reportError(std::move(E
), Obj
->getFileName());
904 reinterpret_cast<const chpe_redirection_entry
*>(RedirMetadataInt
);
905 for (uint32_t i
= 0; i
< CHPE
->RedirectionMetadataCount
; i
++) {
906 W
.startLine() << W
.hex(RedirMetadata
[i
].Source
) << " -> "
907 << W
.hex(RedirMetadata
[i
].Destination
) << "\n";
910 W
.printNumber("RedirectionMetadata", CHPE
->RedirectionMetadata
);
913 W
.printHex("__os_arm64x_dispatch_call_no_redirect",
914 CHPE
->__os_arm64x_dispatch_call_no_redirect
);
915 W
.printHex("__os_arm64x_dispatch_ret", CHPE
->__os_arm64x_dispatch_ret
);
916 W
.printHex("__os_arm64x_dispatch_call", CHPE
->__os_arm64x_dispatch_call
);
917 W
.printHex("__os_arm64x_dispatch_icall", CHPE
->__os_arm64x_dispatch_icall
);
918 W
.printHex("__os_arm64x_dispatch_icall_cfg",
919 CHPE
->__os_arm64x_dispatch_icall_cfg
);
920 W
.printHex("AlternateEntryPoint", CHPE
->AlternateEntryPoint
);
921 W
.printHex("AuxiliaryIAT", CHPE
->AuxiliaryIAT
);
922 W
.printHex("GetX64InformationFunctionPointer",
923 CHPE
->GetX64InformationFunctionPointer
);
924 W
.printHex("SetX64InformationFunctionPointer",
925 CHPE
->SetX64InformationFunctionPointer
);
926 W
.printHex("ExtraRFETable", CHPE
->ExtraRFETable
);
927 W
.printHex("ExtraRFETableSize", CHPE
->ExtraRFETableSize
);
928 W
.printHex("__os_arm64x_dispatch_fptr", CHPE
->__os_arm64x_dispatch_fptr
);
929 W
.printHex("AuxiliaryIATCopy", CHPE
->AuxiliaryIATCopy
);
932 if (Tables
.SEHTableVA
) {
933 ListScope
LS(W
, "SEHTable");
934 printRVATable(Tables
.SEHTableVA
, Tables
.SEHTableCount
, 4);
937 auto PrintGuardFlags
= [](raw_ostream
&OS
, const uint8_t *Entry
) {
938 uint8_t Flags
= *reinterpret_cast<const uint8_t *>(Entry
+ 4);
940 OS
<< " flags " << utohexstr(Flags
);
943 // The stride gives the number of extra bytes in addition to the 4-byte
944 // RVA of each entry in the table. As of writing only a 1-byte extra flag
946 uint32_t Stride
= Tables
.GuardFlags
>> 28;
947 PrintExtraCB PrintExtra
= Stride
== 1 ? +PrintGuardFlags
: nullptr;
949 if (Tables
.GuardFidTableVA
) {
950 ListScope
LS(W
, "GuardFidTable");
951 printRVATable(Tables
.GuardFidTableVA
, Tables
.GuardFidTableCount
,
952 4 + Stride
, PrintExtra
);
955 if (Tables
.GuardIatTableVA
) {
956 ListScope
LS(W
, "GuardIatTable");
957 printRVATable(Tables
.GuardIatTableVA
, Tables
.GuardIatTableCount
,
958 4 + Stride
, PrintExtra
);
961 if (Tables
.GuardLJmpTableVA
) {
962 ListScope
LS(W
, "GuardLJmpTable");
963 printRVATable(Tables
.GuardLJmpTableVA
, Tables
.GuardLJmpTableCount
,
964 4 + Stride
, PrintExtra
);
967 if (Tables
.GuardEHContTableVA
) {
968 ListScope
LS(W
, "GuardEHContTable");
969 printRVATable(Tables
.GuardEHContTableVA
, Tables
.GuardEHContTableCount
,
970 4 + Stride
, PrintExtra
);
974 template <typename T
>
975 void COFFDumper::printCOFFLoadConfig(const T
*Conf
, LoadConfigTables
&Tables
) {
979 ListScope
LS(W
, "LoadConfig");
980 char FormattedTime
[20] = {};
981 time_t TDS
= Conf
->TimeDateStamp
;
982 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
983 W
.printHex("Size", Conf
->Size
);
985 // Print everything before SecurityCookie. The vast majority of images today
986 // have all these fields.
987 if (Conf
->Size
< offsetof(T
, SEHandlerTable
))
989 W
.printHex("TimeDateStamp", FormattedTime
, TDS
);
990 W
.printHex("MajorVersion", Conf
->MajorVersion
);
991 W
.printHex("MinorVersion", Conf
->MinorVersion
);
992 W
.printHex("GlobalFlagsClear", Conf
->GlobalFlagsClear
);
993 W
.printHex("GlobalFlagsSet", Conf
->GlobalFlagsSet
);
994 W
.printHex("CriticalSectionDefaultTimeout",
995 Conf
->CriticalSectionDefaultTimeout
);
996 W
.printHex("DeCommitFreeBlockThreshold", Conf
->DeCommitFreeBlockThreshold
);
997 W
.printHex("DeCommitTotalFreeThreshold", Conf
->DeCommitTotalFreeThreshold
);
998 W
.printHex("LockPrefixTable", Conf
->LockPrefixTable
);
999 W
.printHex("MaximumAllocationSize", Conf
->MaximumAllocationSize
);
1000 W
.printHex("VirtualMemoryThreshold", Conf
->VirtualMemoryThreshold
);
1001 W
.printHex("ProcessHeapFlags", Conf
->ProcessHeapFlags
);
1002 W
.printHex("ProcessAffinityMask", Conf
->ProcessAffinityMask
);
1003 W
.printHex("CSDVersion", Conf
->CSDVersion
);
1004 W
.printHex("DependentLoadFlags", Conf
->DependentLoadFlags
);
1005 W
.printHex("EditList", Conf
->EditList
);
1006 W
.printHex("SecurityCookie", Conf
->SecurityCookie
);
1008 // Print the safe SEH table if present.
1009 if (Conf
->Size
< offsetof(T
, GuardCFCheckFunction
))
1011 W
.printHex("SEHandlerTable", Conf
->SEHandlerTable
);
1012 W
.printNumber("SEHandlerCount", Conf
->SEHandlerCount
);
1014 Tables
.SEHTableVA
= Conf
->SEHandlerTable
;
1015 Tables
.SEHTableCount
= Conf
->SEHandlerCount
;
1017 // Print everything before CodeIntegrity. (2015)
1018 if (Conf
->Size
< offsetof(T
, CodeIntegrity
))
1020 W
.printHex("GuardCFCheckFunction", Conf
->GuardCFCheckFunction
);
1021 W
.printHex("GuardCFCheckDispatch", Conf
->GuardCFCheckDispatch
);
1022 W
.printHex("GuardCFFunctionTable", Conf
->GuardCFFunctionTable
);
1023 W
.printNumber("GuardCFFunctionCount", Conf
->GuardCFFunctionCount
);
1024 W
.printFlags("GuardFlags", Conf
->GuardFlags
, ArrayRef(PELoadConfigGuardFlags
),
1025 (uint32_t)COFF::GuardFlags::CF_FUNCTION_TABLE_SIZE_MASK
);
1027 Tables
.GuardFidTableVA
= Conf
->GuardCFFunctionTable
;
1028 Tables
.GuardFidTableCount
= Conf
->GuardCFFunctionCount
;
1029 Tables
.GuardFlags
= Conf
->GuardFlags
;
1031 // Print everything before Reserved3. (2017)
1032 if (Conf
->Size
< offsetof(T
, Reserved3
))
1034 W
.printHex("GuardAddressTakenIatEntryTable",
1035 Conf
->GuardAddressTakenIatEntryTable
);
1036 W
.printNumber("GuardAddressTakenIatEntryCount",
1037 Conf
->GuardAddressTakenIatEntryCount
);
1038 W
.printHex("GuardLongJumpTargetTable", Conf
->GuardLongJumpTargetTable
);
1039 W
.printNumber("GuardLongJumpTargetCount", Conf
->GuardLongJumpTargetCount
);
1040 W
.printHex("DynamicValueRelocTable", Conf
->DynamicValueRelocTable
);
1041 W
.printHex("CHPEMetadataPointer", Conf
->CHPEMetadataPointer
);
1042 W
.printHex("GuardRFFailureRoutine", Conf
->GuardRFFailureRoutine
);
1043 W
.printHex("GuardRFFailureRoutineFunctionPointer",
1044 Conf
->GuardRFFailureRoutineFunctionPointer
);
1045 W
.printHex("DynamicValueRelocTableOffset",
1046 Conf
->DynamicValueRelocTableOffset
);
1047 W
.printNumber("DynamicValueRelocTableSection",
1048 Conf
->DynamicValueRelocTableSection
);
1049 W
.printHex("GuardRFVerifyStackPointerFunctionPointer",
1050 Conf
->GuardRFVerifyStackPointerFunctionPointer
);
1051 W
.printHex("HotPatchTableOffset", Conf
->HotPatchTableOffset
);
1053 Tables
.GuardIatTableVA
= Conf
->GuardAddressTakenIatEntryTable
;
1054 Tables
.GuardIatTableCount
= Conf
->GuardAddressTakenIatEntryCount
;
1056 Tables
.GuardLJmpTableVA
= Conf
->GuardLongJumpTargetTable
;
1057 Tables
.GuardLJmpTableCount
= Conf
->GuardLongJumpTargetCount
;
1059 // Print the rest. (2019)
1060 if (Conf
->Size
< sizeof(T
))
1062 W
.printHex("EnclaveConfigurationPointer", Conf
->EnclaveConfigurationPointer
);
1063 W
.printHex("VolatileMetadataPointer", Conf
->VolatileMetadataPointer
);
1064 W
.printHex("GuardEHContinuationTable", Conf
->GuardEHContinuationTable
);
1065 W
.printNumber("GuardEHContinuationCount", Conf
->GuardEHContinuationCount
);
1067 Tables
.GuardEHContTableVA
= Conf
->GuardEHContinuationTable
;
1068 Tables
.GuardEHContTableCount
= Conf
->GuardEHContinuationCount
;
1071 void COFFDumper::printBaseOfDataField(const pe32_header
*Hdr
) {
1072 W
.printHex("BaseOfData", Hdr
->BaseOfData
);
1075 void COFFDumper::printBaseOfDataField(const pe32plus_header
*) {}
1077 void COFFDumper::printCodeViewDebugInfo() {
1078 // Print types first to build CVUDTNames, then print symbols.
1079 for (const SectionRef
&S
: Obj
->sections()) {
1080 StringRef SectionName
= unwrapOrError(Obj
->getFileName(), S
.getName());
1081 // .debug$T is a standard CodeView type section, while .debug$P is the same
1082 // format but used for MSVC precompiled header object files.
1083 if (SectionName
== ".debug$T" || SectionName
== ".debug$P")
1084 printCodeViewTypeSection(SectionName
, S
);
1086 for (const SectionRef
&S
: Obj
->sections()) {
1087 StringRef SectionName
= unwrapOrError(Obj
->getFileName(), S
.getName());
1088 if (SectionName
== ".debug$S")
1089 printCodeViewSymbolSection(SectionName
, S
);
1093 void COFFDumper::initializeFileAndStringTables(BinaryStreamReader
&Reader
) {
1094 while (Reader
.bytesRemaining() > 0 &&
1095 (!CVFileChecksumTable
.valid() || !CVStringTable
.valid())) {
1096 // The section consists of a number of subsection in the following format:
1097 // |SubSectionType|SubSectionSize|Contents...|
1098 uint32_t SubType
, SubSectionSize
;
1100 if (Error E
= Reader
.readInteger(SubType
))
1101 reportError(std::move(E
), Obj
->getFileName());
1102 if (Error E
= Reader
.readInteger(SubSectionSize
))
1103 reportError(std::move(E
), Obj
->getFileName());
1106 if (Error E
= Reader
.readFixedString(Contents
, SubSectionSize
))
1107 reportError(std::move(E
), Obj
->getFileName());
1109 BinaryStreamRef
ST(Contents
, llvm::endianness::little
);
1110 switch (DebugSubsectionKind(SubType
)) {
1111 case DebugSubsectionKind::FileChecksums
:
1112 if (Error E
= CVFileChecksumTable
.initialize(ST
))
1113 reportError(std::move(E
), Obj
->getFileName());
1115 case DebugSubsectionKind::StringTable
:
1116 if (Error E
= CVStringTable
.initialize(ST
))
1117 reportError(std::move(E
), Obj
->getFileName());
1123 uint32_t PaddedSize
= alignTo(SubSectionSize
, 4);
1124 if (Error E
= Reader
.skip(PaddedSize
- SubSectionSize
))
1125 reportError(std::move(E
), Obj
->getFileName());
1129 void COFFDumper::printCodeViewSymbolSection(StringRef SectionName
,
1130 const SectionRef
&Section
) {
1131 StringRef SectionContents
=
1132 unwrapOrError(Obj
->getFileName(), Section
.getContents());
1133 StringRef Data
= SectionContents
;
1135 SmallVector
<StringRef
, 10> FunctionNames
;
1136 StringMap
<StringRef
> FunctionLineTables
;
1138 ListScope
D(W
, "CodeViewDebugInfo");
1139 // Print the section to allow correlation with printSectionHeaders.
1140 W
.printNumber("Section", SectionName
, Obj
->getSectionID(Section
));
1143 if (Error E
= consume(Data
, Magic
))
1144 reportError(std::move(E
), Obj
->getFileName());
1146 W
.printHex("Magic", Magic
);
1147 if (Magic
!= COFF::DEBUG_SECTION_MAGIC
)
1148 reportError(errorCodeToError(object_error::parse_failed
),
1149 Obj
->getFileName());
1151 BinaryStreamReader
FSReader(Data
, llvm::endianness::little
);
1152 initializeFileAndStringTables(FSReader
);
1154 // TODO: Convert this over to using ModuleSubstreamVisitor.
1155 while (!Data
.empty()) {
1156 // The section consists of a number of subsection in the following format:
1157 // |SubSectionType|SubSectionSize|Contents...|
1158 uint32_t SubType
, SubSectionSize
;
1159 if (Error E
= consume(Data
, SubType
))
1160 reportError(std::move(E
), Obj
->getFileName());
1161 if (Error E
= consume(Data
, SubSectionSize
))
1162 reportError(std::move(E
), Obj
->getFileName());
1164 ListScope
S(W
, "Subsection");
1165 // Dump the subsection as normal even if the ignore bit is set.
1166 if (SubType
& SubsectionIgnoreFlag
) {
1167 W
.printHex("IgnoredSubsectionKind", SubType
);
1168 SubType
&= ~SubsectionIgnoreFlag
;
1170 W
.printEnum("SubSectionType", SubType
, ArrayRef(SubSectionTypes
));
1171 W
.printHex("SubSectionSize", SubSectionSize
);
1173 // Get the contents of the subsection.
1174 if (SubSectionSize
> Data
.size())
1175 return reportError(errorCodeToError(object_error::parse_failed
),
1176 Obj
->getFileName());
1177 StringRef Contents
= Data
.substr(0, SubSectionSize
);
1179 // Add SubSectionSize to the current offset and align that offset to find
1180 // the next subsection.
1181 size_t SectionOffset
= Data
.data() - SectionContents
.data();
1182 size_t NextOffset
= SectionOffset
+ SubSectionSize
;
1183 NextOffset
= alignTo(NextOffset
, 4);
1184 if (NextOffset
> SectionContents
.size())
1185 return reportError(errorCodeToError(object_error::parse_failed
),
1186 Obj
->getFileName());
1187 Data
= SectionContents
.drop_front(NextOffset
);
1189 // Optionally print the subsection bytes in case our parsing gets confused
1191 if (opts::CodeViewSubsectionBytes
)
1192 printBinaryBlockWithRelocs("SubSectionContents", Section
, SectionContents
,
1195 switch (DebugSubsectionKind(SubType
)) {
1196 case DebugSubsectionKind::Symbols
:
1197 printCodeViewSymbolsSubsection(Contents
, Section
, SectionContents
);
1200 case DebugSubsectionKind::InlineeLines
:
1201 printCodeViewInlineeLines(Contents
);
1204 case DebugSubsectionKind::FileChecksums
:
1205 printCodeViewFileChecksums(Contents
);
1208 case DebugSubsectionKind::Lines
: {
1209 // Holds a PC to file:line table. Some data to parse this subsection is
1210 // stored in the other subsections, so just check sanity and store the
1211 // pointers for deferred processing.
1213 if (SubSectionSize
< 12) {
1214 // There should be at least three words to store two function
1215 // relocations and size of the code.
1216 reportError(errorCodeToError(object_error::parse_failed
),
1217 Obj
->getFileName());
1221 StringRef LinkageName
;
1222 if (std::error_code EC
= resolveSymbolName(Obj
->getCOFFSection(Section
),
1223 SectionOffset
, LinkageName
))
1224 reportError(errorCodeToError(EC
), Obj
->getFileName());
1226 W
.printString("LinkageName", LinkageName
);
1227 if (FunctionLineTables
.count(LinkageName
) != 0) {
1228 // Saw debug info for this function already?
1229 reportError(errorCodeToError(object_error::parse_failed
),
1230 Obj
->getFileName());
1234 FunctionLineTables
[LinkageName
] = Contents
;
1235 FunctionNames
.push_back(LinkageName
);
1238 case DebugSubsectionKind::FrameData
: {
1239 // First four bytes is a relocation against the function.
1240 BinaryStreamReader
SR(Contents
, llvm::endianness::little
);
1242 DebugFrameDataSubsectionRef FrameData
;
1243 if (Error E
= FrameData
.initialize(SR
))
1244 reportError(std::move(E
), Obj
->getFileName());
1246 StringRef LinkageName
;
1247 if (std::error_code EC
=
1248 resolveSymbolName(Obj
->getCOFFSection(Section
), SectionContents
,
1249 FrameData
.getRelocPtr(), LinkageName
))
1250 reportError(errorCodeToError(EC
), Obj
->getFileName());
1251 W
.printString("LinkageName", LinkageName
);
1253 // To find the active frame description, search this array for the
1254 // smallest PC range that includes the current PC.
1255 for (const auto &FD
: FrameData
) {
1256 StringRef FrameFunc
= unwrapOrError(
1257 Obj
->getFileName(), CVStringTable
.getString(FD
.FrameFunc
));
1259 DictScope
S(W
, "FrameData");
1260 W
.printHex("RvaStart", FD
.RvaStart
);
1261 W
.printHex("CodeSize", FD
.CodeSize
);
1262 W
.printHex("LocalSize", FD
.LocalSize
);
1263 W
.printHex("ParamsSize", FD
.ParamsSize
);
1264 W
.printHex("MaxStackSize", FD
.MaxStackSize
);
1265 W
.printHex("PrologSize", FD
.PrologSize
);
1266 W
.printHex("SavedRegsSize", FD
.SavedRegsSize
);
1267 W
.printFlags("Flags", FD
.Flags
, ArrayRef(FrameDataFlags
));
1269 // The FrameFunc string is a small RPN program. It can be broken up into
1270 // statements that end in the '=' operator, which assigns the value on
1271 // the top of the stack to the previously pushed variable. Variables can
1272 // be temporary values ($T0) or physical registers ($esp). Print each
1273 // assignment on its own line to make these programs easier to read.
1275 ListScope
FFS(W
, "FrameFunc");
1276 while (!FrameFunc
.empty()) {
1277 size_t EqOrEnd
= FrameFunc
.find('=');
1278 if (EqOrEnd
== StringRef::npos
)
1279 EqOrEnd
= FrameFunc
.size();
1282 StringRef Stmt
= FrameFunc
.substr(0, EqOrEnd
);
1283 W
.printString(Stmt
);
1284 FrameFunc
= FrameFunc
.drop_front(EqOrEnd
).trim();
1291 // Do nothing for unrecognized subsections.
1298 // Dump the line tables now that we've read all the subsections and know all
1299 // the required information.
1300 for (unsigned I
= 0, E
= FunctionNames
.size(); I
!= E
; ++I
) {
1301 StringRef Name
= FunctionNames
[I
];
1302 ListScope
S(W
, "FunctionLineTable");
1303 W
.printString("LinkageName", Name
);
1305 BinaryStreamReader
Reader(FunctionLineTables
[Name
],
1306 llvm::endianness::little
);
1308 DebugLinesSubsectionRef LineInfo
;
1309 if (Error E
= LineInfo
.initialize(Reader
))
1310 reportError(std::move(E
), Obj
->getFileName());
1312 W
.printHex("Flags", LineInfo
.header()->Flags
);
1313 W
.printHex("CodeSize", LineInfo
.header()->CodeSize
);
1314 for (const auto &Entry
: LineInfo
) {
1316 ListScope
S(W
, "FilenameSegment");
1317 printFileNameForOffset("Filename", Entry
.NameIndex
);
1318 uint32_t ColumnIndex
= 0;
1319 for (const auto &Line
: Entry
.LineNumbers
) {
1320 if (Line
.Offset
>= LineInfo
.header()->CodeSize
) {
1321 reportError(errorCodeToError(object_error::parse_failed
),
1322 Obj
->getFileName());
1326 std::string PC
= std::string(formatv("+{0:X}", uint32_t(Line
.Offset
)));
1327 ListScope
PCScope(W
, PC
);
1328 codeview::LineInfo
LI(Line
.Flags
);
1330 if (LI
.isAlwaysStepInto())
1331 W
.printString("StepInto", StringRef("Always"));
1332 else if (LI
.isNeverStepInto())
1333 W
.printString("StepInto", StringRef("Never"));
1335 W
.printNumber("LineNumberStart", LI
.getStartLine());
1336 W
.printNumber("LineNumberEndDelta", LI
.getLineDelta());
1337 W
.printBoolean("IsStatement", LI
.isStatement());
1338 if (LineInfo
.hasColumnInfo()) {
1339 W
.printNumber("ColStart", Entry
.Columns
[ColumnIndex
].StartColumn
);
1340 W
.printNumber("ColEnd", Entry
.Columns
[ColumnIndex
].EndColumn
);
1348 void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection
,
1349 const SectionRef
&Section
,
1350 StringRef SectionContents
) {
1351 ArrayRef
<uint8_t> BinaryData(Subsection
.bytes_begin(),
1352 Subsection
.bytes_end());
1353 auto CODD
= std::make_unique
<COFFObjectDumpDelegate
>(*this, Section
, Obj
,
1355 CVSymbolDumper
CVSD(W
, Types
, CodeViewContainer::ObjectFile
, std::move(CODD
),
1356 CompilationCPUType
, opts::CodeViewSubsectionBytes
);
1357 CVSymbolArray Symbols
;
1358 BinaryStreamReader
Reader(BinaryData
, llvm::endianness::little
);
1359 if (Error E
= Reader
.readArray(Symbols
, Reader
.getLength())) {
1361 reportError(std::move(E
), Obj
->getFileName());
1364 if (Error E
= CVSD
.dump(Symbols
)) {
1366 reportError(std::move(E
), Obj
->getFileName());
1368 CompilationCPUType
= CVSD
.getCompilationCPUType();
1372 void COFFDumper::printCodeViewFileChecksums(StringRef Subsection
) {
1373 BinaryStreamRef
Stream(Subsection
, llvm::endianness::little
);
1374 DebugChecksumsSubsectionRef Checksums
;
1375 if (Error E
= Checksums
.initialize(Stream
))
1376 reportError(std::move(E
), Obj
->getFileName());
1378 for (auto &FC
: Checksums
) {
1379 DictScope
S(W
, "FileChecksum");
1381 StringRef Filename
= unwrapOrError(
1382 Obj
->getFileName(), CVStringTable
.getString(FC
.FileNameOffset
));
1383 W
.printHex("Filename", Filename
, FC
.FileNameOffset
);
1384 W
.printHex("ChecksumSize", FC
.Checksum
.size());
1385 W
.printEnum("ChecksumKind", uint8_t(FC
.Kind
),
1386 ArrayRef(FileChecksumKindNames
));
1388 W
.printBinary("ChecksumBytes", FC
.Checksum
);
1392 void COFFDumper::printCodeViewInlineeLines(StringRef Subsection
) {
1393 BinaryStreamReader
SR(Subsection
, llvm::endianness::little
);
1394 DebugInlineeLinesSubsectionRef Lines
;
1395 if (Error E
= Lines
.initialize(SR
))
1396 reportError(std::move(E
), Obj
->getFileName());
1398 for (auto &Line
: Lines
) {
1399 DictScope
S(W
, "InlineeSourceLine");
1400 printTypeIndex("Inlinee", Line
.Header
->Inlinee
);
1401 printFileNameForOffset("FileID", Line
.Header
->FileID
);
1402 W
.printNumber("SourceLineNum", Line
.Header
->SourceLineNum
);
1404 if (Lines
.hasExtraFiles()) {
1405 W
.printNumber("ExtraFileCount", Line
.ExtraFiles
.size());
1406 ListScope
ExtraFiles(W
, "ExtraFiles");
1407 for (const auto &FID
: Line
.ExtraFiles
) {
1408 printFileNameForOffset("FileID", FID
);
1414 StringRef
COFFDumper::getFileNameForFileOffset(uint32_t FileOffset
) {
1415 // The file checksum subsection should precede all references to it.
1416 if (!CVFileChecksumTable
.valid() || !CVStringTable
.valid())
1417 reportError(errorCodeToError(object_error::parse_failed
),
1418 Obj
->getFileName());
1420 auto Iter
= CVFileChecksumTable
.getArray().at(FileOffset
);
1422 // Check if the file checksum table offset is valid.
1423 if (Iter
== CVFileChecksumTable
.end())
1424 reportError(errorCodeToError(object_error::parse_failed
),
1425 Obj
->getFileName());
1427 return unwrapOrError(Obj
->getFileName(),
1428 CVStringTable
.getString(Iter
->FileNameOffset
));
1431 void COFFDumper::printFileNameForOffset(StringRef Label
, uint32_t FileOffset
) {
1432 W
.printHex(Label
, getFileNameForFileOffset(FileOffset
), FileOffset
);
1435 void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder
&CVIDs
,
1436 MergingTypeTableBuilder
&CVTypes
,
1437 GlobalTypeTableBuilder
&GlobalCVIDs
,
1438 GlobalTypeTableBuilder
&GlobalCVTypes
,
1440 for (const SectionRef
&S
: Obj
->sections()) {
1441 StringRef SectionName
= unwrapOrError(Obj
->getFileName(), S
.getName());
1442 if (SectionName
== ".debug$T") {
1443 StringRef Data
= unwrapOrError(Obj
->getFileName(), S
.getContents());
1445 if (Error E
= consume(Data
, Magic
))
1446 reportError(std::move(E
), Obj
->getFileName());
1449 reportError(errorCodeToError(object_error::parse_failed
),
1450 Obj
->getFileName());
1453 BinaryStreamReader
Reader(Data
, llvm::endianness::little
);
1454 if (auto EC
= Reader
.readArray(Types
, Reader
.getLength())) {
1455 consumeError(std::move(EC
));
1457 reportError(errorCodeToError(object_error::parse_failed
),
1458 Obj
->getFileName());
1460 SmallVector
<TypeIndex
, 128> SourceToDest
;
1461 std::optional
<PCHMergerInfo
> PCHInfo
;
1463 std::vector
<GloballyHashedType
> Hashes
=
1464 GloballyHashedType::hashTypes(Types
);
1466 mergeTypeAndIdRecords(GlobalCVIDs
, GlobalCVTypes
, SourceToDest
,
1467 Types
, Hashes
, PCHInfo
))
1468 return reportError(std::move(E
), Obj
->getFileName());
1470 if (Error E
= mergeTypeAndIdRecords(CVIDs
, CVTypes
, SourceToDest
, Types
,
1472 return reportError(std::move(E
), Obj
->getFileName());
1478 void COFFDumper::printCodeViewTypeSection(StringRef SectionName
,
1479 const SectionRef
&Section
) {
1480 ListScope
D(W
, "CodeViewTypes");
1481 W
.printNumber("Section", SectionName
, Obj
->getSectionID(Section
));
1483 StringRef Data
= unwrapOrError(Obj
->getFileName(), Section
.getContents());
1484 if (opts::CodeViewSubsectionBytes
)
1485 W
.printBinaryBlock("Data", Data
);
1488 if (Error E
= consume(Data
, Magic
))
1489 reportError(std::move(E
), Obj
->getFileName());
1491 W
.printHex("Magic", Magic
);
1492 if (Magic
!= COFF::DEBUG_SECTION_MAGIC
)
1493 reportError(errorCodeToError(object_error::parse_failed
),
1494 Obj
->getFileName());
1496 Types
.reset(Data
, 100);
1498 TypeDumpVisitor
TDV(Types
, &W
, opts::CodeViewSubsectionBytes
);
1499 if (Error E
= codeview::visitTypeStream(Types
, TDV
))
1500 reportError(std::move(E
), Obj
->getFileName());
1505 void COFFDumper::printSectionHeaders() {
1506 ListScope
SectionsD(W
, "Sections");
1507 int SectionNumber
= 0;
1508 for (const SectionRef
&Sec
: Obj
->sections()) {
1510 const coff_section
*Section
= Obj
->getCOFFSection(Sec
);
1512 StringRef Name
= unwrapOrError(Obj
->getFileName(), Sec
.getName());
1514 DictScope
D(W
, "Section");
1515 W
.printNumber("Number", SectionNumber
);
1516 W
.printBinary("Name", Name
, Section
->Name
);
1517 W
.printHex ("VirtualSize", Section
->VirtualSize
);
1518 W
.printHex ("VirtualAddress", Section
->VirtualAddress
);
1519 W
.printNumber("RawDataSize", Section
->SizeOfRawData
);
1520 W
.printHex ("PointerToRawData", Section
->PointerToRawData
);
1521 W
.printHex ("PointerToRelocations", Section
->PointerToRelocations
);
1522 W
.printHex ("PointerToLineNumbers", Section
->PointerToLinenumbers
);
1523 W
.printNumber("RelocationCount", Section
->NumberOfRelocations
);
1524 W
.printNumber("LineNumberCount", Section
->NumberOfLinenumbers
);
1525 W
.printFlags("Characteristics", Section
->Characteristics
,
1526 ArrayRef(ImageSectionCharacteristics
),
1527 COFF::SectionCharacteristics(0x00F00000));
1529 if (opts::SectionRelocations
) {
1530 ListScope
D(W
, "Relocations");
1531 for (const RelocationRef
&Reloc
: Sec
.relocations())
1532 printRelocation(Sec
, Reloc
);
1535 if (opts::SectionSymbols
) {
1536 ListScope
D(W
, "Symbols");
1537 for (const SymbolRef
&Symbol
: Obj
->symbols()) {
1538 if (!Sec
.containsSymbol(Symbol
))
1541 printSymbol(Symbol
);
1545 if (opts::SectionData
&&
1546 !(Section
->Characteristics
& COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
)) {
1547 StringRef Data
= unwrapOrError(Obj
->getFileName(), Sec
.getContents());
1548 W
.printBinaryBlock("SectionData", Data
);
1553 void COFFDumper::printRelocations() {
1554 ListScope
D(W
, "Relocations");
1556 int SectionNumber
= 0;
1557 for (const SectionRef
&Section
: Obj
->sections()) {
1559 StringRef Name
= unwrapOrError(Obj
->getFileName(), Section
.getName());
1561 bool PrintedGroup
= false;
1562 for (const RelocationRef
&Reloc
: Section
.relocations()) {
1563 if (!PrintedGroup
) {
1564 W
.startLine() << "Section (" << SectionNumber
<< ") " << Name
<< " {\n";
1566 PrintedGroup
= true;
1569 printRelocation(Section
, Reloc
);
1574 W
.startLine() << "}\n";
1579 void COFFDumper::printRelocation(const SectionRef
&Section
,
1580 const RelocationRef
&Reloc
, uint64_t Bias
) {
1581 uint64_t Offset
= Reloc
.getOffset() - Bias
;
1582 uint64_t RelocType
= Reloc
.getType();
1583 SmallString
<32> RelocName
;
1584 StringRef SymbolName
;
1585 Reloc
.getTypeName(RelocName
);
1586 symbol_iterator Symbol
= Reloc
.getSymbol();
1587 int64_t SymbolIndex
= -1;
1588 if (Symbol
!= Obj
->symbol_end()) {
1589 Expected
<StringRef
> SymbolNameOrErr
= Symbol
->getName();
1590 if (!SymbolNameOrErr
)
1591 reportError(SymbolNameOrErr
.takeError(), Obj
->getFileName());
1593 SymbolName
= *SymbolNameOrErr
;
1594 SymbolIndex
= Obj
->getSymbolIndex(Obj
->getCOFFSymbol(*Symbol
));
1597 if (opts::ExpandRelocs
) {
1598 DictScope
Group(W
, "Relocation");
1599 W
.printHex("Offset", Offset
);
1600 W
.printNumber("Type", RelocName
, RelocType
);
1601 W
.printString("Symbol", SymbolName
.empty() ? "-" : SymbolName
);
1602 W
.printNumber("SymbolIndex", SymbolIndex
);
1604 raw_ostream
& OS
= W
.startLine();
1607 << " " << (SymbolName
.empty() ? "-" : SymbolName
)
1608 << " (" << SymbolIndex
<< ")"
1613 void COFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
1614 ListScope
Group(W
, "Symbols");
1616 for (const SymbolRef
&Symbol
: Obj
->symbols())
1617 printSymbol(Symbol
);
1620 void COFFDumper::printDynamicSymbols() { ListScope
Group(W
, "DynamicSymbols"); }
1622 static Expected
<StringRef
>
1623 getSectionName(const llvm::object::COFFObjectFile
*Obj
, int32_t SectionNumber
,
1624 const coff_section
*Section
) {
1626 return Obj
->getSectionName(Section
);
1627 if (SectionNumber
== llvm::COFF::IMAGE_SYM_DEBUG
)
1628 return StringRef("IMAGE_SYM_DEBUG");
1629 if (SectionNumber
== llvm::COFF::IMAGE_SYM_ABSOLUTE
)
1630 return StringRef("IMAGE_SYM_ABSOLUTE");
1631 if (SectionNumber
== llvm::COFF::IMAGE_SYM_UNDEFINED
)
1632 return StringRef("IMAGE_SYM_UNDEFINED");
1633 return StringRef("");
1636 void COFFDumper::printSymbol(const SymbolRef
&Sym
) {
1637 DictScope
D(W
, "Symbol");
1639 COFFSymbolRef Symbol
= Obj
->getCOFFSymbol(Sym
);
1640 Expected
<const coff_section
*> SecOrErr
=
1641 Obj
->getSection(Symbol
.getSectionNumber());
1643 W
.startLine() << "Invalid section number: " << Symbol
.getSectionNumber()
1646 consumeError(SecOrErr
.takeError());
1649 const coff_section
*Section
= *SecOrErr
;
1651 StringRef SymbolName
;
1652 if (Expected
<StringRef
> SymNameOrErr
= Obj
->getSymbolName(Symbol
))
1653 SymbolName
= *SymNameOrErr
;
1655 StringRef SectionName
;
1656 if (Expected
<StringRef
> SecNameOrErr
=
1657 getSectionName(Obj
, Symbol
.getSectionNumber(), Section
))
1658 SectionName
= *SecNameOrErr
;
1660 W
.printString("Name", SymbolName
);
1661 W
.printNumber("Value", Symbol
.getValue());
1662 W
.printNumber("Section", SectionName
, Symbol
.getSectionNumber());
1663 W
.printEnum("BaseType", Symbol
.getBaseType(), ArrayRef(ImageSymType
));
1664 W
.printEnum("ComplexType", Symbol
.getComplexType(), ArrayRef(ImageSymDType
));
1665 W
.printEnum("StorageClass", Symbol
.getStorageClass(),
1666 ArrayRef(ImageSymClass
));
1667 W
.printNumber("AuxSymbolCount", Symbol
.getNumberOfAuxSymbols());
1669 for (uint8_t I
= 0; I
< Symbol
.getNumberOfAuxSymbols(); ++I
) {
1670 if (Symbol
.isFunctionDefinition()) {
1671 const coff_aux_function_definition
*Aux
;
1672 if (std::error_code EC
= getSymbolAuxData(Obj
, Symbol
, I
, Aux
))
1673 reportError(errorCodeToError(EC
), Obj
->getFileName());
1675 DictScope
AS(W
, "AuxFunctionDef");
1676 W
.printNumber("TagIndex", Aux
->TagIndex
);
1677 W
.printNumber("TotalSize", Aux
->TotalSize
);
1678 W
.printHex("PointerToLineNumber", Aux
->PointerToLinenumber
);
1679 W
.printHex("PointerToNextFunction", Aux
->PointerToNextFunction
);
1681 } else if (Symbol
.isAnyUndefined()) {
1682 const coff_aux_weak_external
*Aux
;
1683 if (std::error_code EC
= getSymbolAuxData(Obj
, Symbol
, I
, Aux
))
1684 reportError(errorCodeToError(EC
), Obj
->getFileName());
1686 DictScope
AS(W
, "AuxWeakExternal");
1687 W
.printNumber("Linked", getSymbolName(Aux
->TagIndex
), Aux
->TagIndex
);
1688 W
.printEnum("Search", Aux
->Characteristics
,
1689 ArrayRef(WeakExternalCharacteristics
));
1691 } else if (Symbol
.isFileRecord()) {
1692 const char *FileName
;
1693 if (std::error_code EC
= getSymbolAuxData(Obj
, Symbol
, I
, FileName
))
1694 reportError(errorCodeToError(EC
), Obj
->getFileName());
1695 DictScope
AS(W
, "AuxFileRecord");
1697 StringRef
Name(FileName
, Symbol
.getNumberOfAuxSymbols() *
1698 Obj
->getSymbolTableEntrySize());
1699 W
.printString("FileName", Name
.rtrim(StringRef("\0", 1)));
1701 } else if (Symbol
.isSectionDefinition()) {
1702 const coff_aux_section_definition
*Aux
;
1703 if (std::error_code EC
= getSymbolAuxData(Obj
, Symbol
, I
, Aux
))
1704 reportError(errorCodeToError(EC
), Obj
->getFileName());
1706 int32_t AuxNumber
= Aux
->getNumber(Symbol
.isBigObj());
1708 DictScope
AS(W
, "AuxSectionDef");
1709 W
.printNumber("Length", Aux
->Length
);
1710 W
.printNumber("RelocationCount", Aux
->NumberOfRelocations
);
1711 W
.printNumber("LineNumberCount", Aux
->NumberOfLinenumbers
);
1712 W
.printHex("Checksum", Aux
->CheckSum
);
1713 W
.printNumber("Number", AuxNumber
);
1714 W
.printEnum("Selection", Aux
->Selection
, ArrayRef(ImageCOMDATSelect
));
1716 if (Section
&& Section
->Characteristics
& COFF::IMAGE_SCN_LNK_COMDAT
1717 && Aux
->Selection
== COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
) {
1718 Expected
<const coff_section
*> Assoc
= Obj
->getSection(AuxNumber
);
1720 reportError(Assoc
.takeError(), Obj
->getFileName());
1721 Expected
<StringRef
> AssocName
= getSectionName(Obj
, AuxNumber
, *Assoc
);
1723 reportError(AssocName
.takeError(), Obj
->getFileName());
1725 W
.printNumber("AssocSection", *AssocName
, AuxNumber
);
1727 } else if (Symbol
.isCLRToken()) {
1728 const coff_aux_clr_token
*Aux
;
1729 if (std::error_code EC
= getSymbolAuxData(Obj
, Symbol
, I
, Aux
))
1730 reportError(errorCodeToError(EC
), Obj
->getFileName());
1732 DictScope
AS(W
, "AuxCLRToken");
1733 W
.printNumber("AuxType", Aux
->AuxType
);
1734 W
.printNumber("Reserved", Aux
->Reserved
);
1735 W
.printNumber("SymbolTableIndex", getSymbolName(Aux
->SymbolTableIndex
),
1736 Aux
->SymbolTableIndex
);
1739 W
.startLine() << "<unhandled auxiliary record>\n";
1744 void COFFDumper::printUnwindInfo() {
1745 ListScope
D(W
, "UnwindInformation");
1746 switch (Obj
->getMachine()) {
1747 case COFF::IMAGE_FILE_MACHINE_AMD64
: {
1748 Win64EH::Dumper
Dumper(W
);
1749 Win64EH::Dumper::SymbolResolver
1750 Resolver
= [](const object::coff_section
*Section
, uint64_t Offset
,
1751 SymbolRef
&Symbol
, void *user_data
) -> std::error_code
{
1752 COFFDumper
*Dumper
= reinterpret_cast<COFFDumper
*>(user_data
);
1753 return Dumper
->resolveSymbol(Section
, Offset
, Symbol
);
1755 Win64EH::Dumper::Context
Ctx(*Obj
, Resolver
, this);
1756 Dumper
.printData(Ctx
);
1759 case COFF::IMAGE_FILE_MACHINE_ARM64
:
1760 case COFF::IMAGE_FILE_MACHINE_ARM64EC
:
1761 case COFF::IMAGE_FILE_MACHINE_ARM64X
:
1762 case COFF::IMAGE_FILE_MACHINE_ARMNT
: {
1763 ARM::WinEH::Decoder
Decoder(W
, Obj
->getMachine() !=
1764 COFF::IMAGE_FILE_MACHINE_ARMNT
);
1765 // TODO Propagate the error.
1766 consumeError(Decoder
.dumpProcedureData(*Obj
));
1770 W
.printEnum("unsupported Image Machine", Obj
->getMachine(),
1771 ArrayRef(ImageFileMachineType
));
1776 void COFFDumper::printNeededLibraries() {
1777 ListScope
D(W
, "NeededLibraries");
1779 using LibsTy
= std::vector
<StringRef
>;
1782 for (const ImportDirectoryEntryRef
&DirRef
: Obj
->import_directories()) {
1784 if (!DirRef
.getName(Name
))
1785 Libs
.push_back(Name
);
1788 llvm::stable_sort(Libs
);
1790 for (const auto &L
: Libs
) {
1791 W
.startLine() << L
<< "\n";
1795 void COFFDumper::printImportedSymbols(
1796 iterator_range
<imported_symbol_iterator
> Range
) {
1797 for (const ImportedSymbolRef
&I
: Range
) {
1799 if (Error E
= I
.getSymbolName(Sym
))
1800 reportError(std::move(E
), Obj
->getFileName());
1802 if (Error E
= I
.getOrdinal(Ordinal
))
1803 reportError(std::move(E
), Obj
->getFileName());
1804 W
.printNumber("Symbol", Sym
, Ordinal
);
1808 void COFFDumper::printDelayImportedSymbols(
1809 const DelayImportDirectoryEntryRef
&I
,
1810 iterator_range
<imported_symbol_iterator
> Range
) {
1812 for (const ImportedSymbolRef
&S
: Range
) {
1813 DictScope
Import(W
, "Import");
1815 if (Error E
= S
.getSymbolName(Sym
))
1816 reportError(std::move(E
), Obj
->getFileName());
1819 if (Error E
= S
.getOrdinal(Ordinal
))
1820 reportError(std::move(E
), Obj
->getFileName());
1821 W
.printNumber("Symbol", Sym
, Ordinal
);
1824 if (Error E
= I
.getImportAddress(Index
++, Addr
))
1825 reportError(std::move(E
), Obj
->getFileName());
1826 W
.printHex("Address", Addr
);
1830 void COFFDumper::printCOFFImports() {
1832 for (const ImportDirectoryEntryRef
&I
: Obj
->import_directories()) {
1833 DictScope
Import(W
, "Import");
1835 if (Error E
= I
.getName(Name
))
1836 reportError(std::move(E
), Obj
->getFileName());
1837 W
.printString("Name", Name
);
1839 if (Error E
= I
.getImportLookupTableRVA(ILTAddr
))
1840 reportError(std::move(E
), Obj
->getFileName());
1841 W
.printHex("ImportLookupTableRVA", ILTAddr
);
1843 if (Error E
= I
.getImportAddressTableRVA(IATAddr
))
1844 reportError(std::move(E
), Obj
->getFileName());
1845 W
.printHex("ImportAddressTableRVA", IATAddr
);
1846 // The import lookup table can be missing with certain older linkers, so
1847 // fall back to the import address table in that case.
1849 printImportedSymbols(I
.lookup_table_symbols());
1851 printImportedSymbols(I
.imported_symbols());
1855 for (const DelayImportDirectoryEntryRef
&I
: Obj
->delay_import_directories()) {
1856 DictScope
Import(W
, "DelayImport");
1858 if (Error E
= I
.getName(Name
))
1859 reportError(std::move(E
), Obj
->getFileName());
1860 W
.printString("Name", Name
);
1861 const delay_import_directory_table_entry
*Table
;
1862 if (Error E
= I
.getDelayImportTable(Table
))
1863 reportError(std::move(E
), Obj
->getFileName());
1864 W
.printHex("Attributes", Table
->Attributes
);
1865 W
.printHex("ModuleHandle", Table
->ModuleHandle
);
1866 W
.printHex("ImportAddressTable", Table
->DelayImportAddressTable
);
1867 W
.printHex("ImportNameTable", Table
->DelayImportNameTable
);
1868 W
.printHex("BoundDelayImportTable", Table
->BoundDelayImportTable
);
1869 W
.printHex("UnloadDelayImportTable", Table
->UnloadDelayImportTable
);
1870 printDelayImportedSymbols(I
, I
.imported_symbols());
1874 void COFFDumper::printCOFFExports() {
1875 for (const ExportDirectoryEntryRef
&Exp
: Obj
->export_directories()) {
1876 DictScope
Export(W
, "Export");
1882 if (Error E
= Exp
.getSymbolName(Name
))
1883 reportError(std::move(E
), Obj
->getFileName());
1884 if (Error E
= Exp
.getOrdinal(Ordinal
))
1885 reportError(std::move(E
), Obj
->getFileName());
1886 if (Error E
= Exp
.isForwarder(IsForwarder
))
1887 reportError(std::move(E
), Obj
->getFileName());
1889 W
.printNumber("Ordinal", Ordinal
);
1890 W
.printString("Name", Name
);
1891 StringRef ForwardTo
;
1893 if (Error E
= Exp
.getForwardTo(ForwardTo
))
1894 reportError(std::move(E
), Obj
->getFileName());
1895 W
.printString("ForwardedTo", ForwardTo
);
1898 if (Error E
= Exp
.getExportRVA(RVA
))
1899 reportError(std::move(E
), Obj
->getFileName());
1900 W
.printHex("RVA", RVA
);
1905 void COFFDumper::printCOFFDirectives() {
1906 for (const SectionRef
&Section
: Obj
->sections()) {
1907 StringRef Name
= unwrapOrError(Obj
->getFileName(), Section
.getName());
1908 if (Name
!= ".drectve")
1911 StringRef Contents
=
1912 unwrapOrError(Obj
->getFileName(), Section
.getContents());
1913 W
.printString("Directive(s)", Contents
);
1917 static std::string
getBaseRelocTypeName(uint8_t Type
) {
1919 case COFF::IMAGE_REL_BASED_ABSOLUTE
: return "ABSOLUTE";
1920 case COFF::IMAGE_REL_BASED_HIGH
: return "HIGH";
1921 case COFF::IMAGE_REL_BASED_LOW
: return "LOW";
1922 case COFF::IMAGE_REL_BASED_HIGHLOW
: return "HIGHLOW";
1923 case COFF::IMAGE_REL_BASED_HIGHADJ
: return "HIGHADJ";
1924 case COFF::IMAGE_REL_BASED_ARM_MOV32T
: return "ARM_MOV32(T)";
1925 case COFF::IMAGE_REL_BASED_DIR64
: return "DIR64";
1926 default: return "unknown (" + llvm::utostr(Type
) + ")";
1930 void COFFDumper::printCOFFBaseReloc() {
1931 ListScope
D(W
, "BaseReloc");
1932 for (const BaseRelocRef
&I
: Obj
->base_relocs()) {
1935 if (Error E
= I
.getRVA(RVA
))
1936 reportError(std::move(E
), Obj
->getFileName());
1937 if (Error E
= I
.getType(Type
))
1938 reportError(std::move(E
), Obj
->getFileName());
1939 DictScope
Import(W
, "Entry");
1940 W
.printString("Type", getBaseRelocTypeName(Type
));
1941 W
.printHex("Address", RVA
);
1945 void COFFDumper::printCOFFResources() {
1946 ListScope
ResourcesD(W
, "Resources");
1947 for (const SectionRef
&S
: Obj
->sections()) {
1948 StringRef Name
= unwrapOrError(Obj
->getFileName(), S
.getName());
1949 if (!Name
.startswith(".rsrc"))
1952 StringRef Ref
= unwrapOrError(Obj
->getFileName(), S
.getContents());
1954 if ((Name
== ".rsrc") || (Name
== ".rsrc$01")) {
1955 ResourceSectionRef RSF
;
1956 Error E
= RSF
.load(Obj
, S
);
1958 reportError(std::move(E
), Obj
->getFileName());
1959 auto &BaseTable
= unwrapOrError(Obj
->getFileName(), RSF
.getBaseTable());
1960 W
.printNumber("Total Number of Resources",
1961 countTotalTableEntries(RSF
, BaseTable
, "Type"));
1962 W
.printHex("Base Table Address",
1963 Obj
->getCOFFSection(S
)->PointerToRawData
);
1964 W
.startLine() << "\n";
1965 printResourceDirectoryTable(RSF
, BaseTable
, "Type");
1967 if (opts::SectionData
)
1968 W
.printBinaryBlock(Name
.str() + " Data", Ref
);
1973 COFFDumper::countTotalTableEntries(ResourceSectionRef RSF
,
1974 const coff_resource_dir_table
&Table
,
1976 uint32_t TotalEntries
= 0;
1977 for (int i
= 0; i
< Table
.NumberOfNameEntries
+ Table
.NumberOfIDEntries
;
1979 auto Entry
= unwrapOrError(Obj
->getFileName(), RSF
.getTableEntry(Table
, i
));
1980 if (Entry
.Offset
.isSubDir()) {
1981 StringRef NextLevel
;
1982 if (Level
== "Name")
1983 NextLevel
= "Language";
1987 unwrapOrError(Obj
->getFileName(), RSF
.getEntrySubDir(Entry
));
1988 TotalEntries
+= countTotalTableEntries(RSF
, NextTable
, NextLevel
);
1993 return TotalEntries
;
1996 void COFFDumper::printResourceDirectoryTable(
1997 ResourceSectionRef RSF
, const coff_resource_dir_table
&Table
,
2000 W
.printNumber("Number of String Entries", Table
.NumberOfNameEntries
);
2001 W
.printNumber("Number of ID Entries", Table
.NumberOfIDEntries
);
2003 // Iterate through level in resource directory tree.
2004 for (int i
= 0; i
< Table
.NumberOfNameEntries
+ Table
.NumberOfIDEntries
;
2006 auto Entry
= unwrapOrError(Obj
->getFileName(), RSF
.getTableEntry(Table
, i
));
2008 SmallString
<20> IDStr
;
2009 raw_svector_ostream
OS(IDStr
);
2010 if (i
< Table
.NumberOfNameEntries
) {
2011 ArrayRef
<UTF16
> RawEntryNameString
=
2012 unwrapOrError(Obj
->getFileName(), RSF
.getEntryNameString(Entry
));
2013 std::vector
<UTF16
> EndianCorrectedNameString
;
2014 if (llvm::sys::IsBigEndianHost
) {
2015 EndianCorrectedNameString
.resize(RawEntryNameString
.size() + 1);
2016 std::copy(RawEntryNameString
.begin(), RawEntryNameString
.end(),
2017 EndianCorrectedNameString
.begin() + 1);
2018 EndianCorrectedNameString
[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
;
2019 RawEntryNameString
= ArrayRef(EndianCorrectedNameString
);
2021 std::string EntryNameString
;
2022 if (!llvm::convertUTF16ToUTF8String(RawEntryNameString
, EntryNameString
))
2023 reportError(errorCodeToError(object_error::parse_failed
),
2024 Obj
->getFileName());
2026 OS
<< EntryNameString
;
2028 if (Level
== "Type") {
2030 printResourceTypeName(Entry
.Identifier
.ID
, OS
);
2032 OS
<< ": (ID " << Entry
.Identifier
.ID
<< ")";
2036 ListScope
ResourceType(W
, Level
.str() + Name
.str());
2037 if (Entry
.Offset
.isSubDir()) {
2038 W
.printHex("Table Offset", Entry
.Offset
.value());
2039 StringRef NextLevel
;
2040 if (Level
== "Name")
2041 NextLevel
= "Language";
2045 unwrapOrError(Obj
->getFileName(), RSF
.getEntrySubDir(Entry
));
2046 printResourceDirectoryTable(RSF
, NextTable
, NextLevel
);
2048 W
.printHex("Entry Offset", Entry
.Offset
.value());
2049 char FormattedTime
[20] = {};
2050 time_t TDS
= time_t(Table
.TimeDateStamp
);
2051 strftime(FormattedTime
, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS
));
2052 W
.printHex("Time/Date Stamp", FormattedTime
, Table
.TimeDateStamp
);
2053 W
.printNumber("Major Version", Table
.MajorVersion
);
2054 W
.printNumber("Minor Version", Table
.MinorVersion
);
2055 W
.printNumber("Characteristics", Table
.Characteristics
);
2056 ListScope
DataScope(W
, "Data");
2058 unwrapOrError(Obj
->getFileName(), RSF
.getEntryData(Entry
));
2059 W
.printHex("DataRVA", DataEntry
.DataRVA
);
2060 W
.printNumber("DataSize", DataEntry
.DataSize
);
2061 W
.printNumber("Codepage", DataEntry
.Codepage
);
2062 W
.printNumber("Reserved", DataEntry
.Reserved
);
2063 StringRef Contents
=
2064 unwrapOrError(Obj
->getFileName(), RSF
.getContents(DataEntry
));
2065 W
.printBinaryBlock("Data", Contents
);
2070 void COFFDumper::printStackMap() const {
2071 SectionRef StackMapSection
;
2072 for (auto Sec
: Obj
->sections()) {
2074 if (Expected
<StringRef
> NameOrErr
= Sec
.getName())
2077 consumeError(NameOrErr
.takeError());
2079 if (Name
== ".llvm_stackmaps") {
2080 StackMapSection
= Sec
;
2085 if (StackMapSection
== SectionRef())
2088 StringRef StackMapContents
=
2089 unwrapOrError(Obj
->getFileName(), StackMapSection
.getContents());
2090 ArrayRef
<uint8_t> StackMapContentsArray
=
2091 arrayRefFromStringRef(StackMapContents
);
2093 if (Obj
->isLittleEndian())
2094 prettyPrintStackMap(
2095 W
, StackMapParser
<llvm::endianness::little
>(StackMapContentsArray
));
2097 prettyPrintStackMap(
2098 W
, StackMapParser
<llvm::endianness::big
>(StackMapContentsArray
));
2101 void COFFDumper::printAddrsig() {
2102 SectionRef AddrsigSection
;
2103 for (auto Sec
: Obj
->sections()) {
2105 if (Expected
<StringRef
> NameOrErr
= Sec
.getName())
2108 consumeError(NameOrErr
.takeError());
2110 if (Name
== ".llvm_addrsig") {
2111 AddrsigSection
= Sec
;
2116 if (AddrsigSection
== SectionRef())
2119 StringRef AddrsigContents
=
2120 unwrapOrError(Obj
->getFileName(), AddrsigSection
.getContents());
2121 ArrayRef
<uint8_t> AddrsigContentsArray(AddrsigContents
.bytes_begin(),
2122 AddrsigContents
.size());
2124 ListScope
L(W
, "Addrsig");
2125 const uint8_t *Cur
= AddrsigContents
.bytes_begin();
2126 const uint8_t *End
= AddrsigContents
.bytes_end();
2127 while (Cur
!= End
) {
2130 uint64_t SymIndex
= decodeULEB128(Cur
, &Size
, End
, &Err
);
2132 reportError(createError(Err
), Obj
->getFileName());
2134 W
.printNumber("Sym", getSymbolName(SymIndex
), SymIndex
);
2139 void COFFDumper::printCGProfile() {
2140 SectionRef CGProfileSection
;
2141 for (SectionRef Sec
: Obj
->sections()) {
2142 StringRef Name
= unwrapOrError(Obj
->getFileName(), Sec
.getName());
2143 if (Name
== ".llvm.call-graph-profile") {
2144 CGProfileSection
= Sec
;
2149 if (CGProfileSection
== SectionRef())
2152 StringRef CGProfileContents
=
2153 unwrapOrError(Obj
->getFileName(), CGProfileSection
.getContents());
2154 BinaryStreamReader
Reader(CGProfileContents
, llvm::endianness::little
);
2156 ListScope
L(W
, "CGProfile");
2157 while (!Reader
.empty()) {
2158 uint32_t FromIndex
, ToIndex
;
2160 if (Error Err
= Reader
.readInteger(FromIndex
))
2161 reportError(std::move(Err
), Obj
->getFileName());
2162 if (Error Err
= Reader
.readInteger(ToIndex
))
2163 reportError(std::move(Err
), Obj
->getFileName());
2164 if (Error Err
= Reader
.readInteger(Count
))
2165 reportError(std::move(Err
), Obj
->getFileName());
2167 DictScope
D(W
, "CGProfileEntry");
2168 W
.printNumber("From", getSymbolName(FromIndex
), FromIndex
);
2169 W
.printNumber("To", getSymbolName(ToIndex
), ToIndex
);
2170 W
.printNumber("Weight", Count
);
2174 StringRef
COFFDumper::getSymbolName(uint32_t Index
) {
2175 Expected
<COFFSymbolRef
> Sym
= Obj
->getSymbol(Index
);
2177 reportError(Sym
.takeError(), Obj
->getFileName());
2179 Expected
<StringRef
> SymName
= Obj
->getSymbolName(*Sym
);
2181 reportError(SymName
.takeError(), Obj
->getFileName());
2186 void llvm::dumpCodeViewMergedTypes(ScopedPrinter
&Writer
,
2187 ArrayRef
<ArrayRef
<uint8_t>> IpiRecords
,
2188 ArrayRef
<ArrayRef
<uint8_t>> TpiRecords
) {
2189 TypeTableCollection
TpiTypes(TpiRecords
);
2191 ListScope
S(Writer
, "MergedTypeStream");
2192 TypeDumpVisitor
TDV(TpiTypes
, &Writer
, opts::CodeViewSubsectionBytes
);
2193 if (Error Err
= codeview::visitTypeStream(TpiTypes
, TDV
))
2194 reportError(std::move(Err
), "<?>");
2198 // Flatten the id stream and print it next. The ID stream refers to names from
2200 TypeTableCollection
IpiTypes(IpiRecords
);
2202 ListScope
S(Writer
, "MergedIDStream");
2203 TypeDumpVisitor
TDV(TpiTypes
, &Writer
, opts::CodeViewSubsectionBytes
);
2204 TDV
.setIpiTypes(IpiTypes
);
2205 if (Error Err
= codeview::visitTypeStream(IpiTypes
, TDV
))
2206 reportError(std::move(Err
), "<?>");
2211 void COFFDumper::printCOFFTLSDirectory() {
2213 printCOFFTLSDirectory(Obj
->getTLSDirectory64());
2215 printCOFFTLSDirectory(Obj
->getTLSDirectory32());
2218 template <typename IntTy
>
2219 void COFFDumper::printCOFFTLSDirectory(
2220 const coff_tls_directory
<IntTy
> *TlsTable
) {
2221 DictScope
D(W
, "TLSDirectory");
2225 W
.printHex("StartAddressOfRawData", TlsTable
->StartAddressOfRawData
);
2226 W
.printHex("EndAddressOfRawData", TlsTable
->EndAddressOfRawData
);
2227 W
.printHex("AddressOfIndex", TlsTable
->AddressOfIndex
);
2228 W
.printHex("AddressOfCallBacks", TlsTable
->AddressOfCallBacks
);
2229 W
.printHex("SizeOfZeroFill", TlsTable
->SizeOfZeroFill
);
2230 W
.printFlags("Characteristics", TlsTable
->Characteristics
,
2231 ArrayRef(ImageSectionCharacteristics
),
2232 COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK
));