aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/COFFObjectFile.cpp
diff options
context:
space:
mode:
authorAlvin Wong <alvin@alvinhc.com>2022-06-03 17:57:57 +0300
committerMartin Storsjö <martin@martin.st>2022-06-03 18:31:01 +0300
commitbb94611d6545c2c5271f5bb01de1aa4228a37250 (patch)
tree15d0596b224aadcb1b86d804896f895a9a938293 /llvm/lib/Object/COFFObjectFile.cpp
parentcac60940b771a0685d058a5b471c84cea05fdc46 (diff)
downloadllvm-bb94611d6545c2c5271f5bb01de1aa4228a37250.zip
llvm-bb94611d6545c2c5271f5bb01de1aa4228a37250.tar.gz
llvm-bb94611d6545c2c5271f5bb01de1aa4228a37250.tar.bz2
[COFF] Check table ptr more thoroughly and ignore empty sections
When loading split debug files for PE/COFF executables (produced with `objcopy --only-keep-debug`), the tables or directories in such files may point to data inside sections that may have been stripped. COFFObjectFile shall detect and gracefully handle this, to allow the object file be loaded without considering these tables or directories. This is required for LLDB to load these files for use as debug symbols. COFFObjectFile shall also check these pointers more carefully to account for cases in which the section contains less raw data than the size given by VirtualSize, to prevent going out of bounds. This commit also changes COFFDump in llvm-objdump to reuse the pointers that are already range-checked in COFFObjectFile. This fixes a crash when trying to dump the TLS directory from a stripped file. Fixes https://github.com/mstorsjo/llvm-mingw/issues/284 Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D126898
Diffstat (limited to 'llvm/lib/Object/COFFObjectFile.cpp')
-rw-r--r--llvm/lib/Object/COFFObjectFile.cpp57
1 files changed, 50 insertions, 7 deletions
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index a52671f..65166b3 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -477,6 +477,25 @@ Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,
uint32_t SectionStart = Section->VirtualAddress;
uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
if (SectionStart <= Addr && Addr < SectionEnd) {
+ // A table/directory entry can be pointing to somewhere in a stripped
+ // section, in an object that went through `objcopy --only-keep-debug`.
+ // In this case we don't want to cause the parsing of the object file to
+ // fail, otherwise it will be impossible to use this object as debug info
+ // in LLDB. Return SectionStrippedError here so that
+ // COFFObjectFile::initialize can ignore the error.
+ if (Section->SizeOfRawData == 0)
+ return make_error<SectionStrippedError>();
+ if (Section->SizeOfRawData < Section->VirtualSize &&
+ Addr >= SectionStart + Section->SizeOfRawData) {
+ if (ErrorContext)
+ return createStringError(object_error::parse_failed,
+ "RVA 0x%" PRIx32
+ " for %s found but data is incomplete",
+ Addr, ErrorContext);
+ return createStringError(
+ object_error::parse_failed,
+ "RVA 0x%" PRIx32 " found but data is incomplete", Addr);
+ }
uint32_t Offset = Addr - SectionStart;
Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
Offset;
@@ -602,6 +621,9 @@ Error COFFObjectFile::initDelayImportTablePtr() {
uintptr_t IntPtr = 0;
if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
+
DelayImportDirectory = reinterpret_cast<
const delay_import_directory_table_entry *>(IntPtr);
return Error::success();
@@ -623,6 +645,9 @@ Error COFFObjectFile::initExportTablePtr() {
uintptr_t IntPtr = 0;
if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
+
ExportDirectory =
reinterpret_cast<const export_directory_table_entry *>(IntPtr);
return Error::success();
@@ -640,6 +665,9 @@ Error COFFObjectFile::initBaseRelocPtr() {
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
"base reloc table"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
+
BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
IntPtr);
BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
@@ -668,6 +696,9 @@ Error COFFObjectFile::initDebugDirectoryPtr() {
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
"debug directory"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
+
DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
IntPtr + DataEntry->Size);
@@ -700,6 +731,8 @@ Error COFFObjectFile::initTLSDirectoryPtr() {
if (Error E =
getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
if (is64())
TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
@@ -722,6 +755,8 @@ Error COFFObjectFile::initLoadConfigPtr() {
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
"load config table"))
return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
LoadConfig = (const void *)IntPtr;
return Error::success();
@@ -746,6 +781,14 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
+static Error ignoreStrippedErrors(Error E) {
+ if (E.isA<SectionStrippedError>()) {
+ consumeError(std::move(E));
+ return Error::success();
+ }
+ return std::move(E);
+}
+
Error COFFObjectFile::initialize() {
// Check that we at least have enough room for a header.
std::error_code EC;
@@ -861,28 +904,28 @@ Error COFFObjectFile::initialize() {
}
// Initialize the pointer to the beginning of the import table.
- if (Error E = initImportTablePtr())
+ if (Error E = ignoreStrippedErrors(initImportTablePtr()))
return E;
- if (Error E = initDelayImportTablePtr())
+ if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))
return E;
// Initialize the pointer to the export table.
- if (Error E = initExportTablePtr())
+ if (Error E = ignoreStrippedErrors(initExportTablePtr()))
return E;
// Initialize the pointer to the base relocation table.
- if (Error E = initBaseRelocPtr())
+ if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))
return E;
// Initialize the pointer to the debug directory.
- if (Error E = initDebugDirectoryPtr())
+ if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))
return E;
// Initialize the pointer to the TLS directory.
- if (Error E = initTLSDirectoryPtr())
+ if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))
return E;
- if (Error E = initLoadConfigPtr())
+ if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))
return E;
return Error::success();