aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/COFFObjectFile.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
commit145449b1e420787bb99721a429341fa6be3adfb6 (patch)
tree1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Object/COFFObjectFile.cpp
parentecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff)
Diffstat (limited to 'llvm/lib/Object/COFFObjectFile.cpp')
-rw-r--r--llvm/lib/Object/COFFObjectFile.cpp161
1 files changed, 110 insertions, 51 deletions
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 354b3c0d5577..1a4bb329201a 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -25,7 +25,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/MemoryBufferRef.h"
#include <algorithm>
#include <cassert>
#include <cinttypes>
@@ -447,7 +447,8 @@ Error COFFObjectFile::initSymbolTablePtr() {
// Check that the string table is null terminated if has any in it.
if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "string table missing null terminator");
return Error::success();
}
@@ -469,23 +470,43 @@ Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
}
// Returns the file offset for the given RVA.
-Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
+Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,
+ const char *ErrorContext) const {
for (const SectionRef &S : sections()) {
const coff_section *Section = getCOFFSection(S);
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.
+ // Somewhat common binaries may have RVAs pointing outside of the
+ // provided raw data. Instead of rejecting the binaries, just
+ // treat the section as stripped for these purposes.
+ if (Section->SizeOfRawData < Section->VirtualSize &&
+ Addr >= SectionStart + Section->SizeOfRawData) {
+ return make_error<SectionStrippedError>();
+ }
uint32_t Offset = Addr - SectionStart;
Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
Offset;
return Error::success();
}
}
- return errorCodeToError(object_error::parse_failed);
+ if (ErrorContext)
+ return createStringError(object_error::parse_failed,
+ "RVA 0x%" PRIx32 " for %s not found", Addr,
+ ErrorContext);
+ return createStringError(object_error::parse_failed,
+ "RVA 0x%" PRIx32 " not found", Addr);
}
Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
- ArrayRef<uint8_t> &Contents) const {
+ ArrayRef<uint8_t> &Contents,
+ const char *ErrorContext) const {
for (const SectionRef &S : sections()) {
const coff_section *Section = getCOFFSection(S);
uint32_t SectionStart = Section->VirtualAddress;
@@ -501,7 +522,12 @@ Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
return Error::success();
}
}
- return errorCodeToError(object_error::parse_failed);
+ if (ErrorContext)
+ return createStringError(object_error::parse_failed,
+ "RVA 0x%" PRIx32 " for %s not found", RVA,
+ ErrorContext);
+ return createStringError(object_error::parse_failed,
+ "RVA 0x%" PRIx32 " not found", RVA);
}
// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
@@ -521,11 +547,12 @@ Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
const codeview::DebugInfo *&PDBInfo,
StringRef &PDBFileName) const {
ArrayRef<uint8_t> InfoBytes;
- if (Error E = getRvaAndSizeAsBytes(
- DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
+ if (Error E =
+ getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,
+ InfoBytes, "PDB info"))
return E;
if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed, "PDB info too small");
PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
@@ -563,7 +590,7 @@ Error COFFObjectFile::initImportTablePtr() {
// Find the section that contains the RVA. This is needed because the RVA is
// the import table's memory address which is different from its file offset.
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(ImportTableRva, IntPtr))
+ if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))
return E;
if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
return E;
@@ -586,8 +613,11 @@ Error COFFObjectFile::initDelayImportTablePtr() {
sizeof(delay_import_directory_table_entry) - 1;
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(RVA, IntPtr))
+ 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();
@@ -607,8 +637,11 @@ Error COFFObjectFile::initExportTablePtr() {
uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(ExportTableRva, IntPtr))
+ 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();
@@ -623,8 +656,12 @@ Error COFFObjectFile::initBaseRelocPtr() {
return Error::success();
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ 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 *>(
@@ -646,11 +683,16 @@ Error COFFObjectFile::initDebugDirectoryPtr() {
// Check that the size is a multiple of the entry size.
if (DataEntry->Size % sizeof(debug_directory) != 0)
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "debug directory has uneven size");
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ 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);
@@ -680,7 +722,10 @@ Error COFFObjectFile::initTLSDirectoryPtr() {
static_cast<uint32_t>(DataEntry->Size), DirSize);
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ if (Error E =
+ getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
return E;
if (is64())
@@ -701,7 +746,10 @@ Error COFFObjectFile::initLoadConfigPtr() {
if (DataEntry->RelativeVirtualAddress == 0)
return Error::success();
uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ 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;
@@ -727,6 +775,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 E;
+}
+
Error COFFObjectFile::initialize() {
// Check that we at least have enough room for a header.
std::error_code EC;
@@ -749,7 +805,8 @@ Error COFFObjectFile::initialize() {
CurPtr = DH->AddressOfNewExeHeader;
// Check the PE magic bytes. ("PE\0\0")
if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "incorrect PE magic");
}
CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
HasPEHeader = true;
@@ -805,7 +862,8 @@ Error COFFObjectFile::initialize() {
DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
} else {
// It's neither PE32 nor PE32+.
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "incorrect PE magic");
}
if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
return E;
@@ -834,33 +892,34 @@ Error COFFObjectFile::initialize() {
} else {
// We had better not have any symbols if we don't have a symbol table.
if (getNumberOfSymbols() != 0) {
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "symbol table missing");
}
}
// 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();
@@ -1021,13 +1080,14 @@ Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
// We already verified the section table data, so no need to check again.
return SectionTable + (Index - 1);
}
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "section index out of bounds");
}
Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
if (StringTableSize <= 4)
// Tried to get a string from an empty string table.
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed, "string table empty");
if (Offset >= StringTableSize)
return errorCodeToError(object_error::unexpected_eof);
return StringRef(StringTable + Offset);
@@ -1086,13 +1146,7 @@ uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
Expected<StringRef>
COFFObjectFile::getSectionName(const coff_section *Sec) const {
- StringRef Name;
- if (Sec->Name[COFF::NameSize - 1] == 0)
- // Null terminated, let ::strlen figure out the length.
- Name = Sec->Name;
- else
- // Not null terminated, use all 8 bytes.
- Name = StringRef(Sec->Name, COFF::NameSize);
+ StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;
// Check for string table entry. First byte is '/'.
if (Name.startswith("/")) {
@@ -1414,7 +1468,8 @@ ImportDirectoryEntryRef::lookup_table_symbols() const {
Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
+ if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,
+ "import directory name"))
return E;
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
return Error::success();
@@ -1460,7 +1515,8 @@ DelayImportDirectoryEntryRef::imported_symbols() const {
Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
+ if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,
+ "delay import directory name"))
return E;
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
return Error::success();
@@ -1477,7 +1533,7 @@ Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
uint32_t RVA = Table[Index].DelayImportAddressTable +
AddrIndex * (OwningObject->is64() ? 8 : 4);
uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(RVA, IntPtr))
+ if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))
return E;
if (OwningObject->is64())
Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
@@ -1499,7 +1555,8 @@ void ExportDirectoryEntryRef::moveNext() {
// by ordinal, the empty string is set as a result.
Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
+ if (Error E =
+ OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))
return E;
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
return Error::success();
@@ -1520,8 +1577,8 @@ Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
// Returns the address of the current export symbol.
Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
uintptr_t IntPtr = 0;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,
+ IntPtr, "export address"))
return EC;
const export_address_table_entry *entry =
reinterpret_cast<const export_address_table_entry *>(IntPtr);
@@ -1534,8 +1591,8 @@ Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
Error
ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
uintptr_t IntPtr = 0;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,
+ "export ordinal table"))
return EC;
const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
@@ -1545,11 +1602,12 @@ ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
I < E; ++I, ++Offset) {
if (*I != Index)
continue;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,
+ "export table entry"))
return EC;
const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
- if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,
+ "export symbol name"))
return EC;
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
return Error::success();
@@ -1562,7 +1620,8 @@ Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
const data_directory *DataEntry =
OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
if (!DataEntry)
- return errorCodeToError(object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "export table missing");
uint32_t RVA;
if (auto EC = getExportRVA(RVA))
return EC;
@@ -1577,7 +1636,7 @@ Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
if (auto EC = getExportRVA(RVA))
return EC;
uintptr_t IntPtr = 0;
- if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))
return EC;
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
return Error::success();
@@ -1606,7 +1665,7 @@ Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
RVA = Entry64[Index].getHintNameRVA();
}
uintptr_t IntPtr = 0;
- if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))
return EC;
// +2 because the first two bytes is hint.
Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
@@ -1645,7 +1704,7 @@ Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
RVA = Entry64[Index].getHintNameRVA();
}
uintptr_t IntPtr = 0;
- if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))
return EC;
Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
return Error::success();