[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:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user