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