Skip to content

Commit 6ec18aa

Browse files
committed
[Object] [COFF] Improve error messages
This aids debugging when working with possibly broken files, instead of just flat out erroring out without telling what's wrong. Differential Revision: https://reviews.llvm.org/D120679
1 parent ea4c198 commit 6ec18aa

File tree

3 files changed

+70
-40
lines changed

3 files changed

+70
-40
lines changed

llvm/include/llvm/Object/COFF.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,13 +1079,15 @@ class COFFObjectFile : public ObjectFile {
10791079

10801080
uint64_t getImageBase() const;
10811081
Error getVaPtr(uint64_t VA, uintptr_t &Res) const;
1082-
Error getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
1082+
Error getRvaPtr(uint32_t Rva, uintptr_t &Res,
1083+
const char *ErrorContext = nullptr) const;
10831084

10841085
/// Given an RVA base and size, returns a valid array of bytes or an error
10851086
/// code if the RVA and size is not contained completely within a valid
10861087
/// section.
10871088
Error getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
1088-
ArrayRef<uint8_t> &Contents) const;
1089+
ArrayRef<uint8_t> &Contents,
1090+
const char *ErrorContext = nullptr) const;
10891091

10901092
Error getHintName(uint32_t Rva, uint16_t &Hint,
10911093
StringRef &Name) const;

llvm/lib/Object/COFFObjectFile.cpp

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ Error COFFObjectFile::initSymbolTablePtr() {
447447

448448
// Check that the string table is null terminated if has any in it.
449449
if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
450-
return errorCodeToError(object_error::parse_failed);
450+
return createStringError(object_error::parse_failed,
451+
"string table missing null terminator");
451452
return Error::success();
452453
}
453454

@@ -469,7 +470,8 @@ Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
469470
}
470471

471472
// Returns the file offset for the given RVA.
472-
Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
473+
Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,
474+
const char *ErrorContext) const {
473475
for (const SectionRef &S : sections()) {
474476
const coff_section *Section = getCOFFSection(S);
475477
uint32_t SectionStart = Section->VirtualAddress;
@@ -481,11 +483,17 @@ Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
481483
return Error::success();
482484
}
483485
}
484-
return errorCodeToError(object_error::parse_failed);
486+
if (ErrorContext)
487+
return createStringError(object_error::parse_failed,
488+
"RVA 0x%" PRIx32 " for %s not found", Addr,
489+
ErrorContext);
490+
return createStringError(object_error::parse_failed,
491+
"RVA 0x%" PRIx32 " not found", Addr);
485492
}
486493

487494
Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
488-
ArrayRef<uint8_t> &Contents) const {
495+
ArrayRef<uint8_t> &Contents,
496+
const char *ErrorContext) const {
489497
for (const SectionRef &S : sections()) {
490498
const coff_section *Section = getCOFFSection(S);
491499
uint32_t SectionStart = Section->VirtualAddress;
@@ -501,7 +509,12 @@ Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
501509
return Error::success();
502510
}
503511
}
504-
return errorCodeToError(object_error::parse_failed);
512+
if (ErrorContext)
513+
return createStringError(object_error::parse_failed,
514+
"RVA 0x%" PRIx32 " for %s not found", RVA,
515+
ErrorContext);
516+
return createStringError(object_error::parse_failed,
517+
"RVA 0x%" PRIx32 " not found", RVA);
505518
}
506519

