From 145449b1e420787bb99721a429341fa6be3adfb6 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 3 Jul 2022 16:10:23 +0200 Subject: Vendor import of llvm-project main llvmorg-15-init-15358-g53dc0f107877. --- llvm/lib/Object/COFFObjectFile.cpp | 161 +++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 51 deletions(-) (limited to 'llvm/lib/Object/COFFObjectFile.cpp') 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 #include #include @@ -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(); + } uint32_t Offset = Addr - SectionStart; Res = reinterpret_cast(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 &Contents) const { + ArrayRef &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 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(InfoBytes.data()); InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo)); PDBFileName = StringRef(reinterpret_cast(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(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( IntPtr); BaseRelocEnd = reinterpret_cast( @@ -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(IntPtr); DebugDirectoryEnd = reinterpret_cast( IntPtr + DataEntry->Size); @@ -680,7 +722,10 @@ Error COFFObjectFile::initTLSDirectoryPtr() { static_cast(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()) { + 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 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 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 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(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(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(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(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(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(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(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(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(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(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(IntPtr); return Error::success(); -- cgit v1.2.3