[llvm] 568035a - [llvm-readobj] Add --coff-tls-directory flag to print TLS Directory & test.
Luqman Aden via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 8 01:57:09 PDT 2020
Author: Luqman Aden
Date: 2020-10-08T01:53:15-07:00
New Revision: 568035ac3955790aee2a5dbc2b1f4074c76bb4d7
URL: https://github.com/llvm/llvm-project/commit/568035ac3955790aee2a5dbc2b1f4074c76bb4d7
DIFF: https://github.com/llvm/llvm-project/commit/568035ac3955790aee2a5dbc2b1f4074c76bb4d7.diff
LOG: [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
Added:
llvm/test/tools/llvm-readobj/COFF/tls-directory.test
Modified:
llvm/docs/CommandGuide/llvm-readobj.rst
llvm/include/llvm/BinaryFormat/COFF.h
llvm/include/llvm/Object/COFF.h
llvm/lib/Object/COFFObjectFile.cpp
llvm/tools/llvm-readobj/COFFDumper.cpp
llvm/tools/llvm-readobj/ObjDumper.h
llvm/tools/llvm-readobj/llvm-readobj.cpp
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst
index 9b1b5ba92bc0..ba5511bb765a 100644
--- a/llvm/docs/CommandGuide/llvm-readobj.rst
+++ b/llvm/docs/CommandGuide/llvm-readobj.rst
@@ -286,6 +286,10 @@ The following options are implemented only for the PE/COFF file format.
Display the debug directory.
+.. option:: --coff-tls-directory
+
+ Display the TLS directory.
+
.. option:: --coff-directives
Display the .drectve section.
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index 1919d7f0dece..716d649f7c51 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -311,6 +311,7 @@ enum SectionCharacteristics : uint32_t {
IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
+ IMAGE_SCN_ALIGN_MASK = 0x00F00000,
IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,
diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h
index 8aef00a8809d..505aab8bff5b 100644
--- a/llvm/include/llvm/Object/COFF.h
+++ b/llvm/include/llvm/Object/COFF.h
@@ -786,6 +786,8 @@ class COFFObjectFile : public ObjectFile {
const coff_base_reloc_block_header *BaseRelocEnd;
const debug_directory *DebugDirectoryBegin;
const debug_directory *DebugDirectoryEnd;
+ const coff_tls_directory32 *TLSDirectory32;
+ const coff_tls_directory64 *TLSDirectory64;
// Either coff_load_configuration32 or coff_load_configuration64.
const void *LoadConfig = nullptr;
@@ -805,6 +807,7 @@ class COFFObjectFile : public ObjectFile {
Error initExportTablePtr();
Error initBaseRelocPtr();
Error initDebugDirectoryPtr();
+ Error initTLSDirectoryPtr();
Error initLoadConfigPtr();
public:
@@ -976,6 +979,13 @@ class COFFObjectFile : public ObjectFile {
return make_range(debug_directory_begin(), debug_directory_end());
}
+ const coff_tls_directory32 *getTLSDirectory32() const {
+ return TLSDirectory32;
+ }
+ const coff_tls_directory64 *getTLSDirectory64() const {
+ return TLSDirectory64;
+ }
+
const dos_header *getDOSHeader() const {
if (!PE32Header && !PE32PlusHeader)
return nullptr;
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index c26d7721b3fe..cd10e67af239 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -649,6 +649,38 @@ Error COFFObjectFile::initDebugDirectoryPtr() {
return Error::success();
}
+Error COFFObjectFile::initTLSDirectoryPtr() {
+ // Get the RVA of the TLS directory. Do nothing if it does not exist.
+ const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
+ if (!DataEntry)
+ return Error::success();
+
+ // Do nothing if the RVA is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ uint64_t DirSize =
+ is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);
+
+ // Check that the size is correct.
+ if (DataEntry->Size != DirSize)
+ return createStringError(
+ object_error::parse_failed,
+ "TLS Directory size (%u) is not the expected size (%u).",
+ static_cast<uint32_t>(DataEntry->Size), DirSize);
+
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ return E;
+
+ if (is64())
+ TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
+ else
+ TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
+
+ return Error::success();
+}
+
Error COFFObjectFile::initLoadConfigPtr() {
// Get the RVA of the debug directory. Do nothing if it does not exist.
const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
@@ -682,7 +714,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
ImportDirectory(nullptr), DelayImportDirectory(nullptr),
NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
- DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {}
+ DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
+ TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
Error COFFObjectFile::initialize() {
// Check that we at least have enough room for a header.
@@ -809,10 +842,14 @@ Error COFFObjectFile::initialize() {
if (Error E = initBaseRelocPtr())
return E;
- // Initialize the pointer to the export table.
+ // Initialize the pointer to the debug directory.
if (Error E = initDebugDirectoryPtr())
return E;
+ // Initialize the pointer to the TLS directory.
+ if (Error E = initTLSDirectoryPtr())
+ return E;
+
if (Error E = initLoadConfigPtr())
return E;
diff --git a/llvm/test/tools/llvm-readobj/COFF/tls-directory.test b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test
new file mode 100644
index 000000000000..d553130e0a01
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test
@@ -0,0 +1,162 @@
+## Tests for the --coff-tls-directory flag.
+
+## Test that the output of --coff-tls-directory works on x86.
+## The binary created from this yaml definition is such that .rdata contains
+## only the IMAGE_TLS_DIRECTORY structure and hence we should have that
+## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress.
+## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory32) == sizeof(IMAGE_TLS_DIRECTORY32) == 24
+
+# RUN: yaml2obj %s --docnum=1 -o %t.32.exe -DTLSRVA=10000 -DTLSSIZE=24
+# RUN: llvm-readobj --coff-tls-directory %t.32.exe | FileCheck %s --check-prefix I386
+
+# I386: Arch: i386
+# I386-NEXT: AddressSize: 32bit
+# I386-NEXT: TLSDirectory {
+# I386-NEXT: StartAddressOfRawData: 0x404000
+# I386-NEXT: EndAddressOfRawData: 0x404008
+# I386-NEXT: AddressOfIndex: 0x402000
+# I386-NEXT: AddressOfCallBacks: 0x0
+# I386-NEXT: SizeOfZeroFill: 0x0
+# I386-NEXT: Characteristics [ (0x300000)
+# I386-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000)
+# I386-NEXT: ]
+# I386-NEXT: }
+
+
+## Test that the output of --coff-tls-directory errors on malformed input.
+## On x86, the TLS directory should be 24 bytes.
+## This test has a truncated TLS directory.
+
+# RUN: yaml2obj %s --docnum=1 -o %t.wrong-size.32.exe -DTLSRVA=10000 -DTLSSIZE=10
+# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.32.exe 2>&1 | FileCheck %s --check-prefix I386-WRONG-SIZE-ERR
+
+# I386-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (10) is not the expected size (24).
+
+--- !COFF
+OptionalHeader:
+ AddressOfEntryPoint: 0
+ ImageBase: 0
+ SectionAlignment: 4096
+ FileAlignment: 512
+ MajorOperatingSystemVersion: 0
+ MinorOperatingSystemVersion: 0
+ MajorImageVersion: 0
+ MinorImageVersion: 0
+ MajorSubsystemVersion: 0
+ MinorSubsystemVersion: 0
+ Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+ DLLCharacteristics: []
+ SizeOfStackReserve: 0
+ SizeOfStackCommit: 0
+ SizeOfHeapReserve: 0
+ SizeOfHeapCommit: 0
+ TlsTable:
+ RelativeVirtualAddress: [[TLSRVA]]
+ Size: [[TLSSIZE]]
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE ]
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ VirtualAddress: 10000
+ VirtualSize: 24
+ SectionData: '004040000840400000204000000000000000000000003000'
+symbols: []
+
+
+## Test that the output of --coff-tls-directory works on x86_64.
+## The binary created from this yaml definition is such that .rdata contains
+## only the IMAGE_TLS_DIRECTORY structure and hence we should have that
+## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress.
+## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory64) == sizeof(IMAGE_TLS_DIRECTORY64) == 40
+
+# RUN: yaml2obj %s --docnum=2 -o %t.64.exe -DTLSRVA=10000 -DTLSSIZE=40
+# RUN: llvm-readobj --coff-tls-directory %t.64.exe | FileCheck %s --check-prefix X86-64
+
+# X86-64: Arch: x86_64
+# X86-64-NEXT: AddressSize: 64bit
+# X86-64-NEXT: TLSDirectory {
+# X86-64-NEXT: StartAddressOfRawData: 0x140004000
+# X86-64-NEXT: EndAddressOfRawData: 0x140004008
+# X86-64-NEXT: AddressOfIndex: 0x140002000
+# X86-64-NEXT: AddressOfCallBacks: 0x0
+# X86-64-NEXT: SizeOfZeroFill: 0x0
+# X86-64-NEXT: Characteristics [ (0x300000)
+# X86-64-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000)
+# X86-64-NEXT: ]
+# X86-64-NEXT: }
+
+
+## Test that the output of --coff-tls-directory errors on malformed input.
+
+## On x86-64, the TLS directory should be 40 bytes.
+## This test has an erroneously lengthened TLS directory.
+
+# RUN: yaml2obj %s --docnum=2 -o %t.wrong-size.64.exe -DTLSRVA=10000 -DTLSSIZE=80
+# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.64.exe 2>&1 | FileCheck %s --check-prefix X86-64-WRONG-SIZE-ERR
+
+# X86-64-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (80) is not the expected size (40).
+
+
+## This test has a correct TLS Directory size but the RVA is invalid.
+
+# RUN: yaml2obj %s --docnum=2 -o %t.bad-tls-rva.exe -DTLSRVA=999999 -DTLSSIZE=40
+# RUN: not llvm-readobj --coff-tls-directory %t.bad-tls-rva.exe 2>&1 | FileCheck %s --check-prefix BAD-TLS-RVA-ERR
+
+# BAD-TLS-RVA-ERR: error: '{{.*}}': Invalid data was encountered while parsing the file
+
+--- !COFF
+OptionalHeader:
+ AddressOfEntryPoint: 0
+ ImageBase: 0
+ SectionAlignment: 4096
+ FileAlignment: 512
+ MajorOperatingSystemVersion: 0
+ MinorOperatingSystemVersion: 0
+ MajorImageVersion: 0
+ MinorImageVersion: 0
+ MajorSubsystemVersion: 0
+ MinorSubsystemVersion: 0
+ Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+ DLLCharacteristics: []
+ SizeOfStackReserve: 0
+ SizeOfStackCommit: 0
+ SizeOfHeapReserve: 0
+ SizeOfHeapCommit: 0
+ TlsTable:
+ RelativeVirtualAddress: [[TLSRVA]]
+ Size: [[TLSSIZE]]
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ VirtualAddress: 10000
+ VirtualSize: 40
+ SectionData: '00400040010000000840004001000000002000400100000000000000000000000000000000003000'
+symbols: []
+
+
+## Test that --coff-tls-directory doesn't output anything if there's no TLS directory.
+
+## Case 1: TlsTable.RelativeVirtualAddress/Size = 0.
+
+# RUN: yaml2obj %s --docnum=2 -o %t.no-tls1.exe -DTLSRVA=0 -DTLSSIZE=0
+# RUN: llvm-readobj --coff-tls-directory %t.no-tls1.exe | FileCheck %s --check-prefix NO-TLS
+
+## Case 2: There's no TlsTable listed in the COFF header.
+
+# RUN: yaml2obj %s --docnum=3 -o %t.no-tls2.exe
+# RUN: llvm-readobj --coff-tls-directory %t.no-tls2.exe | FileCheck %s --check-prefix NO-TLS
+
+# NO-TLS: TLSDirectory {
+# NO-TLS-NEXT: }
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections: []
+symbols: []
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 22e27b3e5a29..f59bfd8b7cb6 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -89,6 +89,7 @@ class COFFDumper : public ObjDumper {
void printCOFFDirectives() override;
void printCOFFBaseReloc() override;
void printCOFFDebugDirectory() override;
+ void printCOFFTLSDirectory() override;
void printCOFFResources() override;
void printCOFFLoadConfig() override;
void printCodeViewDebugInfo() override;
@@ -116,6 +117,8 @@ class COFFDumper : public ObjDumper {
void printBaseOfDataField(const pe32plus_header *Hdr);
template <typename T>
void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
+ template <typename IntTy>
+ void printCOFFTLSDirectory(const coff_tls_directory<IntTy> *TlsTable);
typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
PrintExtraCB PrintExtra = 0);
@@ -2018,3 +2021,27 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
Writer.flush();
}
}
+
+void COFFDumper::printCOFFTLSDirectory() {
+ if (Obj->is64())
+ printCOFFTLSDirectory(Obj->getTLSDirectory64());
+ else
+ printCOFFTLSDirectory(Obj->getTLSDirectory32());
+}
+
+template <typename IntTy>
+void COFFDumper::printCOFFTLSDirectory(
+ const coff_tls_directory<IntTy> *TlsTable) {
+ DictScope D(W, "TLSDirectory");
+ if (!TlsTable)
+ return;
+
+ W.printHex("StartAddressOfRawData", TlsTable->StartAddressOfRawData);
+ W.printHex("EndAddressOfRawData", TlsTable->EndAddressOfRawData);
+ W.printHex("AddressOfIndex", TlsTable->AddressOfIndex);
+ W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks);
+ W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill);
+ W.printFlags("Characteristics", TlsTable->Characteristics,
+ makeArrayRef(ImageSectionCharacteristics),
+ COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
+}
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 9e45062ccda8..943299a121fc 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -80,6 +80,7 @@ class ObjDumper {
virtual void printCOFFDirectives() { }
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
+ virtual void printCOFFTLSDirectory() {}
virtual void printCOFFResources() {}
virtual void printCOFFLoadConfig() { }
virtual void printCodeViewDebugInfo() { }
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 173ee3a7f140..1546ce7926a4 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -272,6 +272,10 @@ namespace opts {
COFFDebugDirectory("coff-debug-directory",
cl::desc("Display the PE/COFF debug directory"));
+ // --coff-tls-directory
+ cl::opt<bool> COFFTLSDirectory("coff-tls-directory",
+ cl::desc("Display the PE/COFF TLS directory"));
+
// --coff-resources
cl::opt<bool> COFFResources("coff-resources",
cl::desc("Display the PE/COFF .rsrc section"));
@@ -533,6 +537,8 @@ static void dumpObject(const ObjectFile &Obj, ScopedPrinter &Writer,
Dumper->printCOFFBaseReloc();
if (opts::COFFDebugDirectory)
Dumper->printCOFFDebugDirectory();
+ if (opts::COFFTLSDirectory)
+ Dumper->printCOFFTLSDirectory();
if (opts::COFFResources)
Dumper->printCOFFResources();
if (opts::COFFLoadConfig)
More information about the llvm-commits
mailing list