507520
// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
@@ -521,11 +534,12 @@ Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
521534
const codeview::DebugInfo *&PDBInfo,
522535
StringRef &PDBFileName) const {
523536
ArrayRef<uint8_t> InfoBytes;
524-
if (Error E = getRvaAndSizeAsBytes(
525-
DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
537+
if (Error E =
538+
getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,
539+
InfoBytes, "PDB info"))
526540
return E;
527541
if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
528-
return errorCodeToError(object_error::parse_failed);
542+
return createStringError(object_error::parse_failed, "PDB info too small");
529543
PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
530544
InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
531545
PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
@@ -563,7 +577,7 @@ Error COFFObjectFile::initImportTablePtr() {
563577
// Find the section that contains the RVA. This is needed because the RVA is
564578
// the import table's memory address which is different from its file offset.
565579
uintptr_t IntPtr = 0;
566-
if (Error E = getRvaPtr(ImportTableRva, IntPtr))
580+
if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))
567581
return E;
568582
if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
569583
return E;
@@ -586,7 +600,7 @@ Error COFFObjectFile::initDelayImportTablePtr() {
586600
sizeof(delay_import_directory_table_entry) - 1;
587601

588602
uintptr_t IntPtr = 0;
589-
if (Error E = getRvaPtr(RVA, IntPtr))
603+
if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))
590604
return E;
591605
DelayImportDirectory = reinterpret_cast<
592606
const delay_import_directory_table_entry *>(IntPtr);
@@ -607,7 +621,7 @@ Error COFFObjectFile::initExportTablePtr() {
607621

608622
uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
609623
uintptr_t IntPtr = 0;
610-
if (Error E = getRvaPtr(ExportTableRva, IntPtr))
624+
if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))
611625
return E;
612626
ExportDirectory =
613627
reinterpret_cast<const export_directory_table_entry *>(IntPtr);
@@ -623,7 +637,8 @@ Error COFFObjectFile::initBaseRelocPtr() {
623637
return Error::success();
624638

625639
uintptr_t IntPtr = 0;
626-
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
640+
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
641+
"base reloc table"))
627642
return E;
628643
BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
629644
IntPtr);
@@ -646,10 +661,12 @@ Error COFFObjectFile::initDebugDirectoryPtr() {
646661

647662
// Check that the size is a multiple of the entry size.
648663
if (DataEntry->Size % sizeof(debug_directory) != 0)
649-
return errorCodeToError(object_error::parse_failed);
664+
return createStringError(object_error::parse_failed,
665+
"debug directory has uneven size");
650666

651667
uintptr_t IntPtr = 0;
652-
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
668+
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
669+
"debug directory"))
653670
return E;
654671
DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
655672
DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
@@ -680,7 +697,8 @@ Error COFFObjectFile::initTLSDirectoryPtr() {
680697
static_cast<uint32_t>(DataEntry->Size), DirSize);
681698

682699
uintptr_t IntPtr = 0;
683-
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
700+
if (Error E =
701+
getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))
684702
return E;
685703

686704
if (is64())
@@ -701,7 +719,8 @@ Error COFFObjectFile::initLoadConfigPtr() {
701719
if (DataEntry->RelativeVirtualAddress == 0)
702720
return Error::success();
703721
uintptr_t IntPtr = 0;
704-
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
722+
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
723+
"load config table"))
705724
return E;
706725

707726
LoadConfig = (const void *)IntPtr;
@@ -749,7 +768,8 @@ Error COFFObjectFile::initialize() {
749768
CurPtr = DH->AddressOfNewExeHeader;
750769
// Check the PE magic bytes. ("PE\0\0")
751770
if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
752-
return errorCodeToError(object_error::parse_failed);
771+
return createStringError(object_error::parse_failed,
772+
"incorrect PE magic");
753773
}
754774
CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
755775
HasPEHeader = true;
@@ -805,7 +825,8 @@ Error COFFObjectFile::initialize() {
805825
DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
806826
} else {
807827
// It's neither PE32 nor PE32+.
808-
return errorCodeToError(object_error::parse_failed);
828+
return createStringError(object_error::parse_failed,
829+
"incorrect PE magic");
809830
}
810831
if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
811832
return E;
@@ -834,7 +855,8 @@ Error COFFObjectFile::initialize() {
834855
} else {
835856
// We had better not have any symbols if we don't have a symbol table.
836857
if (getNumberOfSymbols() != 0) {
837-
return errorCodeToError(object_error::parse_failed);
858+
return createStringError(object_error::parse_failed,
859+
"symbol table missing");
838860
}
839861
}
840862

@@ -1021,13 +1043,14 @@ Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
10211043
// We already verified the section table data, so no need to check again.
10221044
return SectionTable + (Index - 1);
10231045
}
1024-
return errorCodeToError(object_error::parse_failed);
1046+
return createStringError(object_error::parse_failed,
1047+
"section index out of bounds");
10251048
}
10261049

