X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-readobj%2FCOFFDumper.cpp;h=5b4129a10c536abc0fce3f3ed6efaba0fdbc35cb;hb=813f44a29fd0fd140127023222d0633e23783bcc;hp=3cbb9b3c34bf1b06eb229823db6a94263ccf6045;hpb=6c1202c459ffa6d693ad92fa84e43902bc780bca;p=oota-llvm.git diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 3cbb9b3c34b..5b4129a10c5 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -13,25 +13,28 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" -#include "ObjDumper.h" - +#include "ARMWinEHPrinter.h" #include "Error.h" +#include "ObjDumper.h" +#include "StackMapPrinter.h" #include "StreamWriter.h" - +#include "Win64EHDumper.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" - #include #include +#include #include using namespace llvm; @@ -45,54 +48,53 @@ public: COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) : ObjDumper(Writer) , Obj(Obj) { - cacheRelocations(); } - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; - + void printFileHeaders() override; + void printSections() override; + void printRelocations() override; + void printSymbols() override; + void printDynamicSymbols() override; + void printUnwindInfo() override; + void printCOFFImports() override; + void printCOFFExports() override; + void printCOFFDirectives() override; + void printCOFFBaseReloc() override; + void printStackMap() const override; private: - void printSymbol(symbol_iterator SymI); - - void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printSymbol(const SymbolRef &Sym); + void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); + void printDataDirectory(uint32_t Index, const std::string &FieldName); - void printX64UnwindInfo(); + void printDOSHeader(const dos_header *DH); + template void printPEHeader(const PEHeader *Hdr); + void printBaseOfDataField(const pe32_header *Hdr); + void printBaseOfDataField(const pe32plus_header *Hdr); - void printRuntimeFunction( - const RuntimeFunction& RTF, - uint64_t OffsetInSection, - const std::vector &Rels); + void printCodeViewDebugInfo(const SectionRef &Section); - void printUnwindInfo( - const Win64EH::UnwindInfo& UI, - uint64_t OffsetInSection, - const std::vector &Rels); - - void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef UCs); + void printCodeViewSymbolsSubsection(StringRef Subsection, + const SectionRef &Section, + uint32_t Offset); void cacheRelocations(); - error_code getSectionContents( - const std::vector &Rels, - uint64_t Offset, - ArrayRef &Contents, - uint64_t &Addr); - - error_code getSection( - const std::vector &Rels, - uint64_t Offset, - const coff_section **Section, - uint64_t *AddrPtr); + std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset, + SymbolRef &Sym); + std::error_code resolveSymbolName(const coff_section *Section, + uint64_t Offset, StringRef &Name); + void printImportedSymbols(iterator_range Range); + void printDelayImportedSymbols( + const DelayImportDirectoryEntryRef &I, + iterator_range Range); typedef DenseMap > RelocMapTy; const llvm::object::COFFObjectFile *Obj; + bool RelocCached = false; RelocMapTy RelocMap; - std::vector EmptyRelocs; + StringRef CVFileIndexToStringOffsetTable; + StringRef CVStringTable; }; } // namespace @@ -100,9 +102,9 @@ private: namespace llvm { -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr &Result) { +std::error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr &Result) { const COFFObjectFile *COFFObj = dyn_cast(Obj); if (!COFFObj) return readobj_error::unsupported_obj_file_format; @@ -113,111 +115,36 @@ error_code createCOFFDumper(const object::ObjectFile *Obj, } // namespace llvm - -// Returns the name of the unwind code. -static StringRef getUnwindCodeTypeName(uint8_t Code) { - switch(Code) { - default: llvm_unreachable("Invalid unwind code"); - case UOP_PushNonVol: return "PUSH_NONVOL"; - case UOP_AllocLarge: return "ALLOC_LARGE"; - case UOP_AllocSmall: return "ALLOC_SMALL"; - case UOP_SetFPReg: return "SET_FPREG"; - case UOP_SaveNonVol: return "SAVE_NONVOL"; - case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; - case UOP_SaveXMM128: return "SAVE_XMM128"; - case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; - case UOP_PushMachFrame: return "PUSH_MACHFRAME"; - } -} - -// Returns the name of a referenced register. -static StringRef getUnwindRegisterName(uint8_t Reg) { - switch(Reg) { - default: llvm_unreachable("Invalid register"); - case 0: return "RAX"; - case 1: return "RCX"; - case 2: return "RDX"; - case 3: return "RBX"; - case 4: return "RSP"; - case 5: return "RBP"; - case 6: return "RSI"; - case 7: return "RDI"; - case 8: return "R8"; - case 9: return "R9"; - case 10: return "R10"; - case 11: return "R11"; - case 12: return "R12"; - case 13: return "R13"; - case 14: return "R14"; - case 15: return "R15"; - } -} - -// Calculates the number of array slots required for the unwind code. -static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { - switch (UnwindCode.getUnwindOp()) { - default: llvm_unreachable("Invalid unwind code"); - case UOP_PushNonVol: - case UOP_AllocSmall: - case UOP_SetFPReg: - case UOP_PushMachFrame: - return 1; - case UOP_SaveNonVol: - case UOP_SaveXMM128: - return 2; - case UOP_SaveNonVolBig: - case UOP_SaveXMM128Big: - return 3; - case UOP_AllocLarge: - return (UnwindCode.getOpInfo() == 0) ? 2 : 3; - } -} - -// Given a symbol sym this functions returns the address and section of it. -static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, - const SymbolRef &Sym, - const coff_section *&ResolvedSection, - uint64_t &ResolvedAddr) { - if (error_code EC = Sym.getAddress(ResolvedAddr)) - return EC; - - section_iterator iter(Obj->begin_sections()); - if (error_code EC = Sym.getSection(iter)) - return EC; - - ResolvedSection = Obj->getCOFFSection(iter); - return object_error::success; -} - -// Given a vector of relocations for a section and an offset into this section -// the function returns the symbol used for the relocation at the offset. -static error_code resolveSymbol(const std::vector &Rels, - uint64_t Offset, SymbolRef &Sym) { - for (std::vector::const_iterator RelI = Rels.begin(), - RelE = Rels.end(); - RelI != RelE; ++RelI) { - uint64_t Ofs; - if (error_code EC = RelI->getOffset(Ofs)) - return EC; - - if (Ofs == Offset) { - Sym = *RelI->getSymbol(); +// Given a a section and an offset into this section the function returns the +// symbol used for the relocation at the offset. +std::error_code COFFDumper::resolveSymbol(const coff_section *Section, + uint64_t Offset, SymbolRef &Sym) { + cacheRelocations(); + const auto &Relocations = RelocMap[Section]; + for (const auto &Relocation : Relocations) { + uint64_t RelocationOffset = Relocation.getOffset(); + + if (RelocationOffset == Offset) { + Sym = *Relocation.getSymbol(); return readobj_error::success; } } - return readobj_error::unknown_symbol; } -// Given a vector of relocations for a section and an offset into this section -// the function returns the name of the symbol used for the relocation at the -// offset. -static error_code resolveSymbolName(const std::vector &Rels, - uint64_t Offset, StringRef &Name) { - SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; - if (error_code EC = Sym.getName(Name)) return EC; - return object_error::success; +// Given a section and an offset into this section the function returns the name +// of the symbol used for the relocation at the offset. +std::error_code COFFDumper::resolveSymbolName(const coff_section *Section, + uint64_t Offset, + StringRef &Name) { + SymbolRef Symbol; + if (std::error_code EC = resolveSymbol(Section, Offset, Symbol)) + return EC; + ErrorOr NameOrErr = Symbol.getName(); + if (std::error_code EC = NameOrErr.getError()) + return EC; + Name = *NameOrErr; + return std::error_code(); } static const EnumEntry ImageFileMachineType[] = { @@ -225,7 +152,7 @@ static const EnumEntry ImageFileMachineType[] = { LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), - LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), @@ -262,8 +189,37 @@ static const EnumEntry ImageFileCharacteristics[] = { LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI ) }; +static const EnumEntry PEWindowsSubsystem[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX ), +}; + +static const EnumEntry PEDLLCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE), +}; + static const EnumEntry ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), @@ -374,207 +330,421 @@ WeakExternalCharacteristics[] = { { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } }; -static const EnumEntry UnwindFlags[] = { - { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, - { "TerminateHandler", Win64EH::UNW_TerminateHandler }, - { "ChainInfo" , Win64EH::UNW_ChainInfo } -}; - -static const EnumEntry UnwindOpInfo[] = { - { "RAX", 0 }, - { "RCX", 1 }, - { "RDX", 2 }, - { "RBX", 3 }, - { "RSP", 4 }, - { "RBP", 5 }, - { "RSI", 6 }, - { "RDI", 7 }, - { "R8", 8 }, - { "R9", 9 }, - { "R10", 10 }, - { "R11", 11 }, - { "R12", 12 }, - { "R13", 13 }, - { "R14", 14 }, - { "R15", 15 } -}; +template +static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, + COFFSymbolRef Symbol, + uint8_t AuxSymbolIdx, const T *&Aux) { + ArrayRef AuxData = Obj->getSymbolAuxData(Symbol); + AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize()); + Aux = reinterpret_cast(AuxData.data()); + return readobj_error::success; +} -// Some additional COFF structures not defined by llvm::object. -namespace { - struct coff_aux_function_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t TotalSize; - support::ulittle32_t PointerToLineNumber; - support::ulittle32_t PointerToNextFunction; - uint8_t Unused[2]; - }; - - struct coff_aux_weak_external_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t Characteristics; - uint8_t Unused[10]; - }; - - struct coff_aux_file_record { - char FileName[18]; - }; - - struct coff_aux_clr_token { - support::ulittle8_t AuxType; - support::ulittle8_t Reserved; - support::ulittle32_t SymbolTableIndex; - uint8_t Unused[12]; - }; -} // namespace +void COFFDumper::cacheRelocations() { + if (RelocCached) + return; + RelocCached = true; -static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { - return static_cast(UI.getLanguageSpecificData()) - - reinterpret_cast(&UI); -} + for (const SectionRef &S : Obj->sections()) { + const coff_section *Section = Obj->getCOFFSection(S); -static uint32_t getLargeSlotValue(ArrayRef UCs) { - if (UCs.size() < 3) - return 0; + for (const RelocationRef &Reloc : S.relocations()) + RelocMap[Section].push_back(Reloc); - return UCs[1].FrameOffset + (static_cast(UCs[2].FrameOffset) << 16); + // Sort relocations by address. + std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), + relocAddressLess); + } } -template -static error_code getSymbolAuxData(const COFFObjectFile *Obj, - const coff_symbol *Symbol, const T* &Aux) { - ArrayRef AuxData = Obj->getSymbolAuxData(Symbol); - Aux = reinterpret_cast(AuxData.data()); - return readobj_error::success; +void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) { + const data_directory *Data; + if (Obj->getDataDirectory(Index, Data)) + return; + W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress); + W.printHex(FieldName + "Size", Data->Size); } -static std::string formatSymbol(const std::vector &Rels, - uint64_t Offset, uint32_t Disp) { - std::string Buffer; - raw_string_ostream Str(Buffer); +void COFFDumper::printFileHeaders() { + time_t TDS = Obj->getTimeDateStamp(); + char FormattedTime[20] = { }; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); - StringRef Sym; - if (resolveSymbolName(Rels, Offset, Sym)) { - Str << format(" (0x%X)", Offset); - return Str.str(); + { + DictScope D(W, "ImageFileHeader"); + W.printEnum ("Machine", Obj->getMachine(), + makeArrayRef(ImageFileMachineType)); + W.printNumber("SectionCount", Obj->getNumberOfSections()); + W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp()); + W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable()); + W.printNumber("SymbolCount", Obj->getNumberOfSymbols()); + W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader()); + W.printFlags ("Characteristics", Obj->getCharacteristics(), + makeArrayRef(ImageFileCharacteristics)); } - Str << Sym; - if (Disp > 0) { - Str << format(" +0x%X (0x%X)", Disp, Offset); - } else { - Str << format(" (0x%X)", Offset); - } + // Print PE header. This header does not exist if this is an object file and + // not an executable. + const pe32_header *PEHeader = nullptr; + error(Obj->getPE32Header(PEHeader)); + if (PEHeader) + printPEHeader(PEHeader); - return Str.str(); -} + const pe32plus_header *PEPlusHeader = nullptr; + error(Obj->getPE32PlusHeader(PEPlusHeader)); + if (PEPlusHeader) + printPEHeader(PEPlusHeader); -// Given a vector of relocations for a section and an offset into this section -// the function resolves the symbol used for the relocation at the offset and -// returns the section content and the address inside the content pointed to -// by the symbol. -error_code COFFDumper::getSectionContents( - const std::vector &Rels, uint64_t Offset, - ArrayRef &Contents, uint64_t &Addr) { + if (const dos_header *DH = Obj->getDOSHeader()) + printDOSHeader(DH); +} - SymbolRef Sym; - const coff_section *Section; +void COFFDumper::printDOSHeader(const dos_header *DH) { + DictScope D(W, "DOSHeader"); + W.printString("Magic", StringRef(DH->Magic, sizeof(DH->Magic))); + W.printNumber("UsedBytesInTheLastPage", DH->UsedBytesInTheLastPage); + W.printNumber("FileSizeInPages", DH->FileSizeInPages); + W.printNumber("NumberOfRelocationItems", DH->NumberOfRelocationItems); + W.printNumber("HeaderSizeInParagraphs", DH->HeaderSizeInParagraphs); + W.printNumber("MinimumExtraParagraphs", DH->MinimumExtraParagraphs); + W.printNumber("MaximumExtraParagraphs", DH->MaximumExtraParagraphs); + W.printNumber("InitialRelativeSS", DH->InitialRelativeSS); + W.printNumber("InitialSP", DH->InitialSP); + W.printNumber("Checksum", DH->Checksum); + W.printNumber("InitialIP", DH->InitialIP); + W.printNumber("InitialRelativeCS", DH->InitialRelativeCS); + W.printNumber("AddressOfRelocationTable", DH->AddressOfRelocationTable); + W.printNumber("OverlayNumber", DH->OverlayNumber); + W.printNumber("OEMid", DH->OEMid); + W.printNumber("OEMinfo", DH->OEMinfo); + W.printNumber("AddressOfNewExeHeader", DH->AddressOfNewExeHeader); +} - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) - return EC; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return EC; - if (error_code EC = Obj->getSectionContents(Section, Contents)) - return EC; +template +void COFFDumper::printPEHeader(const PEHeader *Hdr) { + DictScope D(W, "ImageOptionalHeader"); + W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion); + W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion); + W.printNumber("SizeOfCode", Hdr->SizeOfCode); + W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData); + W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData); + W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint); + W.printHex ("BaseOfCode", Hdr->BaseOfCode); + printBaseOfDataField(Hdr); + W.printHex ("ImageBase", Hdr->ImageBase); + W.printNumber("SectionAlignment", Hdr->SectionAlignment); + W.printNumber("FileAlignment", Hdr->FileAlignment); + W.printNumber("MajorOperatingSystemVersion", + Hdr->MajorOperatingSystemVersion); + W.printNumber("MinorOperatingSystemVersion", + Hdr->MinorOperatingSystemVersion); + W.printNumber("MajorImageVersion", Hdr->MajorImageVersion); + W.printNumber("MinorImageVersion", Hdr->MinorImageVersion); + W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion); + W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion); + W.printNumber("SizeOfImage", Hdr->SizeOfImage); + W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders); + W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem)); + W.printFlags ("Characteristics", Hdr->DLLCharacteristics, + makeArrayRef(PEDLLCharacteristics)); + W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve); + W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit); + W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve); + W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit); + W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize); + + if (Hdr->NumberOfRvaAndSize > 0) { + DictScope D(W, "DataDirectory"); + static const char * const directory[] = { + "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable", + "CertificateTable", "BaseRelocationTable", "Debug", "Architecture", + "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT", + "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" + }; + + for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) { + printDataDirectory(i, directory[i]); + } + } +} - return object_error::success; +void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { + W.printHex("BaseOfData", Hdr->BaseOfData); } -error_code COFFDumper::getSection( - const std::vector &Rels, uint64_t Offset, - const coff_section **SectionPtr, uint64_t *AddrPtr) { +void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} - SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) - return EC; +void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { + StringRef Data; + error(Section.getContents(Data)); - const coff_section *Section; - uint64_t Addr; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return EC; + SmallVector FunctionNames; + StringMap FunctionLineTables; - if (SectionPtr) - *SectionPtr = Section; - if (AddrPtr) - *AddrPtr = Addr; + ListScope D(W, "CodeViewDebugInfo"); + { + // FIXME: Add more offset correctness checks. + DataExtractor DE(Data, true, 4); + uint32_t Offset = 0, + Magic = DE.getU32(&Offset); + W.printHex("Magic", Magic); + if (Magic != COFF::DEBUG_SECTION_MAGIC) { + error(object_error::parse_failed); + return; + } - return object_error::success; -} + bool Finished = false; + while (DE.isValidOffset(Offset) && !Finished) { + // The section consists of a number of subsection in the following format: + // |Type|PayloadSize|Payload...| + uint32_t SubSectionType = DE.getU32(&Offset), + PayloadSize = DE.getU32(&Offset); + ListScope S(W, "Subsection"); + W.printHex("Type", SubSectionType); + W.printHex("PayloadSize", PayloadSize); + if (PayloadSize > Data.size() - Offset) { + error(object_error::parse_failed); + return; + } -void COFFDumper::cacheRelocations() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; + StringRef Contents = Data.substr(Offset, PayloadSize); + if (opts::CodeViewSubsectionBytes) { + // Print the raw contents to simplify debugging if anything goes wrong + // afterwards. + W.printBinaryBlock("Contents", Contents); + } - const coff_section *Section = Obj->getCOFFSection(SecI); + switch (SubSectionType) { + case COFF::DEBUG_SYMBOL_SUBSECTION: + if (opts::SectionSymbols) + printCodeViewSymbolsSubsection(Contents, Section, Offset); + break; + case COFF::DEBUG_LINE_TABLE_SUBSECTION: { + // Holds a PC to file:line table. Some data to parse this subsection is + // stored in the other subsections, so just check sanity and store the + // pointers for deferred processing. + + if (PayloadSize < 12) { + // There should be at least three words to store two function + // relocations and size of the code. + error(object_error::parse_failed); + return; + } - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, + LinkageName)); + W.printString("LinkageName", LinkageName); + if (FunctionLineTables.count(LinkageName) != 0) { + // Saw debug info for this function already? + error(object_error::parse_failed); + return; + } + + FunctionLineTables[LinkageName] = Contents; + FunctionNames.push_back(LinkageName); + break; + } + case COFF::DEBUG_STRING_TABLE_SUBSECTION: + if (PayloadSize == 0 || CVStringTable.data() != nullptr || + Contents.back() != '\0') { + // Empty or duplicate or non-null-terminated subsection. + error(object_error::parse_failed); + return; + } + CVStringTable = Contents; + break; + case COFF::DEBUG_INDEX_SUBSECTION: + // Holds the translation table from file indices + // to offsets in the string table. + + if (PayloadSize == 0 || + CVFileIndexToStringOffsetTable.data() != nullptr) { + // Empty or duplicate subsection. + error(object_error::parse_failed); + return; + } + CVFileIndexToStringOffsetTable = Contents; break; + } + Offset += PayloadSize; - RelocMap[Section].push_back(*RelI); + // Align the reading pointer by 4. + Offset += (-Offset) % 4; } + } - // Sort relocations by address. - std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), - relocAddressLess); + // Dump the line tables now that we've read all the subsections and know all + // the required information. + for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) { + StringRef Name = FunctionNames[I]; + ListScope S(W, "FunctionLineTable"); + W.printString("LinkageName", Name); + + DataExtractor DE(FunctionLineTables[Name], true, 4); + uint32_t Offset = 6; // Skip relocations. + uint16_t Flags = DE.getU16(&Offset); + W.printHex("Flags", Flags); + bool HasColumnInformation = + Flags & COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS; + uint32_t FunctionSize = DE.getU32(&Offset); + W.printHex("CodeSize", FunctionSize); + while (DE.isValidOffset(Offset)) { + // For each range of lines with the same filename, we have a segment + // in the line table. The filename string is accessed using double + // indirection to the string table subsection using the index subsection. + uint32_t OffsetInIndex = DE.getU32(&Offset), + SegmentLength = DE.getU32(&Offset), + FullSegmentSize = DE.getU32(&Offset); + + if (FullSegmentSize != + 12 + 8 * SegmentLength + + (HasColumnInformation ? 4 * SegmentLength : 0)) { + error(object_error::parse_failed); + return; + } + + uint32_t FilenameOffset; + { + DataExtractor SDE(CVFileIndexToStringOffsetTable, true, 4); + uint32_t OffsetInSDE = OffsetInIndex; + if (!SDE.isValidOffset(OffsetInSDE)) { + error(object_error::parse_failed); + return; + } + FilenameOffset = SDE.getU32(&OffsetInSDE); + } + + if (FilenameOffset == 0 || FilenameOffset + 1 >= CVStringTable.size() || + CVStringTable.data()[FilenameOffset - 1] != '\0') { + // Each string in an F3 subsection should be preceded by a null + // character. + error(object_error::parse_failed); + return; + } + + StringRef Filename(CVStringTable.data() + FilenameOffset); + ListScope S(W, "FilenameSegment"); + W.printString("Filename", Filename); + for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset); + ++J) { + // Then go the (PC, LineNumber) pairs. The line number is stored in the + // least significant 31 bits of the respective word in the table. + uint32_t PC = DE.getU32(&Offset), + LineNumber = DE.getU32(&Offset) & 0x7fffffff; + if (PC >= FunctionSize) { + error(object_error::parse_failed); + return; + } + char Buffer[32]; + format("+0x%X", PC).snprint(Buffer, 32); + W.printNumber(Buffer, LineNumber); + } + if (HasColumnInformation) { + for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset); + ++J) { + uint16_t ColStart = DE.getU16(&Offset); + W.printNumber("ColStart", ColStart); + uint16_t ColEnd = DE.getU16(&Offset); + W.printNumber("ColEnd", ColEnd); + } + } + } } } -void COFFDumper::printFileHeaders() { - const coff_file_header *Header = 0; - if (error(Obj->getHeader(Header))) +void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, + const SectionRef &Section, + uint32_t OffsetInSection) { + if (Subsection.size() == 0) { + error(object_error::parse_failed); return; + } + DataExtractor DE(Subsection, true, 4); + uint32_t Offset = 0; + + // Function-level subsections have "procedure start" and "procedure end" + // commands that should come in pairs and surround relevant info. + bool InFunctionScope = false; + while (DE.isValidOffset(Offset)) { + // Read subsection segments one by one. + uint16_t Size = DE.getU16(&Offset); + // The section size includes the size of the type identifier. + if (Size < 2 || !DE.isValidOffsetForDataOfSize(Offset, Size)) { + error(object_error::parse_failed); + return; + } + Size -= 2; + uint16_t Type = DE.getU16(&Offset); + switch (Type) { + case COFF::DEBUG_SYMBOL_TYPE_PROC_START: { + DictScope S(W, "ProcStart"); + if (InFunctionScope || Size < 36) { + error(object_error::parse_failed); + return; + } + InFunctionScope = true; + + // We're currently interested in a limited subset of fields in this + // segment, just ignore the rest of the fields for now. + uint8_t Unused[12]; + DE.getU8(&Offset, Unused, 12); + uint32_t CodeSize = DE.getU32(&Offset); + DE.getU8(&Offset, Unused, 12); + StringRef SectionName; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + Offset, SectionName)); + Offset += 4; + DE.getU8(&Offset, Unused, 3); + StringRef DisplayName = DE.getCStr(&Offset); + if (!DE.isValidOffset(Offset)) { + error(object_error::parse_failed); + return; + } + W.printString("DisplayName", DisplayName); + W.printString("Section", SectionName); + W.printHex("CodeSize", CodeSize); - time_t TDS = Header->TimeDateStamp; - char FormattedTime[20] = { }; - strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + break; + } + case COFF::DEBUG_SYMBOL_TYPE_PROC_END: { + W.startLine() << "ProcEnd\n"; + if (!InFunctionScope || Size > 0) { + error(object_error::parse_failed); + return; + } + InFunctionScope = false; + break; + } + default: { + if (opts::CodeViewSubsectionBytes) { + ListScope S(W, "Record"); + W.printHex("Size", Size); + W.printHex("Type", Type); + + StringRef Contents = DE.getData().substr(Offset, Size); + W.printBinaryBlock("Contents", Contents); + } - { - DictScope D(W, "ImageFileHeader"); - W.printEnum ("Machine", Header->Machine, - makeArrayRef(ImageFileMachineType)); - W.printNumber("SectionCount", Header->NumberOfSections); - W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp); - W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable); - W.printNumber("SymbolCount", Header->NumberOfSymbols); - W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader); - W.printFlags ("Characteristics", Header->Characteristics, - makeArrayRef(ImageFileCharacteristics)); + Offset += Size; + break; + } + } } + + if (InFunctionScope) + error(object_error::parse_failed); } void COFFDumper::printSections() { - error_code EC; - ListScope SectionsD(W, "Sections"); int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; - + for (const SectionRef &Sec : Obj->sections()) { ++SectionNumber; - const coff_section *Section = Obj->getCOFFSection(SecI); + const coff_section *Section = Obj->getCOFFSection(Sec); StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + error(Sec.getName(Name)); DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -593,33 +763,27 @@ void COFFDumper::printSections() { if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + for (const RelocationRef &Reloc : Sec.relocations()) + printRelocation(Sec, Reloc); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + for (const SymbolRef &Symbol : Obj->symbols()) { + if (!Sec.containsSymbol(Symbol)) continue; - printSymbol(SymI); + printSymbol(Symbol); } } - if (opts::SectionData) { + if (Name == ".debug$S" && opts::CodeView) + printCodeViewDebugInfo(Sec); + + if (opts::SectionData && + !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { StringRef Data; - if (error(SecI->getContents(Data))) break; + error(Sec.getContents(Data)); W.printBinaryBlock("SectionData", Data); } @@ -629,32 +793,21 @@ void COFFDumper::printSections() { void COFFDumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { + for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; - if (error(EC)) - break; - StringRef Name; - if (error(SecI->getName(Name))) - continue; + error(Section.getName(Name)); bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - + for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; W.indent(); PrintedGroup = true; } - printRelocation(SecI, RelI); + printRelocation(Section, Reloc); } if (PrintedGroup) { @@ -664,30 +817,30 @@ void COFFDumper::printRelocations() { } } -void COFFDumper::printRelocation(section_iterator SecI, - relocation_iterator RelI) { - uint64_t Offset; - uint64_t RelocType; +void COFFDumper::printRelocation(const SectionRef &Section, + const RelocationRef &Reloc) { + uint64_t Offset = Reloc.getOffset(); + uint64_t RelocType = Reloc.getType(); SmallString<32> RelocName; StringRef SymbolName; - StringRef Contents; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getType(RelocType))) return; - if (error(RelI->getTypeName(RelocName))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (error(Symbol->getName(SymbolName))) return; - if (error(SecI->getContents(Contents))) return; + Reloc.getTypeName(RelocName); + symbol_iterator Symbol = Reloc.getSymbol(); + if (Symbol != Obj->symbol_end()) { + ErrorOr SymbolNameOrErr = Symbol->getName(); + error(SymbolNameOrErr.getError()); + SymbolName = *SymbolNameOrErr; + } if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Offset); W.printNumber("Type", RelocName, RelocType); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printString("Symbol", SymbolName.empty() ? "-" : SymbolName); } else { raw_ostream& OS = W.startLine(); OS << W.hex(Offset) << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << (SymbolName.empty() ? "-" : SymbolName) << "\n"; } } @@ -695,26 +848,36 @@ void COFFDumper::printRelocation(section_iterator SecI, void COFFDumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); - } + for (const SymbolRef &Symbol : Obj->symbols()) + printSymbol(Symbol); } -void COFFDumper::printDynamicSymbols() { - ListScope Group(W, "DynamicSymbols"); +void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); } + +static ErrorOr +getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber, + const coff_section *Section) { + if (Section) { + StringRef SectionName; + if (std::error_code EC = Obj->getSectionName(Section, SectionName)) + return EC; + return SectionName; + } + if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) + return StringRef("IMAGE_SYM_DEBUG"); + if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE) + return StringRef("IMAGE_SYM_ABSOLUTE"); + if (SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED) + return StringRef("IMAGE_SYM_UNDEFINED"); + return StringRef(""); } -void COFFDumper::printSymbol(symbol_iterator SymI) { +void COFFDumper::printSymbol(const SymbolRef &Sym) { DictScope D(W, "Symbol"); - const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym); const coff_section *Section; - if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { + if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; W.flush(); return; @@ -725,49 +888,40 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { SymbolName = ""; StringRef SectionName = ""; - if (Section) - Obj->getSectionName(Section, SectionName); + ErrorOr Res = + getSectionName(Obj, Symbol.getSectionNumber(), Section); + if (Res) + SectionName = *Res; W.printString("Name", SymbolName); - W.printNumber("Value", Symbol->Value); - W.printNumber("Section", SectionName, Symbol->SectionNumber); - W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType)); - W.printEnum ("ComplexType", Symbol->getComplexType(), + W.printNumber("Value", Symbol.getValue()); + W.printNumber("Section", SectionName, Symbol.getSectionNumber()); + W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType)); + W.printEnum ("ComplexType", Symbol.getComplexType(), makeArrayRef(ImageSymDType)); - W.printEnum ("StorageClass", Symbol->StorageClass, + W.printEnum ("StorageClass", Symbol.getStorageClass(), makeArrayRef(ImageSymClass)); - W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); + W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols()); - for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { - if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && - Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && - Symbol->SectionNumber > 0) { + for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) { + if (Symbol.isFunctionDefinition()) { const coff_aux_function_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); W.printNumber("TotalSize", Aux->TotalSize); - W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); + W.printHex("PointerToLineNumber", Aux->PointerToLinenumber); W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); - W.printBinary("Unused", makeArrayRef(Aux->Unused)); - - } else if ( - Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber == 0 && - Symbol->Value == 0)) { - const coff_aux_weak_external_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) - break; - const coff_symbol *Linked; + } else if (Symbol.isAnyUndefined()) { + const coff_aux_weak_external *Aux; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); + + ErrorOr Linked = Obj->getSymbol(Aux->TagIndex); StringRef LinkedName; - error_code EC; - if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || - (EC = Obj->getSymbolName(Linked, LinkedName))) { + std::error_code EC = Linked.getError(); + if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) { LinkedName = ""; error(EC); } @@ -776,55 +930,65 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("Linked", LinkedName, Aux->TagIndex); W.printEnum ("Search", Aux->Characteristics, makeArrayRef(WeakExternalCharacteristics)); - W.printBinary("Unused", Aux->Unused); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { - const coff_aux_file_record *Aux; - if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) - break; + } else if (Symbol.isFileRecord()) { + const char *FileName; + error(getSymbolAuxData(Obj, Symbol, I, FileName)); DictScope AS(W, "AuxFileRecord"); - W.printString("FileName", StringRef(Aux->FileName)); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) { + StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() * + Obj->getSymbolTableEntrySize()); + W.printString("FileName", Name.rtrim(StringRef("\0", 1))); + break; + } else if (Symbol.isSectionDefinition()) { const coff_aux_section_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); + + int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); DictScope AS(W, "AuxSectionDef"); W.printNumber("Length", Aux->Length); W.printNumber("RelocationCount", Aux->NumberOfRelocations); W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); W.printHex("Checksum", Aux->CheckSum); - W.printNumber("Number", Aux->Number); + W.printNumber("Number", AuxNumber); W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); - W.printBinary("Unused", makeArrayRef(Aux->Unused)); if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { const coff_section *Assoc; - StringRef AssocName; - error_code EC; - if ((EC = Obj->getSection(Aux->Number, Assoc)) || - (EC = Obj->getSectionName(Assoc, AssocName))) { + StringRef AssocName = ""; + std::error_code EC = Obj->getSection(AuxNumber, Assoc); + ErrorOr Res = getSectionName(Obj, AuxNumber, Assoc); + if (Res) + AssocName = *Res; + if (!EC) + EC = Res.getError(); + if (EC) { AssocName = ""; error(EC); } - W.printNumber("AssocSection", AssocName, Aux->Number); + W.printNumber("AssocSection", AssocName, AuxNumber); } - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + } else if (Symbol.isCLRToken()) { const coff_aux_clr_token *Aux; - if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); + + ErrorOr ReferredSym = + Obj->getSymbol(Aux->SymbolTableIndex); + StringRef ReferredName; + std::error_code EC = ReferredSym.getError(); + if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) { + ReferredName = ""; + error(EC); + } DictScope AS(W, "AuxCLRToken"); W.printNumber("AuxType", Aux->AuxType); W.printNumber("Reserved", Aux->Reserved); - W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); - W.printBinary("Unused", Aux->Unused); + W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex); } else { W.startLine() << "\n"; @@ -833,192 +997,176 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { } void COFFDumper::printUnwindInfo() { - const coff_file_header *Header; - if (error(Obj->getHeader(Header))) - return; - ListScope D(W, "UnwindInformation"); - if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { - W.startLine() << "Unsupported image machine type " - "(currently only AMD64 is supported).\n"; - return; + switch (Obj->getMachine()) { + case COFF::IMAGE_FILE_MACHINE_AMD64: { + Win64EH::Dumper Dumper(W); + Win64EH::Dumper::SymbolResolver + Resolver = [](const object::coff_section *Section, uint64_t Offset, + SymbolRef &Symbol, void *user_data) -> std::error_code { + COFFDumper *Dumper = reinterpret_cast(user_data); + return Dumper->resolveSymbol(Section, Offset, Symbol); + }; + Win64EH::Dumper::Context Ctx(*Obj, Resolver, this); + Dumper.printData(Ctx); + break; + } + case COFF::IMAGE_FILE_MACHINE_ARMNT: { + ARM::WinEH::Decoder Decoder(W); + Decoder.dumpProcedureData(*Obj); + break; } + default: + W.printEnum("unsupported Image Machine", Obj->getMachine(), + makeArrayRef(ImageFileMachineType)); + break; + } +} - printX64UnwindInfo(); +void COFFDumper::printImportedSymbols( + iterator_range Range) { + for (const ImportedSymbolRef &I : Range) { + StringRef Sym; + error(I.getSymbolName(Sym)); + uint16_t Ordinal; + error(I.getOrdinal(Ordinal)); + W.printNumber("Symbol", Sym, Ordinal); + } } -void COFFDumper::printX64UnwindInfo() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; +void COFFDumper::printDelayImportedSymbols( + const DelayImportDirectoryEntryRef &I, + iterator_range Range) { + int Index = 0; + for (const ImportedSymbolRef &S : Range) { + DictScope Import(W, "Import"); + StringRef Sym; + error(S.getSymbolName(Sym)); + uint16_t Ordinal; + error(S.getOrdinal(Ordinal)); + W.printNumber("Symbol", Sym, Ordinal); + uint64_t Addr; + error(I.getImportAddress(Index++, Addr)); + W.printHex("Address", Addr); + } +} +void COFFDumper::printCOFFImports() { + // Regular imports + for (const ImportDirectoryEntryRef &I : Obj->import_directories()) { + DictScope Import(W, "Import"); StringRef Name; - if (error(SecI->getName(Name))) - continue; - if (Name != ".pdata" && !Name.startswith(".pdata$")) - continue; + error(I.getName(Name)); + W.printString("Name", Name); + uint32_t Addr; + error(I.getImportLookupTableRVA(Addr)); + W.printHex("ImportLookupTableRVA", Addr); + error(I.getImportAddressTableRVA(Addr)); + W.printHex("ImportAddressTableRVA", Addr); + printImportedSymbols(I.imported_symbols()); + } - const coff_section *PData = Obj->getCOFFSection(SecI); + // Delay imports + for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) { + DictScope Import(W, "DelayImport"); + StringRef Name; + error(I.getName(Name)); + W.printString("Name", Name); + const delay_import_directory_table_entry *Table; + error(I.getDelayImportTable(Table)); + W.printHex("Attributes", Table->Attributes); + W.printHex("ModuleHandle", Table->ModuleHandle); + W.printHex("ImportAddressTable", Table->DelayImportAddressTable); + W.printHex("ImportNameTable", Table->DelayImportNameTable); + W.printHex("BoundDelayImportTable", Table->BoundDelayImportTable); + W.printHex("UnloadDelayImportTable", Table->UnloadDelayImportTable); + printDelayImportedSymbols(I, I.imported_symbols()); + } +} - ArrayRef Contents; - if (error(Obj->getSectionContents(PData, Contents)) || - Contents.empty()) - continue; +void COFFDumper::printCOFFExports() { + for (const ExportDirectoryEntryRef &E : Obj->export_directories()) { + DictScope Export(W, "Export"); - ArrayRef RFs( - reinterpret_cast(Contents.data()), - Contents.size() / sizeof(RuntimeFunction)); + StringRef Name; + uint32_t Ordinal, RVA; - for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { - const uint64_t OffsetInSection = std::distance(RFs.begin(), I) - * sizeof(RuntimeFunction); + error(E.getSymbolName(Name)); + error(E.getOrdinal(Ordinal)); + error(E.getExportRVA(RVA)); - printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); - } + W.printNumber("Ordinal", Ordinal); + W.printString("Name", Name); + W.printHex("RVA", RVA); } } -void COFFDumper::printRuntimeFunction( - const RuntimeFunction& RTF, - uint64_t OffsetInSection, - const std::vector &Rels) { - - DictScope D(W, "RuntimeFunction"); - W.printString("StartAddress", - formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); - W.printString("EndAddress", - formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); - W.printString("UnwindInfoAddress", - formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); - - const coff_section* XData = 0; - uint64_t UnwindInfoOffset = 0; - if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) - return; - - ArrayRef XContents; - if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) - return; - - UnwindInfoOffset += RTF.UnwindInfoOffset; - if (UnwindInfoOffset > XContents.size()) - return; +void COFFDumper::printCOFFDirectives() { + for (const SectionRef &Section : Obj->sections()) { + StringRef Contents; + StringRef Name; - const Win64EH::UnwindInfo *UI = - reinterpret_cast( - XContents.data() + UnwindInfoOffset); + error(Section.getName(Name)); + if (Name != ".drectve") + continue; - printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); -} + error(Section.getContents(Contents)); -void COFFDumper::printUnwindInfo( - const Win64EH::UnwindInfo& UI, - uint64_t OffsetInSection, - const std::vector &Rels) { - DictScope D(W, "UnwindInfo"); - W.printNumber("Version", UI.getVersion()); - W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); - W.printNumber("PrologSize", UI.PrologSize); - if (UI.getFrameRegister() != 0) { - W.printEnum("FrameRegister", UI.getFrameRegister(), - makeArrayRef(UnwindOpInfo)); - W.printHex("FrameOffset", UI.getFrameOffset()); - } else { - W.printString("FrameRegister", StringRef("-")); - W.printString("FrameOffset", StringRef("-")); + W.printString("Directive(s)", Contents); } +} - W.printNumber("UnwindCodeCount", UI.NumCodes); - { - ListScope CodesD(W, "UnwindCodes"); - ArrayRef UCs(&UI.UnwindCodes[0], UI.NumCodes); - for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { - unsigned UsedSlots = getNumUsedSlots(*I); - if (UsedSlots > UCs.size()) { - errs() << "Corrupt unwind data"; - return; - } - printUnwindCode(UI, ArrayRef(I, E)); - I += UsedSlots - 1; - } +static StringRef getBaseRelocTypeName(uint8_t Type) { + switch (Type) { + case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE"; + case COFF::IMAGE_REL_BASED_HIGH: return "HIGH"; + case COFF::IMAGE_REL_BASED_LOW: return "LOW"; + case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW"; + case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ"; + case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)"; + case COFF::IMAGE_REL_BASED_DIR64: return "DIR64"; + default: return "unknown (" + llvm::utostr(Type) + ")"; } +} - uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); - if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { - W.printString("Handler", formatSymbol(Rels, LSDAOffset, - UI.getLanguageSpecificHandlerOffset())); - } else if (UI.getFlags() & UNW_ChainInfo) { - const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); - if (Chained) { - DictScope D(W, "Chained"); - W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, - Chained->StartAddress)); - W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, - Chained->EndAddress)); - W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, - Chained->UnwindInfoOffset)); - } +void COFFDumper::printCOFFBaseReloc() { + ListScope D(W, "BaseReloc"); + for (const BaseRelocRef &I : Obj->base_relocs()) { + uint8_t Type; + uint32_t RVA; + error(I.getRVA(RVA)); + error(I.getType(Type)); + DictScope Import(W, "Entry"); + W.printString("Type", getBaseRelocTypeName(Type)); + W.printHex("Address", RVA); } } -// Prints one unwind code. Because an unwind code can occupy up to 3 slots in -// the unwind codes array, this function requires that the correct number of -// slots is provided. -void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, - ArrayRef UCs) { - assert(UCs.size() >= getNumUsedSlots(UCs[0])); - - W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) - << getUnwindCodeTypeName(UCs[0].getUnwindOp()); - - uint32_t AllocSize = 0; - - switch (UCs[0].getUnwindOp()) { - case UOP_PushNonVol: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); - break; - - case UOP_AllocLarge: - if (UCs[0].getOpInfo() == 0) { - AllocSize = UCs[1].FrameOffset * 8; - } else { - AllocSize = getLargeSlotValue(UCs); - } - outs() << " size=" << AllocSize; - break; - case UOP_AllocSmall: - outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); - break; - case UOP_SetFPReg: - if (UI.getFrameRegister() == 0) { - outs() << " reg="; - } else { - outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) - << format(", offset=0x%X", UI.getFrameOffset() * 16); +void COFFDumper::printStackMap() const { + object::SectionRef StackMapSection; + for (auto Sec : Obj->sections()) { + StringRef Name; + Sec.getName(Name); + if (Name == ".llvm_stackmaps") { + StackMapSection = Sec; + break; } - break; - case UOP_SaveNonVol: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) - << format(", offset=0x%X", UCs[1].FrameOffset * 8); - break; - case UOP_SaveNonVolBig: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) - << format(", offset=0x%X", getLargeSlotValue(UCs)); - break; - case UOP_SaveXMM128: - outs() << " reg=XMM" << static_cast(UCs[0].getOpInfo()) - << format(", offset=0x%X", UCs[1].FrameOffset * 16); - break; - case UOP_SaveXMM128Big: - outs() << " reg=XMM" << static_cast(UCs[0].getOpInfo()) - << format(", offset=0x%X", getLargeSlotValue(UCs)); - break; - case UOP_PushMachFrame: - outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); - break; } - outs() << "\n"; + if (StackMapSection == object::SectionRef()) + return; + + StringRef StackMapContents; + StackMapSection.getContents(StackMapContents); + ArrayRef StackMapContentsArray( + reinterpret_cast(StackMapContents.data()), + StackMapContents.size()); + + if (Obj->isLittleEndian()) + prettyPrintStackMap( + llvm::outs(), + StackMapV1Parser(StackMapContentsArray)); + else + prettyPrintStackMap(llvm::outs(), + StackMapV1Parser(StackMapContentsArray)); }