[COFF] Expose the PE debug data directory and dump it

This directory is used to find if there is a PDB associated with an
executable. I plan to use this functionality to teach llvm-symbolizer
whether it should use DIA or DWARF to symbolize a given DLL.

Reviewers: majnemer

Differential Revision: http://reviews.llvm.org/D20885

llvm-svn: 271539
This commit is contained in:
Reid Kleckner
2016-06-02 17:10:43 +00:00
parent 6393ef135c
commit 2da433ea99
9 changed files with 218 additions and 6 deletions

View File

@@ -453,6 +453,27 @@ std::error_code COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
return object_error::parse_failed;
}
std::error_code
COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
ArrayRef<uint8_t> &Contents) const {
for (const SectionRef &S : sections()) {
const coff_section *Section = getCOFFSection(S);
uint32_t SectionStart = Section->VirtualAddress;
// Check if this RVA is within the section bounds. Be careful about integer
// overflow.
uint32_t OffsetIntoSection = RVA - SectionStart;
if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
Size <= Section->VirtualSize - OffsetIntoSection) {
uintptr_t Begin =
uintptr_t(base()) + Section->PointerToRawData + OffsetIntoSection;
Contents =
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
return std::error_code();
}
}
return object_error::parse_failed;
}
// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
// table entry.
std::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
@@ -466,6 +487,24 @@ std::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
return std::error_code();
}
std::error_code COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
const debug_pdb_info *&PDBInfo,
StringRef &PDBFileName) const {
ArrayRef<uint8_t> InfoBytes;
if (std::error_code EC = getRvaAndSizeAsBytes(
DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
return EC;
if (InfoBytes.size() < sizeof(debug_pdb_info) + 1)
return object_error::parse_failed;
PDBInfo = reinterpret_cast<const debug_pdb_info *>(InfoBytes.data());
InfoBytes = InfoBytes.drop_front(sizeof(debug_pdb_info));
PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
InfoBytes.size());
// Truncate the name at the first null byte. Ignore any padding.
PDBFileName = PDBFileName.split('\0').first;
return std::error_code();
}
// Find the import table.
std::error_code COFFObjectFile::initImportTablePtr() {
// First, we get the RVA of the import table. If the file lacks a pointer to
@@ -551,6 +590,31 @@ std::error_code COFFObjectFile::initBaseRelocPtr() {
return std::error_code();
}
std::error_code COFFObjectFile::initDebugDirectoryPtr() {
// Get the RVA of the debug directory. Do nothing if it does not exist.
const data_directory *DataEntry;
if (getDataDirectory(COFF::DEBUG_DIRECTORY, DataEntry))
return std::error_code();
// Do nothing if the RVA is NULL.
if (DataEntry->RelativeVirtualAddress == 0)
return std::error_code();
// Check that the size is a multiple of the entry size.
if (DataEntry->Size % sizeof(debug_directory) != 0)
return object_error::parse_failed;
uintptr_t IntPtr = 0;
if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
return EC;
DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
if (std::error_code EC = getRvaPtr(
DataEntry->RelativeVirtualAddress + DataEntry->Size, IntPtr))
return EC;
DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(IntPtr);
return std::error_code();
}
COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
: ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
@@ -558,8 +622,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
ImportDirectory(nullptr), NumberOfImportDirectory(0),
DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0),
ExportDirectory(nullptr), BaseRelocHeader(nullptr),
BaseRelocEnd(nullptr) {
ExportDirectory(nullptr), BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {
// Check that we at least have enough room for a header.
if (!checkSize(Data, EC, sizeof(coff_file_header)))
return;
@@ -675,6 +739,10 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
if ((EC = initBaseRelocPtr()))
return;
// Initialize the pointer to the export table.
if ((EC = initDebugDirectoryPtr()))
return;
EC = std::error_code();
}