[llvm] r271539 - [COFF] Expose the PE debug data directory and dump it
Reid Kleckner via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 2 10:10:43 PDT 2016
Author: rnk
Date: Thu Jun 2 12:10:43 2016
New Revision: 271539
URL: http://llvm.org/viewvc/llvm-project?rev=271539&view=rev
Log:
[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
Added:
llvm/trunk/test/tools/llvm-readobj/Inputs/has_pdb.exe
llvm/trunk/test/tools/llvm-readobj/coff-debug-directory.test
Modified:
llvm/trunk/include/llvm/Object/COFF.h
llvm/trunk/include/llvm/Support/COFF.h
llvm/trunk/lib/Object/COFFObjectFile.cpp
llvm/trunk/lib/ObjectYAML/COFFYAML.cpp
llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
llvm/trunk/tools/llvm-readobj/ObjDumper.h
llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
Modified: llvm/trunk/include/llvm/Object/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/COFF.h?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/COFF.h (original)
+++ llvm/trunk/include/llvm/Object/COFF.h Thu Jun 2 12:10:43 2016
@@ -169,6 +169,26 @@ struct import_directory_table_entry {
support::ulittle32_t ImportAddressTableRVA;
};
+struct debug_directory {
+ support::ulittle32_t Characteristics;
+ support::ulittle32_t TimeDateStamp;
+ support::ulittle16_t MajorVersion;
+ support::ulittle16_t MinorVersion;
+ support::ulittle32_t Type;
+ support::ulittle32_t SizeOfData;
+ support::ulittle32_t AddressOfRawData;
+ support::ulittle32_t PointerToRawData;
+};
+
+/// Information that is resent in debug_directory::AddressOfRawData if Type is
+/// IMAGE_DEBUG_TYPE_CODEVIEW.
+struct debug_pdb_info {
+ support::ulittle32_t Signature;
+ uint8_t Guid[16];
+ support::ulittle32_t Age;
+ // PDBFileName: The null-terminated PDB file name follows.
+};
+
template <typename IntTy>
struct import_lookup_table_entry {
IntTy Data;
@@ -620,6 +640,8 @@ private:
const export_directory_table_entry *ExportDirectory;
const coff_base_reloc_block_header *BaseRelocHeader;
const coff_base_reloc_block_header *BaseRelocEnd;
+ const debug_directory *DebugDirectoryBegin;
+ const debug_directory *DebugDirectoryEnd;
std::error_code getString(uint32_t offset, StringRef &Res) const;
@@ -633,6 +655,7 @@ private:
std::error_code initDelayImportTablePtr();
std::error_code initExportTablePtr();
std::error_code initBaseRelocPtr();
+ std::error_code initDebugDirectoryPtr();
public:
uintptr_t getSymbolTable() const {
@@ -754,12 +777,21 @@ public:
export_directory_iterator export_directory_end() const;
base_reloc_iterator base_reloc_begin() const;
base_reloc_iterator base_reloc_end() const;
+ const debug_directory *debug_directory_begin() const {
+ return DebugDirectoryBegin;
+ }
+ const debug_directory *debug_directory_end() const {
+ return DebugDirectoryEnd;
+ }
iterator_range<import_directory_iterator> import_directories() const;
iterator_range<delay_import_directory_iterator>
delay_import_directories() const;
iterator_range<export_directory_iterator> export_directories() const;
iterator_range<base_reloc_iterator> base_relocs() const;
+ iterator_range<const debug_directory *> debug_directories() const {
+ return make_range(debug_directory_begin(), debug_directory_end());
+ }
const dos_header *getDOSHeader() const {
if (!PE32Header && !PE32PlusHeader)
@@ -828,9 +860,20 @@ public:
uint64_t getImageBase() const;
std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const;
std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
+
+ /// Given an RVA base and size, returns a valid array of bytes or an error
+ /// code if the RVA and size is not contained completely within a valid
+ /// section.
+ std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
+ ArrayRef<uint8_t> &Contents) const;
+
std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
StringRef &Name) const;
+ std::error_code getDebugPDBInfo(const debug_directory *DebugDir,
+ const debug_pdb_info *&Info,
+ StringRef &PDBFileName) const;
+
bool isRelocatableObject() const override;
bool is64() const { return PE32PlusHeader; }
Modified: llvm/trunk/include/llvm/Support/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/COFF.h?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/COFF.h (original)
+++ llvm/trunk/include/llvm/Support/COFF.h Thu Jun 2 12:10:43 2016
@@ -529,7 +529,7 @@ namespace COFF {
EXCEPTION_TABLE,
CERTIFICATE_TABLE,
BASE_RELOCATION_TABLE,
- DEBUG,
+ DEBUG_DIRECTORY,
ARCHITECTURE,
GLOBAL_PTR,
TLS_TABLE,
@@ -598,7 +598,12 @@ namespace COFF {
IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7,
IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
IMAGE_DEBUG_TYPE_BORLAND = 9,
- IMAGE_DEBUG_TYPE_CLSID = 11
+ IMAGE_DEBUG_TYPE_CLSID = 11,
+ IMAGE_DEBUG_TYPE_VC_FEATURE = 12,
+ IMAGE_DEBUG_TYPE_POGO = 13,
+ IMAGE_DEBUG_TYPE_ILTCG = 14,
+ IMAGE_DEBUG_TYPE_MPX = 15,
+ IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16,
};
enum BaseRelocationType {
Modified: llvm/trunk/lib/Object/COFFObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/COFFObjectFile.cpp?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/lib/Object/COFFObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/COFFObjectFile.cpp Thu Jun 2 12:10:43 2016
@@ -453,6 +453,27 @@ std::error_code COFFObjectFile::getRvaPt
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::getHintN
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::initBase
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(MemoryBuf
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(MemoryBuf
if ((EC = initBaseRelocPtr()))
return;
+ // Initialize the pointer to the export table.
+ if ((EC = initDebugDirectoryPtr()))
+ return;
+
EC = std::error_code();
}
Modified: llvm/trunk/lib/ObjectYAML/COFFYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/COFFYAML.cpp?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/COFFYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/COFFYAML.cpp Thu Jun 2 12:10:43 2016
@@ -397,7 +397,7 @@ void MappingTraits<COFFYAML::PEHeader>::
IO.mapOptional("CertificateTable", PH.DataDirectories[COFF::CERTIFICATE_TABLE]);
IO.mapOptional("BaseRelocationTable",
PH.DataDirectories[COFF::BASE_RELOCATION_TABLE]);
- IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG]);
+ IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG_DIRECTORY]);
IO.mapOptional("Architecture", PH.DataDirectories[COFF::ARCHITECTURE]);
IO.mapOptional("GlobalPtr", PH.DataDirectories[COFF::GLOBAL_PTR]);
IO.mapOptional("TlsTable", PH.DataDirectories[COFF::TLS_TABLE]);
Added: llvm/trunk/test/tools/llvm-readobj/Inputs/has_pdb.exe
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/has_pdb.exe?rev=271539&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-readobj/Inputs/has_pdb.exe (added) and llvm/trunk/test/tools/llvm-readobj/Inputs/has_pdb.exe Thu Jun 2 12:10:43 2016 differ
Added: llvm/trunk/test/tools/llvm-readobj/coff-debug-directory.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/coff-debug-directory.test?rev=271539&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/coff-debug-directory.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/coff-debug-directory.test Thu Jun 2 12:10:43 2016
@@ -0,0 +1,34 @@
+RUN: llvm-readobj -coff-debug-directory %p/Inputs/has_pdb.exe | FileCheck %s
+
+CHECK: DebugDirectory [
+CHECK: DebugEntry {
+CHECK: Characteristics: 0x0
+CHECK: TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
+CHECK: MajorVersion: 0x0
+CHECK: MinorVersion: 0x0
+CHECK: Type: CodeView (0x2)
+CHECK: SizeOfData: 0x36
+CHECK: AddressOfRawData: 0x5B068
+CHECK: PointerToRawData: 0x5A268
+CHECK: PDBInfo {
+CHECK: PDBSignature: 0x53445352
+CHECK: PDBGUID: (96 83 40 42 81 07 9D 40 90 1B 4A 3C 0D 4F 56 32)
+CHECK: PDBAge: 3
+CHECK: PDBFileName: D:\src\llvm\build\has_pdb.pdb
+CHECK: }
+CHECK: }
+CHECK: DebugEntry {
+CHECK: Characteristics: 0x0
+CHECK: TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
+CHECK: MajorVersion: 0x0
+CHECK: MinorVersion: 0x0
+CHECK: Type: VCFeature (0xC)
+CHECK: SizeOfData: 0x14
+CHECK: AddressOfRawData: 0x5B0A0
+CHECK: PointerToRawData: 0x5A2A0
+CHECK: RawData (
+CHECK: 0000: 00000000 C1000000 C1000000 00000000 |................|
+CHECK: 0010: C0000000 |....|
+CHECK: )
+CHECK: }
+CHECK: ]
Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Thu Jun 2 12:10:43 2016
@@ -75,6 +75,7 @@ public:
void printCOFFExports() override;
void printCOFFDirectives() override;
void printCOFFBaseReloc() override;
+ void printCOFFDebugDirectory() override;
void printCodeViewDebugInfo() override;
void
mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
@@ -475,6 +476,25 @@ static const EnumEntry<COFF::COMDATType>
{ "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
};
+static const EnumEntry<COFF::DebugType> ImageDebugType[] = {
+ { "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN },
+ { "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF },
+ { "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW },
+ { "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO },
+ { "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC },
+ { "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION },
+ { "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP },
+ { "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC },
+ { "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC },
+ { "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND },
+ { "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID },
+ { "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE },
+ { "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO },
+ { "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG },
+ { "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX },
+ { "NoTimestamp", COFF::IMAGE_DEBUG_TYPE_NO_TIMESTAMP },
+};
+
static const EnumEntry<COFF::WeakExternalCharacteristics>
WeakExternalCharacteristics[] = {
{ "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
@@ -643,8 +663,42 @@ void COFFDumper::printPEHeader(const PEH
"DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
};
- for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
+ for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i)
printDataDirectory(i, directory[i]);
+ }
+}
+
+void COFFDumper::printCOFFDebugDirectory() {
+ ListScope LS(W, "DebugDirectory");
+ for (const debug_directory &D : Obj->debug_directories()) {
+ char FormattedTime[20] = {};
+ time_t TDS = D.TimeDateStamp;
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+ DictScope S(W, "DebugEntry");
+ W.printHex("Characteristics", D.Characteristics);
+ W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp);
+ W.printHex("MajorVersion", D.MajorVersion);
+ W.printHex("MinorVersion", D.MinorVersion);
+ W.printEnum("Type", D.Type, makeArrayRef(ImageDebugType));
+ W.printHex("SizeOfData", D.SizeOfData);
+ W.printHex("AddressOfRawData", D.AddressOfRawData);
+ W.printHex("PointerToRawData", D.PointerToRawData);
+ if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) {
+ const debug_pdb_info *PDBInfo;
+ StringRef PDBFileName;
+ error(Obj->getDebugPDBInfo(&D, PDBInfo, PDBFileName));
+ DictScope PDBScope(W, "PDBInfo");
+ W.printHex("PDBSignature", PDBInfo->Signature);
+ W.printBinary("PDBGUID", makeArrayRef(PDBInfo->Guid));
+ W.printNumber("PDBAge", PDBInfo->Age);
+ W.printString("PDBFileName", PDBFileName);
+ } else {
+ // FIXME: Type values of 12 and 13 are commonly observed but are not in
+ // the documented type enum. Figure out what they mean.
+ ArrayRef<uint8_t> RawData;
+ error(
+ Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData));
+ W.printBinaryBlock("RawData", RawData);
}
}
}
Modified: llvm/trunk/tools/llvm-readobj/ObjDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ObjDumper.h?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ObjDumper.h (original)
+++ llvm/trunk/tools/llvm-readobj/ObjDumper.h Thu Jun 2 12:10:43 2016
@@ -62,6 +62,7 @@ public:
virtual void printCOFFExports() { }
virtual void printCOFFDirectives() { }
virtual void printCOFFBaseReloc() { }
+ virtual void printCOFFDebugDirectory() { }
virtual void printCodeViewDebugInfo() { }
virtual void
mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=271539&r1=271538&r2=271539&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Thu Jun 2 12:10:43 2016
@@ -196,6 +196,11 @@ namespace opts {
COFFBaseRelocs("coff-basereloc",
cl::desc("Display the PE/COFF .reloc section"));
+ // -coff-debug-directory
+ cl::opt<bool>
+ COFFDebugDirectory("coff-debug-directory",
+ cl::desc("Display the PE/COFF debug directory"));
+
// -macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
@@ -392,6 +397,8 @@ static void dumpObject(const ObjectFile
Dumper->printCOFFDirectives();
if (opts::COFFBaseRelocs)
Dumper->printCOFFBaseReloc();
+ if (opts::COFFDebugDirectory)
+ Dumper->printCOFFDebugDirectory();
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
More information about the llvm-commits
mailing list