diff options
author | Rafael Auler <rafaelauler@fb.com> | 2018-03-08 00:46:53 +0000 |
---|---|---|
committer | Rafael Auler <rafaelauler@fb.com> | 2018-03-08 00:46:53 +0000 |
commit | 86fb7bf2bca553bc7137e85d0ac0c7a809e16c80 (patch) | |
tree | 6af7787dea9d397d6c399d683cbeff5d2dbd17db /llvm/tools/llvm-readobj | |
parent | a4259cd3a6268d6b7e27acd45fd6f114e2ac9ac2 (diff) | |
download | bcm5719-llvm-86fb7bf2bca553bc7137e85d0ac0c7a809e16c80.tar.gz bcm5719-llvm-86fb7bf2bca553bc7137e85d0ac0c7a809e16c80.zip |
Reland "[DebugInfo] Support DWARF expressions in eh_frame"
Summary:
Original change was D43313 (r326932) and reverted by r326953 because it
broke an LLD test and a windows build. The LLD test was already fixed in
lld commit r326944 (thanks maskray). This is the original change with
the windows build fixed.
llvm-svn: 326970
Diffstat (limited to 'llvm/tools/llvm-readobj')
-rw-r--r-- | llvm/tools/llvm-readobj/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h | 244 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 6 |
3 files changed, 251 insertions, 0 deletions
diff --git a/llvm/tools/llvm-readobj/CMakeLists.txt b/llvm/tools/llvm-readobj/CMakeLists.txt index dafc9e10cfa..b0550f34012 100644 --- a/llvm/tools/llvm-readobj/CMakeLists.txt +++ b/llvm/tools/llvm-readobj/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS DebugInfoCodeView + DebugInfoDWARF Object BinaryFormat Support diff --git a/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h new file mode 100644 index 00000000000..6f1e35ced94 --- /dev/null +++ b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h @@ -0,0 +1,244 @@ +//===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H +#define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H + +#include "Error.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/type_traits.h" + +namespace llvm { +namespace DwarfCFIEH { + +template <typename ELFT> +class PrinterContext { + ScopedPrinter &W; + const object::ELFFile<ELFT> *Obj; + + void printEHFrameHdr(uint64_t Offset, uint64_t Address, uint64_t Size) const; + + void printEHFrame(const typename ELFT::Shdr *EHFrameShdr) const; + +public: + PrinterContext(ScopedPrinter &W, const object::ELFFile<ELFT> *Obj) + : W(W), Obj(Obj) {} + + void printUnwindInformation() const; +}; + +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, + uint64_t Addr) { + auto Sections = Obj->sections(); + if (Error E = Sections.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Shdr : *Sections) + if (Shdr.sh_addr == Addr) + return &Shdr; + return nullptr; +} + +template <typename ELFT> +void PrinterContext<ELFT>::printUnwindInformation() const { + const typename ELFT::Phdr *EHFramePhdr = nullptr; + + auto PHs = Obj->program_headers(); + if (Error E = PHs.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Phdr : *PHs) { + if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { + EHFramePhdr = &Phdr; + if (Phdr.p_memsz != Phdr.p_filesz) + reportError("p_memsz does not match p_filesz for GNU_EH_FRAME"); + break; + } + } + + if (EHFramePhdr) + printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr, + EHFramePhdr->p_memsz); + + auto Sections = Obj->sections(); + if (Error E = Sections.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Shdr : *Sections) { + auto SectionName = Obj->getSectionName(&Shdr); + if (Error E = SectionName.takeError()) + reportError(toString(std::move(E))); + + if (*SectionName == ".eh_frame") + printEHFrame(&Shdr); + } +} + +template <typename ELFT> +void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, + uint64_t EHFrameHdrAddress, + uint64_t EHFrameHdrSize) const { + ListScope L(W, "EH_FRAME Header"); + W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); + W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset); + W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize); + + const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress); + if (EHFrameHdrShdr) { + auto SectionName = Obj->getSectionName(EHFrameHdrShdr); + if (Error E = SectionName.takeError()) + reportError(toString(std::move(E))); + + W.printString("Corresponding Section", *SectionName); + } + + DataExtractor DE( + StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset, + EHFrameHdrSize), + ELFT::TargetEndianness == support::endianness::little, + ELFT::Is64Bits ? 8 : 4); + + DictScope D(W, "Header"); + uint32_t Offset = 0; + + auto Version = DE.getU8(&Offset); + W.printNumber("version", Version); + if (Version != 1) + reportError("only version 1 of .eh_frame_hdr is supported"); + + uint64_t EHFramePtrEnc = DE.getU8(&Offset); + W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); + if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) + reportError("unexpected encoding eh_frame_ptr_enc"); + + uint64_t FDECountEnc = DE.getU8(&Offset); + W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); + if (FDECountEnc != dwarf::DW_EH_PE_udata4) + reportError("unexpected encoding fde_count_enc"); + + uint64_t TableEnc = DE.getU8(&Offset); + W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); + if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) + reportError("unexpected encoding table_enc"); + + auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; + W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); + + auto FDECount = DE.getUnsigned(&Offset, 4); + W.printNumber("fde_count", FDECount); + + unsigned NumEntries = 0; + uint64_t PrevPC = 0; + while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) { + DictScope D(W, std::string("entry ") + std::to_string(NumEntries)); + + auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; + W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC); + auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; + W.startLine() << format("address: 0x%" PRIx64 "\n", Address); + + if (InitialPC < PrevPC) + reportError("initial_location is out of order"); + + PrevPC = InitialPC; + ++NumEntries; + } +} + +template <typename ELFT> +void PrinterContext<ELFT>::printEHFrame( + const typename ELFT::Shdr *EHFrameShdr) const { + uint64_t Address = EHFrameShdr->sh_addr; + uint64_t ShOffset = EHFrameShdr->sh_offset; + W.startLine() << format(".eh_frame section at offset 0x%" PRIx64 + " address 0x%" PRIx64 ":\n", + ShOffset, Address); + W.indent(); + + auto Result = Obj->getSectionContents(EHFrameShdr); + if (Error E = Result.takeError()) + reportError(toString(std::move(E))); + + auto Contents = Result.get(); + DWARFDataExtractor DE( + StringRef(reinterpret_cast<const char *>(Contents.data()), + Contents.size()), + ELFT::TargetEndianness == support::endianness::little, + ELFT::Is64Bits ? 8 : 4); + DWARFDebugFrame EHFrame(/*IsEH=*/true, /*EHFrameAddress=*/Address); + EHFrame.parse(DE); + + for (const auto &Entry : EHFrame) { + if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) { + W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", + Address + CIE->getOffset(), + CIE->getLength()); + W.indent(); + + W.printNumber("version", CIE->getVersion()); + W.printString("augmentation", CIE->getAugmentationString()); + W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); + W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); + W.printNumber("return_address_register", CIE->getReturnAddressRegister()); + + W.getOStream() << "\n"; + W.startLine() << "Program:\n"; + W.indent(); + CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); + W.unindent(); + + W.unindent(); + W.getOStream() << "\n"; + + } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) { + W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 + " cie=[0x%" PRIx64 "]\n", + Address + FDE->getOffset(), + FDE->getLength(), + Address + FDE->getLinkedCIE()->getOffset()); + W.indent(); + + W.startLine() << format("initial_location: 0x%" PRIx64 "\n", + FDE->getInitialLocation()); + W.startLine() + << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", + FDE->getAddressRange(), + FDE->getInitialLocation() + FDE->getAddressRange()); + + W.getOStream() << "\n"; + W.startLine() << "Program:\n"; + W.indent(); + FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); + W.unindent(); + + W.unindent(); + W.getOStream() << "\n"; + } else { + llvm_unreachable("unexpected DWARF frame kind"); + } + } + + W.unindent(); +} + +} +} + +#endif diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 36cda459225..6b6582b7566 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "ARMEHABIPrinter.h" +#include "DwarfCFIEHPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" @@ -1808,6 +1809,11 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { template<class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { + const unsigned Machine = Obj->getHeader()->e_machine; + if (Machine == EM_386 || Machine == EM_X86_64) { + DwarfCFIEH::PrinterContext<ELFT> Ctx(W, Obj); + return Ctx.printUnwindInformation(); + } W.startLine() << "UnwindInfo not implemented.\n"; } |