[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
This commit is contained in:
Luqman Aden 2020-10-08 01:43:50 -07:00
parent 8e9622f961
commit 568035ac39
8 changed files with 250 additions and 2 deletions

View File

@ -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.

View File

@ -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,

View File

@ -786,6 +786,8 @@ private:
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 @@ private:
Error initExportTablePtr();
Error initBaseRelocPtr();
Error initDebugDirectoryPtr();
Error initTLSDirectoryPtr();
Error initLoadConfigPtr();
public:
@ -976,6 +979,13 @@ public:
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;

View File

@ -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;

View File

@ -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: []

View File

@ -89,6 +89,7 @@ public:
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 @@ private:
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));
}

View File

@ -80,6 +80,7 @@ public:
virtual void printCOFFDirectives() { }
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
virtual void printCOFFTLSDirectory() {}
virtual void printCOFFResources() {}
virtual void printCOFFLoadConfig() { }
virtual void printCodeViewDebugInfo() { }

View File

@ -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)