10271050
Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
10281051
if (StringTableSize <= 4)
10291052
// Tried to get a string from an empty string table.
1030-
return errorCodeToError(object_error::parse_failed);
1053+
return createStringError(object_error::parse_failed, "string table empty");
10311054
if (Offset >= StringTableSize)
10321055
return errorCodeToError(object_error::unexpected_eof);
10331056
return StringRef(StringTable + Offset);
@@ -1414,7 +1437,8 @@ ImportDirectoryEntryRef::lookup_table_symbols() const {
14141437

14151438
Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
14161439
uintptr_t IntPtr = 0;
1417-
if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
1440+
if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,
1441+
"import directory name"))
14181442
return E;
14191443
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
14201444
return Error::success();
@@ -1460,7 +1484,8 @@ DelayImportDirectoryEntryRef::imported_symbols() const {
14601484

14611485
Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
14621486
uintptr_t IntPtr = 0;
1463-
if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
1487+
if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,
1488+
"delay import directory name"))
14641489
return E;
14651490
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
14661491
return Error::success();
@@ -1477,7 +1502,7 @@ Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
14771502
uint32_t RVA = Table[Index].DelayImportAddressTable +
14781503
AddrIndex * (OwningObject->is64() ? 8 : 4);
14791504
uintptr_t IntPtr = 0;
1480-
if (Error E = OwningObject->getRvaPtr(RVA, IntPtr))
1505+
if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))
14811506
return E;
14821507
if (OwningObject->is64())
14831508
Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
@@ -1499,7 +1524,8 @@ void ExportDirectoryEntryRef::moveNext() {
14991524
// by ordinal, the empty string is set as a result.
15001525
Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
15011526
uintptr_t IntPtr = 0;
1502-
if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
1527+
if (Error E =
1528+
OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))
15031529
return E;
15041530
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
15051531
return Error::success();
@@ -1520,8 +1546,8 @@ Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
15201546
// Returns the address of the current export symbol.
15211547
Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
15221548
uintptr_t IntPtr = 0;
1523-
if (Error EC =
1524-
OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
1549+
if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,
1550+
IntPtr, "export address"))
15251551
return EC;
15261552
const export_address_table_entry *entry =
15271553
reinterpret_cast<const export_address_table_entry *>(IntPtr);
@@ -1534,8 +1560,8 @@ Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
15341560
Error
15351561
ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
15361562
uintptr_t IntPtr = 0;
1537-
if (Error EC =
1538-
OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
1563+
if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,
1564+
"export ordinal table"))
15391565
return EC;
15401566
const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
15411567

@@ -1545,11 +1571,12 @@ ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
15451571
I < E; ++I, ++Offset) {
15461572
if (*I != Index)
15471573
continue;
1548-
if (Error EC =
1549-
OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
1574+
if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,
1575+
"export table entry"))
15501576
return EC;
15511577
const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
1552-
if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
1578+
if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,
1579+
"export symbol name"))
15531580
return EC;
15541581
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
15551582
return Error::success();
@@ -1562,7 +1589,8 @@ Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
15621589
const data_directory *DataEntry =
15631590
OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
15641591
if (!DataEntry)
1565-
return errorCodeToError(object_error::parse_failed);
1592+
return createStringError(object_error::parse_failed,
1593+
"export table missing");
15661594
uint32_t RVA;
15671595
if (auto EC = getExportRVA(RVA))
15681596
return EC;
@@ -1577,7 +1605,7 @@ Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
15771605
if (auto EC = getExportRVA(RVA))
15781606
return EC;
15791607
uintptr_t IntPtr = 0;
1580-
if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
1608+
if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))
15811609
return EC;
15821610
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
15831611
return Error::success();
@@ -1606,7 +1634,7 @@ Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
16061634
RVA = Entry64[Index].getHintNameRVA();
16071635
}
16081636
uintptr_t IntPtr = 0;
1609-
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
1637+
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))
16101638
return EC;
16111639
// +2 because the first two bytes is hint.
16121640
Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
@@ -1645,7 +1673,7 @@ Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
16451673
RVA = Entry64[Index].getHintNameRVA();
16461674
}
16471675
uintptr_t IntPtr = 0;
1648-
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
1676+
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))
16491677
return EC;
16501678
Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
16511679
return Error::success();

llvm/test/tools/llvm-readobj/COFF/tls-directory.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ symbols: []
102102
## This test has a correct TLS Directory size but the RVA is invalid.
103103

104104
# RUN: yaml2obj %s --docnum=2 -o %t.bad-tls-rva.exe -DTLSRVA=999999 -DTLSSIZE=40
105-
# RUN: not llvm-readobj --coff-tls-directory %t.bad-tls-rva.exe 2>&1 | FileCheck %s --check-prefix BAD-TLS-RVA-ERR
105+
# RUN: not llvm-readobj --coff-tls-directory %t.bad-tls-rva.exe 2>&1 | FileCheck -DFILE=%t.bad-tls-rva.exe %s --check-prefix BAD-TLS-RVA-ERR
106106

107-
# BAD-TLS-RVA-ERR: error: '{{.*}}': Invalid data was encountered while parsing the file
107+
# BAD-TLS-RVA-ERR: error: '[[FILE]]': RVA 0xf423f for TLS directory not found
108108

109109
--- !COFF
110110
OptionalHeader:

0 commit comments

Comments
 (0)