summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-readobj
diff options
context:
space:
mode:
authorRafael Auler <rafaelauler@fb.com>2018-03-08 00:46:53 +0000
committerRafael Auler <rafaelauler@fb.com>2018-03-08 00:46:53 +0000
commit86fb7bf2bca553bc7137e85d0ac0c7a809e16c80 (patch)
tree6af7787dea9d397d6c399d683cbeff5d2dbd17db /llvm/tools/llvm-readobj
parenta4259cd3a6268d6b7e27acd45fd6f114e2ac9ac2 (diff)
downloadbcm5719-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.txt1
-rw-r--r--llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h244
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp6
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";
}
OpenPOWER on IntegriCloud