llvm.org GIT mirror llvm / fb1a911
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271539 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 3 years ago
9 changed file(s) with 218 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
168168 support::ulittle32_t ImportAddressTableRVA;
169169 };
170170
171 struct debug_directory {
172 support::ulittle32_t Characteristics;
173 support::ulittle32_t TimeDateStamp;
174 support::ulittle16_t MajorVersion;
175 support::ulittle16_t MinorVersion;
176 support::ulittle32_t Type;
177 support::ulittle32_t SizeOfData;
178 support::ulittle32_t AddressOfRawData;
179 support::ulittle32_t PointerToRawData;
180 };
181
182 /// Information that is resent in debug_directory::AddressOfRawData if Type is
183 /// IMAGE_DEBUG_TYPE_CODEVIEW.
184 struct debug_pdb_info {
185 support::ulittle32_t Signature;
186 uint8_t Guid[16];
187 support::ulittle32_t Age;
188 // PDBFileName: The null-terminated PDB file name follows.
189 };
190
171191 template
172192 struct import_lookup_table_entry {
173193 IntTy Data;
619639 const export_directory_table_entry *ExportDirectory;
620640 const coff_base_reloc_block_header *BaseRelocHeader;
621641 const coff_base_reloc_block_header *BaseRelocEnd;
642 const debug_directory *DebugDirectoryBegin;
643 const debug_directory *DebugDirectoryEnd;
622644
623645 std::error_code getString(uint32_t offset, StringRef &Res) const;
624646
632654 std::error_code initDelayImportTablePtr();
633655 std::error_code initExportTablePtr();
634656 std::error_code initBaseRelocPtr();
657 std::error_code initDebugDirectoryPtr();
635658
636659 public:
637660 uintptr_t getSymbolTable() const {
753776 export_directory_iterator export_directory_end() const;
754777 base_reloc_iterator base_reloc_begin() const;
755778 base_reloc_iterator base_reloc_end() const;
779 const debug_directory *debug_directory_begin() const {
780 return DebugDirectoryBegin;
781 }
782 const debug_directory *debug_directory_end() const {
783 return DebugDirectoryEnd;
784 }
756785
757786 iterator_range import_directories() const;
758787 iterator_range
759788 delay_import_directories() const;
760789 iterator_range export_directories() const;
761790 iterator_range base_relocs() const;
791 iterator_range debug_directories() const {
792 return make_range(debug_directory_begin(), debug_directory_end());
793 }
762794
763795 const dos_header *getDOSHeader() const {
764796 if (!PE32Header && !PE32PlusHeader)
827859 uint64_t getImageBase() const;
828860 std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const;
829861 std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
862
863 /// Given an RVA base and size, returns a valid array of bytes or an error
864 /// code if the RVA and size is not contained completely within a valid
865 /// section.
866 std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
867 ArrayRef &Contents) const;
868
830869 std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
831870 StringRef &Name) const;
871
872 std::error_code getDebugPDBInfo(const debug_directory *DebugDir,
873 const debug_pdb_info *&Info,
874 StringRef &PDBFileName) const;
832875
833876 bool isRelocatableObject() const override;
834877 bool is64() const { return PE32PlusHeader; }
528528 EXCEPTION_TABLE,
529529 CERTIFICATE_TABLE,
530530 BASE_RELOCATION_TABLE,
531 DEBUG,
531 DEBUG_DIRECTORY,
532532 ARCHITECTURE,
533533 GLOBAL_PTR,
534534 TLS_TABLE,
597597 IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7,
598598 IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
599599 IMAGE_DEBUG_TYPE_BORLAND = 9,
600 IMAGE_DEBUG_TYPE_CLSID = 11
600 IMAGE_DEBUG_TYPE_CLSID = 11,
601 IMAGE_DEBUG_TYPE_VC_FEATURE = 12,
602 IMAGE_DEBUG_TYPE_POGO = 13,
603 IMAGE_DEBUG_TYPE_ILTCG = 14,
604 IMAGE_DEBUG_TYPE_MPX = 15,
605 IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16,
601606 };
602607
603608 enum BaseRelocationType {
452452 return object_error::parse_failed;
453453 }
454454
455 std::error_code
456 COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
457 ArrayRef &Contents) const {
458 for (const SectionRef &S : sections()) {
459 const coff_section *Section = getCOFFSection(S);
460 uint32_t SectionStart = Section->VirtualAddress;
461 // Check if this RVA is within the section bounds. Be careful about integer
462 // overflow.
463 uint32_t OffsetIntoSection = RVA - SectionStart;
464 if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
465 Size <= Section->VirtualSize - OffsetIntoSection) {
466 uintptr_t Begin =
467 uintptr_t(base()) + Section->PointerToRawData + OffsetIntoSection;
468 Contents =
469 ArrayRef(reinterpret_cast(Begin), Size);
470 return std::error_code();
471 }
472 }
473 return object_error::parse_failed;
474 }
475
455476 // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
456477 // table entry.
457478 std::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
462483 const uint8_t *Ptr = reinterpret_cast(IntPtr);
463484 Hint = *reinterpret_cast(Ptr);
464485 Name = StringRef(reinterpret_cast(Ptr + 2));
486 return std::error_code();
487 }
488
489 std::error_code COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
490 const debug_pdb_info *&PDBInfo,
491 StringRef &PDBFileName) const {
492 ArrayRef InfoBytes;
493 if (std::error_code EC = getRvaAndSizeAsBytes(
494 DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
495 return EC;
496 if (InfoBytes.size() < sizeof(debug_pdb_info) + 1)
497 return object_error::parse_failed;
498 PDBInfo = reinterpret_cast(InfoBytes.data());
499 InfoBytes = InfoBytes.drop_front(sizeof(debug_pdb_info));
500 PDBFileName = StringRef(reinterpret_cast(InfoBytes.data()),
501 InfoBytes.size());
502 // Truncate the name at the first null byte. Ignore any padding.
503 PDBFileName = PDBFileName.split('\0').first;
465504 return std::error_code();
466505 }
467506
550589 return std::error_code();
551590 }
552591
592 std::error_code COFFObjectFile::initDebugDirectoryPtr() {
593 // Get the RVA of the debug directory. Do nothing if it does not exist.
594 const data_directory *DataEntry;
595 if (getDataDirectory(COFF::DEBUG_DIRECTORY, DataEntry))
596 return std::error_code();
597
598 // Do nothing if the RVA is NULL.
599 if (DataEntry->RelativeVirtualAddress == 0)
600 return std::error_code();
601
602 // Check that the size is a multiple of the entry size.
603 if (DataEntry->Size % sizeof(debug_directory) != 0)
604 return object_error::parse_failed;
605
606 uintptr_t IntPtr = 0;
607 if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
608 return EC;
609 DebugDirectoryBegin = reinterpret_cast(IntPtr);
610 if (std::error_code EC = getRvaPtr(
611 DataEntry->RelativeVirtualAddress + DataEntry->Size, IntPtr))
612 return EC;
613 DebugDirectoryEnd = reinterpret_cast(IntPtr);
614 return std::error_code();
615 }
616
553617 COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
554618 : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
555619 COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
557621 SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
558622 ImportDirectory(nullptr), NumberOfImportDirectory(0),
559623 DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0),
560 ExportDirectory(nullptr), BaseRelocHeader(nullptr),
561 BaseRelocEnd(nullptr) {
624 ExportDirectory(nullptr), BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
625 DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {
562626 // Check that we at least have enough room for a header.
563627 if (!checkSize(Data, EC, sizeof(coff_file_header)))
564628 return;
672736
673737 // Initialize the pointer to the base relocation table.
674738 if ((EC = initBaseRelocPtr()))
739 return;
740
741 // Initialize the pointer to the export table.
742 if ((EC = initDebugDirectoryPtr()))
675743 return;
676744
677745 EC = std::error_code();
396396 IO.mapOptional("CertificateTable", PH.DataDirectories[COFF::CERTIFICATE_TABLE]);
397397 IO.mapOptional("BaseRelocationTable",
398398 PH.DataDirectories[COFF::BASE_RELOCATION_TABLE]);
399 IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG]);
399 IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG_DIRECTORY]);
400400 IO.mapOptional("Architecture", PH.DataDirectories[COFF::ARCHITECTURE]);
401401 IO.mapOptional("GlobalPtr", PH.DataDirectories[COFF::GLOBAL_PTR]);
402402 IO.mapOptional("TlsTable", PH.DataDirectories[COFF::TLS_TABLE]);
0 RUN: llvm-readobj -coff-debug-directory %p/Inputs/has_pdb.exe | FileCheck %s
1
2 CHECK: DebugDirectory [
3 CHECK: DebugEntry {
4 CHECK: Characteristics: 0x0
5 CHECK: TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
6 CHECK: MajorVersion: 0x0
7 CHECK: MinorVersion: 0x0
8 CHECK: Type: CodeView (0x2)
9 CHECK: SizeOfData: 0x36
10 CHECK: AddressOfRawData: 0x5B068
11 CHECK: PointerToRawData: 0x5A268
12 CHECK: PDBInfo {
13 CHECK: PDBSignature: 0x53445352
14 CHECK: PDBGUID: (96 83 40 42 81 07 9D 40 90 1B 4A 3C 0D 4F 56 32)
15 CHECK: PDBAge: 3
16 CHECK: PDBFileName: D:\src\llvm\build\has_pdb.pdb
17 CHECK: }
18 CHECK: }
19 CHECK: DebugEntry {
20 CHECK: Characteristics: 0x0
21 CHECK: TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
22 CHECK: MajorVersion: 0x0
23 CHECK: MinorVersion: 0x0
24 CHECK: Type: VCFeature (0xC)
25 CHECK: SizeOfData: 0x14
26 CHECK: AddressOfRawData: 0x5B0A0
27 CHECK: PointerToRawData: 0x5A2A0
28 CHECK: RawData (
29 CHECK: 0000: 00000000 C1000000 C1000000 00000000 |................|
30 CHECK: 0010: C0000000 |....|
31 CHECK: )
32 CHECK: }
33 CHECK: ]
7474 void printCOFFExports() override;
7575 void printCOFFDirectives() override;
7676 void printCOFFBaseReloc() override;
77 void printCOFFDebugDirectory() override;
7778 void printCodeViewDebugInfo() override;
7879 void
7980 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
474475 { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
475476 };
476477
478 static const EnumEntry ImageDebugType[] = {
479 { "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN },
480 { "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF },
481 { "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW },
482 { "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO },
483 { "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC },
484 { "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION },
485 { "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP },
486 { "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC },
487 { "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC },
488 { "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND },
489 { "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID },
490 { "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE },
491 { "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO },
492 { "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG },
493 { "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX },
494 { "NoTimestamp", COFF::IMAGE_DEBUG_TYPE_NO_TIMESTAMP },
495 };
496
477497 static const EnumEntry
478498 WeakExternalCharacteristics[] = {
479499 { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
642662 "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
643663 };
644664
645 for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
665 for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i)
646666 printDataDirectory(i, directory[i]);
667 }
668 }
669
670 void COFFDumper::printCOFFDebugDirectory() {
671 ListScope LS(W, "DebugDirectory");
672 for (const debug_directory &D : Obj->debug_directories()) {
673 char FormattedTime[20] = {};
674 time_t TDS = D.TimeDateStamp;
675 strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
676 DictScope S(W, "DebugEntry");
677 W.printHex("Characteristics", D.Characteristics);
678 W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp);
679 W.printHex("MajorVersion", D.MajorVersion);
680 W.printHex("MinorVersion", D.MinorVersion);
681 W.printEnum("Type", D.Type, makeArrayRef(ImageDebugType));
682 W.printHex("SizeOfData", D.SizeOfData);
683 W.printHex("AddressOfRawData", D.AddressOfRawData);
684 W.printHex("PointerToRawData", D.PointerToRawData);
685 if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) {
686 const debug_pdb_info *PDBInfo;
687 StringRef PDBFileName;
688 error(Obj->getDebugPDBInfo(&D, PDBInfo, PDBFileName));
689 DictScope PDBScope(W, "PDBInfo");
690 W.printHex("PDBSignature", PDBInfo->Signature);
691 W.printBinary("PDBGUID", makeArrayRef(PDBInfo->Guid));
692 W.printNumber("PDBAge", PDBInfo->Age);
693 W.printString("PDBFileName", PDBFileName);
694 } else {
695 // FIXME: Type values of 12 and 13 are commonly observed but are not in
696 // the documented type enum. Figure out what they mean.
697 ArrayRef RawData;
698 error(
699 Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData));
700 W.printBinaryBlock("RawData", RawData);
647701 }
648702 }
649703 }
6161 virtual void printCOFFExports() { }
6262 virtual void printCOFFDirectives() { }
6363 virtual void printCOFFBaseReloc() { }
64 virtual void printCOFFDebugDirectory() { }
6465 virtual void printCodeViewDebugInfo() { }
6566 virtual void
6667 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
194194 cl::opt
195195 COFFBaseRelocs("coff-basereloc",
196196 cl::desc("Display the PE/COFF .reloc section"));
197
198 // -coff-debug-directory
199 cl::opt
200 COFFDebugDirectory("coff-debug-directory",
201 cl::desc("Display the PE/COFF debug directory"));
197202
198203 // -macho-data-in-code
199204 cl::opt
391396 Dumper->printCOFFDirectives();
392397 if (opts::COFFBaseRelocs)
393398 Dumper->printCOFFBaseReloc();
399 if (opts::COFFDebugDirectory)
400 Dumper->printCOFFDebugDirectory();
394401 if (opts::CodeView)
395402 Dumper->printCodeViewDebugInfo();
396403 if (opts::CodeViewMergedTypes)