Skip to content

Commit 7f288db

Browse files
luqmanacuviper
authored andcommitted
[llvm-readobj] Add --coff-tls-directory flag to print TLS Directory & test.
Akin to dumpbin's /TLS option, this will print out the TLS directory, if present, in the image. Example output: ``` > llvm-readobj --coff-tls-directory test.exe File: test.exe Format: COFF-x86-64 Arch: x86_64 AddressSize: 64bit TLSDirectory { StartAddressOfRawData: 0x140004000 EndAddressOfRawData: 0x140004040 AddressOfIndex: 0x140002000 AddressOfCallBacks: 0x0 SizeOfZeroFill: 0x0 Characteristics [ (0x0) ] } ``` Reviewed By: jhenderson, grimar Differential Revision: https://reviews.llvm.org/D88635
1 parent 76cda82 commit 7f288db

File tree

8 files changed

+250
-2
lines changed

8 files changed

+250
-2
lines changed

llvm/docs/CommandGuide/llvm-readobj.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ The following options are implemented only for the PE/COFF file format.
286286

287287
Display the debug directory.
288288

289+
.. option:: --coff-tls-directory
290+
291+
Display the TLS directory.
292+
289293
.. option:: --coff-directives
290294

291295
Display the .drectve section.

llvm/include/llvm/BinaryFormat/COFF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ enum SectionCharacteristics : uint32_t {
311311
IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
312312
IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
313313
IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
314+
IMAGE_SCN_ALIGN_MASK = 0x00F00000,
314315
IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
315316
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
316317
IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,

llvm/include/llvm/Object/COFF.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,8 @@ class COFFObjectFile : public ObjectFile {
786786
const coff_base_reloc_block_header *BaseRelocEnd;
787787
const debug_directory *DebugDirectoryBegin;
788788
const debug_directory *DebugDirectoryEnd;
789+
const coff_tls_directory32 *TLSDirectory32;
790+
const coff_tls_directory64 *TLSDirectory64;
789791
// Either coff_load_configuration32 or coff_load_configuration64.
790792
const void *LoadConfig = nullptr;
791793

@@ -805,6 +807,7 @@ class COFFObjectFile : public ObjectFile {
805807
Error initExportTablePtr();
806808
Error initBaseRelocPtr();
807809
Error initDebugDirectoryPtr();
810+
Error initTLSDirectoryPtr();
808811
Error initLoadConfigPtr();
809812

810813
public:
@@ -976,6 +979,13 @@ class COFFObjectFile : public ObjectFile {
976979
return make_range(debug_directory_begin(), debug_directory_end());
977980
}
978981

982+
const coff_tls_directory32 *getTLSDirectory32() const {
983+
return TLSDirectory32;
984+
}
985+
const coff_tls_directory64 *getTLSDirectory64() const {
986+
return TLSDirectory64;
987+
}
988+
979989
const dos_header *getDOSHeader() const {
980990
if (!PE32Header && !PE32PlusHeader)
981991
return nullptr;

llvm/lib/Object/COFFObjectFile.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,38 @@ Error COFFObjectFile::initDebugDirectoryPtr() {
649649
return Error::success();
650650
}
651651

652+
Error COFFObjectFile::initTLSDirectoryPtr() {
653+
// Get the RVA of the TLS directory. Do nothing if it does not exist.
654+
const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
655+
if (!DataEntry)
656+
return Error::success();
657+
658+
// Do nothing if the RVA is NULL.
659+
if (DataEntry->RelativeVirtualAddress == 0)
660+
return Error::success();
661+
662+
uint64_t DirSize =
663+
is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);
664+
665+
// Check that the size is correct.
666+
if (DataEntry->Size != DirSize)
667+
return createStringError(
668+
object_error::parse_failed,
669+
"TLS Directory size (%u) is not the expected size (%u).",
670+
static_cast<uint32_t>(DataEntry->Size), DirSize);
671+
672+
uintptr_t IntPtr = 0;
673+
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
674+
return E;
675+
676+
if (is64())
677+
TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
678+
else
679+
TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
680+
681+
return Error::success();
682+
}
683+
652684
Error COFFObjectFile::initLoadConfigPtr() {
653685
// Get the RVA of the debug directory. Do nothing if it does not exist.
654686
const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
@@ -682,7 +714,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
682714
ImportDirectory(nullptr), DelayImportDirectory(nullptr),
683715
NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
684716
BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
685-
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {}
717+
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
718+
TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
686719

687720
Error COFFObjectFile::initialize() {
688721
// Check that we at least have enough room for a header.
@@ -809,10 +842,14 @@ Error COFFObjectFile::initialize() {
809842
if (Error E = initBaseRelocPtr())
810843
return E;
811844

812-
// Initialize the pointer to the export table.
845+
// Initialize the pointer to the debug directory.
813846
if (Error E = initDebugDirectoryPtr())
814847
return E;
815848

849+
// Initialize the pointer to the TLS directory.
850+
if (Error E = initTLSDirectoryPtr())
851+
return E;
852+
816853
if (Error E = initLoadConfigPtr())
817854
return E;
818855

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
## Tests for the --coff-tls-directory flag.
2+
3+
## Test that the output of --coff-tls-directory works on x86.
4+
## The binary created from this yaml definition is such that .rdata contains
5+
## only the IMAGE_TLS_DIRECTORY structure and hence we should have that
6+
## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress.
7+
## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory32) == sizeof(IMAGE_TLS_DIRECTORY32) == 24
8+
9+
# RUN: yaml2obj %s --docnum=1 -o %t.32.exe -DTLSRVA=10000 -DTLSSIZE=24
10+
# RUN: llvm-readobj --coff-tls-directory %t.32.exe | FileCheck %s --check-prefix I386
11+
12+
# I386: Arch: i386
13+
# I386-NEXT: AddressSize: 32bit
14+
# I386-NEXT: TLSDirectory {
15+
# I386-NEXT: StartAddressOfRawData: 0x404000
16+
# I386-NEXT: EndAddressOfRawData: 0x404008
17+
# I386-NEXT: AddressOfIndex: 0x402000
18+
# I386-NEXT: AddressOfCallBacks: 0x0
19+
# I386-NEXT: SizeOfZeroFill: 0x0
20+
# I386-NEXT: Characteristics [ (0x300000)
21+
# I386-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000)
22+
# I386-NEXT: ]
23+
# I386-NEXT: }
24+
25+
26+
## Test that the output of --coff-tls-directory errors on malformed input.
27+
## On x86, the TLS directory should be 24 bytes.
28+
## This test has a truncated TLS directory.
29+
30+
# RUN: yaml2obj %s --docnum=1 -o %t.wrong-size.32.exe -DTLSRVA=10000 -DTLSSIZE=10
31+
# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.32.exe 2>&1 | FileCheck %s --check-prefix I386-WRONG-SIZE-ERR
32+
33+
# I386-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (10) is not the expected size (24).
34+
35+
--- !COFF
36+
OptionalHeader:
37+
AddressOfEntryPoint: 0
38+
ImageBase: 0
39+
SectionAlignment: 4096
40+
FileAlignment: 512
41+
MajorOperatingSystemVersion: 0
42+
MinorOperatingSystemVersion: 0
43+
MajorImageVersion: 0
44+
MinorImageVersion: 0
45+
MajorSubsystemVersion: 0
46+
MinorSubsystemVersion: 0
47+
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
48+
DLLCharacteristics: []
49+
SizeOfStackReserve: 0
50+
SizeOfStackCommit: 0
51+
SizeOfHeapReserve: 0
52+
SizeOfHeapCommit: 0
53+
TlsTable:
54+
RelativeVirtualAddress: [[TLSRVA]]
55+
Size: [[TLSSIZE]]
56+
header:
57+
Machine: IMAGE_FILE_MACHINE_I386
58+
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE ]
59+
sections:
60+
- Name: .rdata
61+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
62+
VirtualAddress: 10000
63+
VirtualSize: 24
64+
SectionData: '004040000840400000204000000000000000000000003000'
65+
symbols: []
66+
67+
68+
## Test that the output of --coff-tls-directory works on x86_64.
69+
## The binary created from this yaml definition is such that .rdata contains
70+
## only the IMAGE_TLS_DIRECTORY structure and hence we should have that
71+
## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress.
72+
## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory64) == sizeof(IMAGE_TLS_DIRECTORY64) == 40
73+
74+
# RUN: yaml2obj %s --docnum=2 -o %t.64.exe -DTLSRVA=10000 -DTLSSIZE=40
75+
# RUN: llvm-readobj --coff-tls-directory %t.64.exe | FileCheck %s --check-prefix X86-64
76+
77+
# X86-64: Arch: x86_64
78+
# X86-64-NEXT: AddressSize: 64bit
79+
# X86-64-NEXT: TLSDirectory {
80+
# X86-64-NEXT: StartAddressOfRawData: 0x140004000
81+
# X86-64-NEXT: EndAddressOfRawData: 0x140004008
82+
# X86-64-NEXT: AddressOfIndex: 0x140002000
83+
# X86-64-NEXT: AddressOfCallBacks: 0x0
84+
# X86-64-NEXT: SizeOfZeroFill: 0x0
85+
# X86-64-NEXT: Characteristics [ (0x300000)
86+
# X86-64-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000)
87+
# X86-64-NEXT: ]
88+
# X86-64-NEXT: }
89+
90+
91+
## Test that the output of --coff-tls-directory errors on malformed input.
92+
93+
## On x86-64, the TLS directory should be 40 bytes.
94+
## This test has an erroneously lengthened TLS directory.
95+
96+
# RUN: yaml2obj %s --docnum=2 -o %t.wrong-size.64.exe -DTLSRVA=10000 -DTLSSIZE=80
97+
# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.64.exe 2>&1 | FileCheck %s --check-prefix X86-64-WRONG-SIZE-ERR
98+
99+
# X86-64-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (80) is not the expected size (40).
100+
101+
102+
## This test has a correct TLS Directory size but the RVA is invalid.
103+
104+
# RUN: yaml2obj %s --docnum=2 -o %t.bad-tls-rva.exe -DTLSRVA=999999 -DTLSSIZE=40
105+
# RUN: not llvm-readobj --coff-tls-directory %t.bad-tls-rva.exe 2>&1 | FileCheck %s --check-prefix BAD-TLS-RVA-ERR
106+
107+
# BAD-TLS-RVA-ERR: error: '{{.*}}': Invalid data was encountered while parsing the file
108+
109+
--- !COFF
110+
OptionalHeader:
111+
AddressOfEntryPoint: 0
112+
ImageBase: 0
113+
SectionAlignment: 4096
114+
FileAlignment: 512
115+
MajorOperatingSystemVersion: 0
116+
MinorOperatingSystemVersion: 0
117+
MajorImageVersion: 0
118+
MinorImageVersion: 0
119+
MajorSubsystemVersion: 0
120+
MinorSubsystemVersion: 0
121+
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
122+
DLLCharacteristics: []
123+
SizeOfStackReserve: 0
124+
SizeOfStackCommit: 0
125+
SizeOfHeapReserve: 0
126+
SizeOfHeapCommit: 0
127+
TlsTable:
128+
RelativeVirtualAddress: [[TLSRVA]]
129+
Size: [[TLSSIZE]]
130+
header:
131+
Machine: IMAGE_FILE_MACHINE_AMD64
132+
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
133+
sections:
134+
- Name: .rdata
135+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
136+
VirtualAddress: 10000
137+
VirtualSize: 40
138+
SectionData: '00400040010000000840004001000000002000400100000000000000000000000000000000003000'
139+
symbols: []
140+
141+
142+
## Test that --coff-tls-directory doesn't output anything if there's no TLS directory.
143+
144+
## Case 1: TlsTable.RelativeVirtualAddress/Size = 0.
145+
146+
# RUN: yaml2obj %s --docnum=2 -o %t.no-tls1.exe -DTLSRVA=0 -DTLSSIZE=0
147+
# RUN: llvm-readobj --coff-tls-directory %t.no-tls1.exe | FileCheck %s --check-prefix NO-TLS
148+
149+
## Case 2: There's no TlsTable listed in the COFF header.
150+
151+
# RUN: yaml2obj %s --docnum=3 -o %t.no-tls2.exe
152+
# RUN: llvm-readobj --coff-tls-directory %t.no-tls2.exe | FileCheck %s --check-prefix NO-TLS
153+
154+
# NO-TLS: TLSDirectory {
155+
# NO-TLS-NEXT: }
156+
157+
--- !COFF
158+
header:
159+
Machine: IMAGE_FILE_MACHINE_AMD64
160+
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
161+
sections: []
162+
symbols: []

llvm/tools/llvm-readobj/COFFDumper.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class COFFDumper : public ObjDumper {
9494
void printCOFFDirectives() override;
9595
void printCOFFBaseReloc() override;
9696
void printCOFFDebugDirectory() override;
97+
void printCOFFTLSDirectory() override;
9798
void printCOFFResources() override;
9899
void printCOFFLoadConfig() override;
99100
void printCodeViewDebugInfo() override;
@@ -121,6 +122,8 @@ class COFFDumper : public ObjDumper {
121122
void printBaseOfDataField(const pe32plus_header *Hdr);
122123
template <typename T>
123124
void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
125+
template <typename IntTy>
126+
void printCOFFTLSDirectory(const coff_tls_directory<IntTy> *TlsTable);
124127
typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
125128
void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
126129
PrintExtraCB PrintExtra = 0);
@@ -2029,3 +2032,27 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
20292032
Writer.flush();
20302033
}
20312034
}
2035+
2036+
void COFFDumper::printCOFFTLSDirectory() {
2037+
if (Obj->is64())
2038+
printCOFFTLSDirectory(Obj->getTLSDirectory64());
2039+
else
2040+
printCOFFTLSDirectory(Obj->getTLSDirectory32());
2041+
}
2042+
2043+
template <typename IntTy>
2044+
void COFFDumper::printCOFFTLSDirectory(
2045+
const coff_tls_directory<IntTy> *TlsTable) {
2046+
DictScope D(W, "TLSDirectory");
2047+
if (!TlsTable)
2048+
return;
2049+
2050+
W.printHex("StartAddressOfRawData", TlsTable->StartAddressOfRawData);
2051+
W.printHex("EndAddressOfRawData", TlsTable->EndAddressOfRawData);
2052+
W.printHex("AddressOfIndex", TlsTable->AddressOfIndex);
2053+
W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks);
2054+
W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill);
2055+
W.printFlags("Characteristics", TlsTable->Characteristics,
2056+
makeArrayRef(ImageSectionCharacteristics),
2057+
COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
2058+
}

llvm/tools/llvm-readobj/ObjDumper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class ObjDumper {
7878
virtual void printCOFFDirectives() { }
7979
virtual void printCOFFBaseReloc() { }
8080
virtual void printCOFFDebugDirectory() { }
81+
virtual void printCOFFTLSDirectory() {}
8182
virtual void printCOFFResources() {}
8283
virtual void printCOFFLoadConfig() { }
8384
virtual void printCodeViewDebugInfo() { }

llvm/tools/llvm-readobj/llvm-readobj.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ namespace opts {
265265
COFFDebugDirectory("coff-debug-directory",
266266
cl::desc("Display the PE/COFF debug directory"));
267267

268+
// --coff-tls-directory
269+
cl::opt<bool> COFFTLSDirectory("coff-tls-directory",
270+
cl::desc("Display the PE/COFF TLS directory"));
271+
268272
// --coff-resources
269273
cl::opt<bool> COFFResources("coff-resources",
270274
cl::desc("Display the PE/COFF .rsrc section"));
@@ -524,6 +528,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
524528
Dumper->printCOFFBaseReloc();
525529
if (opts::COFFDebugDirectory)
526530
Dumper->printCOFFDebugDirectory();
531+
if (opts::COFFTLSDirectory)
532+
Dumper->printCOFFTLSDirectory();
527533
if (opts::COFFResources)
528534
Dumper->printCOFFResources();
529535
if (opts::COFFLoadConfig)

0 commit comments

Comments
 (0)