[llvm] r326932 - [DebugInfo] Support DWARF expressions in eh_frame

Rafael Auler via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 7 11:19:51 PST 2018


Author: rafauler
Date: Wed Mar  7 11:19:51 2018
New Revision: 326932

URL: http://llvm.org/viewvc/llvm-project?rev=326932&view=rev
Log:
[DebugInfo] Support DWARF expressions in eh_frame

This patch enhances DWARFDebugFrame with the capability of parsing and
printing DWARF expressions in CFI instructions. It also makes FDEs and
CIEs accessible to lib users, so they can process them in client tools
that rely on LLVM. To make it self-contained with a test case, it
teaches llvm-readobj to be able to dump EH frames and checks they are
correct in a unit test. The llvm-readobj code is Maksim Panchenko's work
(maksfb).

Reviewers: JDevlieghere, espindola

Reviewed By: JDevlieghere

Differential Revision: https://reviews.llvm.org/D43313

Added:
    llvm/trunk/test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml
    llvm/trunk/test/tools/llvm-readobj/unwind.test
    llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h
Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h
    llvm/trunk/include/llvm/Support/ScopedPrinter.h
    llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp
    llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
    llvm/trunk/tools/llvm-readobj/CMakeLists.txt
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h Wed Mar  7 11:19:51 2018
@@ -44,6 +44,13 @@ public:
   uint64_t getRelocatedAddress(uint32_t *Off, uint64_t *SecIx = nullptr) const {
     return getRelocatedValue(getAddressSize(), Off, SecIx);
   }
+
+  /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
+  /// There is a DWARF encoding that uses a PC-relative adjustment.
+  /// For these values, \p AbsPosOffset is used to fix them, which should
+  /// reflect the absolute address of this pointer.
+  Optional<uint64_t> getEncodedPointer(uint32_t *Offset, uint8_t Encoding,
+                                       uint64_t AbsPosOffset = 0) const;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h Wed Mar  7 11:19:51 2018
@@ -10,40 +10,290 @@
 #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
 #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
 
-#include "llvm/Support/DataExtractor.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/Support/Error.h"
 #include <memory>
 #include <vector>
 
 namespace llvm {
 
-class FrameEntry;
 class raw_ostream;
 
-/// \brief A parsed .debug_frame or .eh_frame section
-///
+namespace dwarf {
+
+/// Represent a sequence of Call Frame Information instructions that, when read
+/// in order, construct a table mapping PC to frame state. This can also be
+/// referred to as "CFI rules" in DWARF literature to avoid confusion with
+/// computer programs in the broader sense, and in this context each instruction
+/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
+/// manual, "6.4.1 Structure of Call Frame Information".
+class CFIProgram {
+public:
+  typedef SmallVector<uint64_t, 2> Operands;
+
+  /// An instruction consists of a DWARF CFI opcode and an optional sequence of
+  /// operands. If it refers to an expression, then this expression has its own
+  /// sequence of operations and operands handled separately by DWARFExpression.
+  struct Instruction {
+    Instruction(uint8_t Opcode) : Opcode(Opcode) {}
+
+    uint8_t Opcode;
+    Operands Ops;
+    // Associated DWARF expression in case this instruction refers to one
+    Optional<DWARFExpression> Expression;
+  };
+
+  using InstrList = std::vector<Instruction>;
+  using iterator = InstrList::iterator;
+  using const_iterator = InstrList::const_iterator;
+
+  iterator begin() { return Instructions.begin(); }
+  const_iterator begin() const { return Instructions.begin(); }
+  iterator end() { return Instructions.end(); }
+  const_iterator end() const { return Instructions.end(); }
+
+  unsigned size() const { return (unsigned)Instructions.size(); }
+  bool empty() const { return Instructions.empty(); }
+
+  CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor)
+      : CodeAlignmentFactor(CodeAlignmentFactor),
+        DataAlignmentFactor(DataAlignmentFactor) {}
+
+  /// Parse and store a sequence of CFI instructions from Data,
+  /// starting at *Offset and ending at EndOffset. *Offset is updated
+  /// to EndOffset upon successful parsing, or indicates the offset
+  /// where a problem occurred in case an error is returned.
+  Error parse(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset);
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+            unsigned IndentLevel = 1) const;
+
+private:
+  std::vector<Instruction> Instructions;
+  const uint64_t CodeAlignmentFactor;
+  const int64_t DataAlignmentFactor;
+
+  /// Convenience method to add a new instruction with the given opcode.
+  void addInstruction(uint8_t Opcode) {
+    Instructions.push_back(Instruction(Opcode));
+  }
+
+  /// Add a new single-operand instruction.
+  void addInstruction(uint8_t Opcode, uint64_t Operand1) {
+    Instructions.push_back(Instruction(Opcode));
+    Instructions.back().Ops.push_back(Operand1);
+  }
+
+  /// Add a new instruction that has two operands.
+  void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
+    Instructions.push_back(Instruction(Opcode));
+    Instructions.back().Ops.push_back(Operand1);
+    Instructions.back().Ops.push_back(Operand2);
+  }
+
+  /// Types of operands to CFI instructions
+  /// In DWARF, this type is implicitly tied to a CFI instruction opcode and
+  /// thus this type doesn't need to be explictly written to the file (this is
+  /// not a DWARF encoding). The relationship of instrs to operand types can
+  /// be obtained from getOperandTypes() and is only used to simplify
+  /// instruction printing.
+  enum OperandType {
+    OT_Unset,
+    OT_None,
+    OT_Address,
+    OT_Offset,
+    OT_FactoredCodeOffset,
+    OT_SignedFactDataOffset,
+    OT_UnsignedFactDataOffset,
+    OT_Register,
+    OT_Expression
+  };
+
+  /// Retrieve the array describing the types of operands according to the enum
+  /// above. This is indexed by opcode.
+  static ArrayRef<OperandType[2]> getOperandTypes();
+
+  /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+  void printOperand(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+                    const Instruction &Instr, unsigned OperandIdx,
+                    uint64_t Operand) const;
+};
+
+/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
+/// FDE.
+class FrameEntry {
+public:
+  enum FrameKind { FK_CIE, FK_FDE };
+
+  FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign,
+             int64_t DataAlign)
+      : Kind(K), Offset(Offset), Length(Length), CFIs(CodeAlign, DataAlign) {}
+
+  virtual ~FrameEntry() {}
+
+  FrameKind getKind() const { return Kind; }
+  uint64_t getOffset() const { return Offset; }
+  uint64_t getLength() const { return Length; }
+  const CFIProgram &cfis() const { return CFIs; }
+  CFIProgram &cfis() { return CFIs; }
+
+  /// Dump the instructions in this CFI fragment
+  virtual void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+                    bool IsEH) const = 0;
+
+protected:
+  const FrameKind Kind;
+
+  /// Offset of this entry in the section.
+  const uint64_t Offset;
+
+  /// Entry length as specified in DWARF.
+  const uint64_t Length;
+
+  CFIProgram CFIs;
+};
+
+/// DWARF Common Information Entry (CIE)
+class CIE : public FrameEntry {
+public:
+  // CIEs (and FDEs) are simply container classes, so the only sensible way to
+  // create them is by providing the full parsed contents in the constructor.
+  CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
+      SmallString<8> Augmentation, uint8_t AddressSize,
+      uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
+      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
+      SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
+      uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
+      Optional<uint32_t> PersonalityEnc)
+      : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor,
+                   DataAlignmentFactor),
+        Version(Version), Augmentation(std::move(Augmentation)),
+        AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
+        CodeAlignmentFactor(CodeAlignmentFactor),
+        DataAlignmentFactor(DataAlignmentFactor),
+        ReturnAddressRegister(ReturnAddressRegister),
+        AugmentationData(std::move(AugmentationData)),
+        FDEPointerEncoding(FDEPointerEncoding),
+        LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality),
+        PersonalityEnc(PersonalityEnc) {}
+
+  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; }
+
+  StringRef getAugmentationString() const { return Augmentation; }
+  uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
+  int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
+  uint8_t getVersion() const { return Version; }
+  uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; }
+  Optional<uint64_t> getPersonalityAddress() const { return Personality; }
+  Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; }
+
+  uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; }
+
+  uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; }
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            bool IsEH) const override;
+
+private:
+  /// The following fields are defined in section 6.4.1 of the DWARF standard v4
+  const uint8_t Version;
+  const SmallString<8> Augmentation;
+  const uint8_t AddressSize;
+  const uint8_t SegmentDescriptorSize;
+  const uint64_t CodeAlignmentFactor;
+  const int64_t DataAlignmentFactor;
+  const uint64_t ReturnAddressRegister;
+
+  // The following are used when the CIE represents an EH frame entry.
+  const SmallString<8> AugmentationData;
+  const uint32_t FDEPointerEncoding;
+  const uint32_t LSDAPointerEncoding;
+  const Optional<uint64_t> Personality;
+  const Optional<uint32_t> PersonalityEnc;
+};
+
+/// DWARF Frame Description Entry (FDE)
+class FDE : public FrameEntry {
+public:
+  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
+  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
+  // is obtained lazily once it's actually required.
+  FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
+      uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
+      Optional<uint64_t> LSDAAddress)
+      : FrameEntry(FK_FDE, Offset, Length,
+                   Cie ? Cie->getCodeAlignmentFactor() : 0,
+                   Cie ? Cie->getDataAlignmentFactor() : 0),
+        LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation),
+        AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}
+
+  ~FDE() override = default;
+
+  const CIE *getLinkedCIE() const { return LinkedCIE; }
+  uint64_t getInitialLocation() const { return InitialLocation; }
+  uint64_t getAddressRange() const { return AddressRange; }
+  Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; }
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            bool IsEH) const override;
+
+  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; }
+
+private:
+  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
+  const uint64_t LinkedCIEOffset;
+  const uint64_t InitialLocation;
+  const uint64_t AddressRange;
+  const CIE *LinkedCIE;
+  const Optional<uint64_t> LSDAAddress;
+};
+
+} // end namespace dwarf
+
+/// A parsed .debug_frame or .eh_frame section
 class DWARFDebugFrame {
   // True if this is parsing an eh_frame section.
-  bool IsEH;
+  const bool IsEH;
+  // Not zero for sane pointer values coming out of eh_frame
+  const uint64_t EHFrameAddress;
+
+  std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries;
+  using iterator = pointee_iterator<decltype(Entries)::const_iterator>;
+
+  /// Return the entry at the given offset or nullptr.
+  dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const;
 
 public:
-  DWARFDebugFrame(bool IsEH);
+  // If IsEH is true, assume it is a .eh_frame section. Otherwise,
+  // it is a .debug_frame section. EHFrameAddress should be different
+  // than zero for correct parsing of .eh_frame addresses when they
+  // use a PC-relative encoding.
+  DWARFDebugFrame(bool IsEH = false, uint64_t EHFrameAddress = 0);
   ~DWARFDebugFrame();
 
   /// Dump the section data into the given stream.
-  void dump(raw_ostream &OS, Optional<uint64_t> Offset) const;
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            Optional<uint64_t> Offset) const;
 
-  /// \brief Parse the section from raw data.
-  /// data is assumed to be pointing to the beginning of the section.
-  void parse(DataExtractor Data);
+  /// Parse the section from raw data. \p Data is assumed to contain the whole
+  /// frame section contents to be parsed.
+  void parse(DWARFDataExtractor Data);
 
   /// Return whether the section has any entries.
   bool empty() const { return Entries.empty(); }
 
-  /// Return the entry at the given offset or nullptr.
-  FrameEntry *getEntryAtOffset(uint64_t Offset) const;
+  /// DWARF Frame entries accessors
+  iterator begin() const { return Entries.begin(); }
+  iterator end() const { return Entries.end(); }
+  iterator_range<iterator> entries() const {
+    return iterator_range<iterator>(Entries.begin(), Entries.end());
+  }
 
-private:
-  std::vector<std::unique_ptr<FrameEntry>> Entries;
+  uint64_t getEHFrameAddress() const { return EHFrameAddress; }
 };
 
 } // end namespace llvm

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h Wed Mar  7 11:19:51 2018
@@ -93,12 +93,13 @@ public:
 
   /// An iterator to go through the expression operations.
   class iterator
-      : public iterator_facade_base<iterator, std::forward_iterator_tag, Operation> {
+      : public iterator_facade_base<iterator, std::forward_iterator_tag,
+                                    Operation> {
     friend class DWARFExpression;
-    DWARFExpression *Expr;
+    const DWARFExpression *Expr;
     uint32_t Offset;
     Operation Op;
-    iterator(DWARFExpression *Expr, uint32_t Offset)
+    iterator(const DWARFExpression *Expr, uint32_t Offset)
         : Expr(Expr), Offset(Offset) {
       Op.Error =
           Offset >= Expr->Data.getData().size() ||
@@ -127,10 +128,11 @@ public:
     assert(AddressSize == 8 || AddressSize == 4);
   }
 
-  iterator begin() { return iterator(this, 0); }
-  iterator end() { return iterator(this, Data.getData().size()); }
+  iterator begin() const { return iterator(this, 0); }
+  iterator end() const { return iterator(this, Data.getData().size()); }
 
-  void print(raw_ostream &OS, const MCRegisterInfo *RegInfo);
+  void print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
+             bool IsEH = false) const;
 
 private:
   DataExtractor Data;

Modified: llvm/trunk/include/llvm/Support/ScopedPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ScopedPrinter.h?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ScopedPrinter.h (original)
+++ llvm/trunk/include/llvm/Support/ScopedPrinter.h Wed Mar  7 11:19:51 2018
@@ -80,6 +80,8 @@ public:
 
   void resetIndent() { IndentLevel = 0; }
 
+  int getIndentLevel() { return IndentLevel; }
+
   void setPrefix(StringRef P) { Prefix = P; }
 
   void printIndent() {

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Wed Mar  7 11:19:51 2018
@@ -349,11 +349,11 @@ void DWARFContext::dump(
 
   if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
                  DObj->getDebugFrameSection()))
-    getDebugFrame()->dump(OS, DumpOffset);
+    getDebugFrame()->dump(OS, getRegisterInfo(), DumpOffset);
 
   if (shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
                  DObj->getEHFrameSection()))
-    getEHFrame()->dump(OS, DumpOffset);
+    getEHFrame()->dump(OS, getRegisterInfo(), DumpOffset);
 
   if (DumpType & DIDT_DebugMacro) {
     if (Explicit || !getDebugMacro()->empty()) {
@@ -712,8 +712,8 @@ const DWARFDebugFrame *DWARFContext::get
   // provides this information). This problem is fixed in DWARFv4
   // See this dwarf-discuss discussion for more details:
   // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
-  DataExtractor debugFrameData(DObj->getDebugFrameSection(), isLittleEndian(),
-                               DObj->getAddressSize());
+  DWARFDataExtractor debugFrameData(DObj->getDebugFrameSection(),
+                                    isLittleEndian(), DObj->getAddressSize());
   DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
   DebugFrame->parse(debugFrameData);
   return DebugFrame.get();
@@ -723,8 +723,8 @@ const DWARFDebugFrame *DWARFContext::get
   if (EHFrame)
     return EHFrame.get();
 
-  DataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
-                               DObj->getAddressSize());
+  DWARFDataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
+                                    DObj->getAddressSize());
   DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
   DebugFrame->parse(debugFrameData);
   return DebugFrame.get();

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp Wed Mar  7 11:19:51 2018
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 
 using namespace llvm;
@@ -25,3 +26,71 @@ uint64_t DWARFDataExtractor::getRelocate
     *SecNdx = Rel->SectionIndex;
   return getUnsigned(Off, Size) + Rel->Value;
 }
+
+Optional<uint64_t>
+DWARFDataExtractor::getEncodedPointer(uint32_t *Offset, uint8_t Encoding,
+                                      uint64_t PCRelOffset) const {
+  if (Encoding == dwarf::DW_EH_PE_omit)
+    return None;
+
+  uint64_t Result = 0;
+  uint32_t OldOffset = *Offset;
+  // First get value
+  switch (Encoding & 0x0F) {
+  case dwarf::DW_EH_PE_absptr:
+    switch (getAddressSize()) {
+    case 2:
+    case 4:
+    case 8:
+      Result = getUnsigned(Offset, getAddressSize());
+      break;
+    default:
+      return None;
+    }
+    break;
+  case dwarf::DW_EH_PE_uleb128:
+    Result = getULEB128(Offset);
+    break;
+  case dwarf::DW_EH_PE_sleb128:
+    Result = getSLEB128(Offset);
+    break;
+  case dwarf::DW_EH_PE_udata2:
+    Result = getUnsigned(Offset, 2);
+    break;
+  case dwarf::DW_EH_PE_udata4:
+    Result = getUnsigned(Offset, 4);
+    break;
+  case dwarf::DW_EH_PE_udata8:
+    Result = getUnsigned(Offset, 8);
+    break;
+  case dwarf::DW_EH_PE_sdata2:
+    Result = getSigned(Offset, 2);
+    break;
+  case dwarf::DW_EH_PE_sdata4:
+    Result = getSigned(Offset, 4);
+    break;
+  case dwarf::DW_EH_PE_sdata8:
+    Result = getSigned(Offset, 8);
+    break;
+  default:
+    return None;
+  }
+  // Then add relative offset, if required
+  switch (Encoding & 0x70) {
+  case dwarf::DW_EH_PE_absptr:
+    // do nothing
+    break;
+  case dwarf::DW_EH_PE_pcrel:
+    Result += PCRelOffset;
+    break;
+  case dwarf::DW_EH_PE_datarel:
+  case dwarf::DW_EH_PE_textrel:
+  case dwarf::DW_EH_PE_funcrel:
+  case dwarf::DW_EH_PE_aligned:
+  default:
+    *Offset = OldOffset;
+    return None;
+  }
+
+  return Result;
+}

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp Wed Mar  7 11:19:51 2018
@@ -8,10 +8,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
@@ -31,87 +29,13 @@
 using namespace llvm;
 using namespace dwarf;
 
-/// \brief Abstract frame entry defining the common interface concrete
-/// entries implement.
-class llvm::FrameEntry {
-public:
-  enum FrameKind {FK_CIE, FK_FDE};
-
-  FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length)
-      : Kind(K), Offset(Offset), Length(Length) {}
-
-  virtual ~FrameEntry() = default;
-
-  FrameKind getKind() const { return Kind; }
-  virtual uint64_t getOffset() const { return Offset; }
-
-  /// Parse and store a sequence of CFI instructions from Data,
-  /// starting at *Offset and ending at EndOffset. If everything
-  /// goes well, *Offset should be equal to EndOffset when this method
-  /// returns. Otherwise, an error occurred.
-  virtual void parseInstructions(DataExtractor Data, uint32_t *Offset,
-                                 uint32_t EndOffset);
-
-  /// Dump the entry header to the given output stream.
-  virtual void dumpHeader(raw_ostream &OS) const = 0;
-
-  /// Dump the entry's instructions to the given output stream.
-  virtual void dumpInstructions(raw_ostream &OS) const;
-
-  /// Dump the entire entry to the given output stream.
-  void dump(raw_ostream &OS) const {
-    dumpHeader(OS);
-    dumpInstructions(OS);
-    OS << "\n";
-  }
-
-protected:
-  const FrameKind Kind;
-
-  /// \brief Offset of this entry in the section.
-  uint64_t Offset;
-
-  /// \brief Entry length as specified in DWARF.
-  uint64_t Length;
-
-  /// An entry may contain CFI instructions. An instruction consists of an
-  /// opcode and an optional sequence of operands.
-  using Operands = std::vector<uint64_t>;
-  struct Instruction {
-    Instruction(uint8_t Opcode)
-      : Opcode(Opcode)
-    {}
-
-    uint8_t Opcode;
-    Operands Ops;
-  };
-
-  std::vector<Instruction> Instructions;
-
-  /// Convenience methods to add a new instruction with the given opcode and
-  /// operands to the Instructions vector.
-  void addInstruction(uint8_t Opcode) {
-    Instructions.push_back(Instruction(Opcode));
-  }
-
-  void addInstruction(uint8_t Opcode, uint64_t Operand1) {
-    Instructions.push_back(Instruction(Opcode));
-    Instructions.back().Ops.push_back(Operand1);
-  }
-
-  void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
-    Instructions.push_back(Instruction(Opcode));
-    Instructions.back().Ops.push_back(Operand1);
-    Instructions.back().Ops.push_back(Operand2);
-  }
-};
 
 // See DWARF standard v3, section 7.23
 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
 const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
 
-void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
-                                   uint32_t EndOffset) {
+Error CFIProgram::parse(DataExtractor Data, uint32_t *Offset,
+                        uint32_t EndOffset) {
   while (*Offset < EndOffset) {
     uint8_t Opcode = Data.getU8(Offset);
     // Some instructions have a primary opcode encoded in the top bits.
@@ -122,67 +46,73 @@ void FrameEntry::parseInstructions(DataE
       // bits of the opcode itself.
       uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
       switch (Primary) {
-        default: llvm_unreachable("Impossible primary CFI opcode");
-        case DW_CFA_advance_loc:
-        case DW_CFA_restore:
-          addInstruction(Primary, Op1);
-          break;
-        case DW_CFA_offset:
-          addInstruction(Primary, Op1, Data.getULEB128(Offset));
-          break;
+      default:
+        return make_error<StringError>(
+            "Invalid primary CFI opcode",
+            std::make_error_code(std::errc::illegal_byte_sequence));
+      case DW_CFA_advance_loc:
+      case DW_CFA_restore:
+        addInstruction(Primary, Op1);
+        break;
+      case DW_CFA_offset:
+        addInstruction(Primary, Op1, Data.getULEB128(Offset));
+        break;
       }
     } else {
       // Extended opcode - its value is Opcode itself.
       switch (Opcode) {
-        default: llvm_unreachable("Invalid extended CFI opcode");
-        case DW_CFA_nop:
-        case DW_CFA_remember_state:
-        case DW_CFA_restore_state:
-        case DW_CFA_GNU_window_save:
-          // No operands
-          addInstruction(Opcode);
-          break;
-        case DW_CFA_set_loc:
-          // Operands: Address
-          addInstruction(Opcode, Data.getAddress(Offset));
-          break;
-        case DW_CFA_advance_loc1:
-          // Operands: 1-byte delta
-          addInstruction(Opcode, Data.getU8(Offset));
-          break;
-        case DW_CFA_advance_loc2:
-          // Operands: 2-byte delta
-          addInstruction(Opcode, Data.getU16(Offset));
-          break;
-        case DW_CFA_advance_loc4:
-          // Operands: 4-byte delta
-          addInstruction(Opcode, Data.getU32(Offset));
-          break;
-        case DW_CFA_restore_extended:
-        case DW_CFA_undefined:
-        case DW_CFA_same_value:
-        case DW_CFA_def_cfa_register:
-        case DW_CFA_def_cfa_offset:
-        case DW_CFA_GNU_args_size:
-          // Operands: ULEB128
-          addInstruction(Opcode, Data.getULEB128(Offset));
-          break;
-        case DW_CFA_def_cfa_offset_sf:
-          // Operands: SLEB128
-          addInstruction(Opcode, Data.getSLEB128(Offset));
-          break;
-        case DW_CFA_offset_extended:
-        case DW_CFA_register:
-        case DW_CFA_def_cfa:
-        case DW_CFA_val_offset: {
-          // Operands: ULEB128, ULEB128
-          // Note: We can not embed getULEB128 directly into function
-          // argument list. getULEB128 changes Offset and order of evaluation
-          // for arguments is unspecified.
-          auto op1 = Data.getULEB128(Offset);
-          auto op2 = Data.getULEB128(Offset);
-          addInstruction(Opcode, op1, op2);
-          break;
+      default:
+        return make_error<StringError>(
+            "Invalid extended CFI opcode",
+            std::make_error_code(std::errc::illegal_byte_sequence));
+      case DW_CFA_nop:
+      case DW_CFA_remember_state:
+      case DW_CFA_restore_state:
+      case DW_CFA_GNU_window_save:
+        // No operands
+        addInstruction(Opcode);
+        break;
+      case DW_CFA_set_loc:
+        // Operands: Address
+        addInstruction(Opcode, Data.getAddress(Offset));
+        break;
+      case DW_CFA_advance_loc1:
+        // Operands: 1-byte delta
+        addInstruction(Opcode, Data.getU8(Offset));
+        break;
+      case DW_CFA_advance_loc2:
+        // Operands: 2-byte delta
+        addInstruction(Opcode, Data.getU16(Offset));
+        break;
+      case DW_CFA_advance_loc4:
+        // Operands: 4-byte delta
+        addInstruction(Opcode, Data.getU32(Offset));
+        break;
+      case DW_CFA_restore_extended:
+      case DW_CFA_undefined:
+      case DW_CFA_same_value:
+      case DW_CFA_def_cfa_register:
+      case DW_CFA_def_cfa_offset:
+      case DW_CFA_GNU_args_size:
+        // Operands: ULEB128
+        addInstruction(Opcode, Data.getULEB128(Offset));
+        break;
+      case DW_CFA_def_cfa_offset_sf:
+        // Operands: SLEB128
+        addInstruction(Opcode, Data.getSLEB128(Offset));
+        break;
+      case DW_CFA_offset_extended:
+      case DW_CFA_register:
+      case DW_CFA_def_cfa:
+      case DW_CFA_val_offset: {
+        // Operands: ULEB128, ULEB128
+        // Note: We can not embed getULEB128 directly into function
+        // argument list. getULEB128 changes Offset and order of evaluation
+        // for arguments is unspecified.
+        auto op1 = Data.getULEB128(Offset);
+        auto op2 = Data.getULEB128(Offset);
+        addInstruction(Opcode, op1, op2);
+        break;
         }
         case DW_CFA_offset_extended_sf:
         case DW_CFA_def_cfa_sf:
@@ -194,162 +124,49 @@ void FrameEntry::parseInstructions(DataE
           addInstruction(Opcode, op1, op2);
           break;
         }
-        case DW_CFA_def_cfa_expression:
-          // FIXME: Parse the actual instruction.
-          *Offset += Data.getULEB128(Offset);
+        case DW_CFA_def_cfa_expression: {
+          uint32_t ExprLength = Data.getULEB128(Offset);
+          addInstruction(Opcode, 0);
+          DataExtractor Extractor(
+              Data.getData().slice(*Offset, *Offset + ExprLength),
+              Data.isLittleEndian(), Data.getAddressSize());
+          Instructions.back().Expression = DWARFExpression(
+              Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+          *Offset += ExprLength;
           break;
+        }
         case DW_CFA_expression:
         case DW_CFA_val_expression: {
-          // FIXME: Parse the actual instruction.
-          Data.getULEB128(Offset);
-          *Offset += Data.getULEB128(Offset);
+          auto RegNum = Data.getULEB128(Offset);
+          auto BlockLength = Data.getULEB128(Offset);
+          addInstruction(Opcode, RegNum, 0);
+          DataExtractor Extractor(
+              Data.getData().slice(*Offset, *Offset + BlockLength),
+              Data.isLittleEndian(), Data.getAddressSize());
+          Instructions.back().Expression = DWARFExpression(
+              Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+          *Offset += BlockLength;
           break;
         }
       }
     }
   }
+
+  return Error::success();
 }
 
 namespace {
 
-/// \brief DWARF Common Information Entry (CIE)
-class CIE : public FrameEntry {
-public:
-  // CIEs (and FDEs) are simply container classes, so the only sensible way to
-  // create them is by providing the full parsed contents in the constructor.
-  CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
-      SmallString<8> Augmentation, uint8_t AddressSize,
-      uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
-      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
-      SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
-      uint32_t LSDAPointerEncoding)
-      : FrameEntry(FK_CIE, Offset, Length), Version(Version),
-        Augmentation(std::move(Augmentation)), AddressSize(AddressSize),
-        SegmentDescriptorSize(SegmentDescriptorSize),
-        CodeAlignmentFactor(CodeAlignmentFactor),
-        DataAlignmentFactor(DataAlignmentFactor),
-        ReturnAddressRegister(ReturnAddressRegister),
-        AugmentationData(std::move(AugmentationData)),
-        FDEPointerEncoding(FDEPointerEncoding),
-        LSDAPointerEncoding(LSDAPointerEncoding) {}
-
-  ~CIE() override = default;
-
-  StringRef getAugmentationString() const { return Augmentation; }
-  uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
-  int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
-
-  uint32_t getFDEPointerEncoding() const {
-    return FDEPointerEncoding;
-  }
-
-  uint32_t getLSDAPointerEncoding() const {
-    return LSDAPointerEncoding;
-  }
-
-  void dumpHeader(raw_ostream &OS) const override {
-    OS << format("%08x %08x %08x CIE",
-                 (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID)
-       << "\n";
-    OS << format("  Version:               %d\n", Version);
-    OS << "  Augmentation:          \"" << Augmentation << "\"\n";
-    if (Version >= 4) {
-      OS << format("  Address size:          %u\n",
-                   (uint32_t)AddressSize);
-      OS << format("  Segment desc size:     %u\n",
-                   (uint32_t)SegmentDescriptorSize);
-    }
-    OS << format("  Code alignment factor: %u\n",
-                 (uint32_t)CodeAlignmentFactor);
-    OS << format("  Data alignment factor: %d\n",
-                 (int32_t)DataAlignmentFactor);
-    OS << format("  Return address column: %d\n",
-                 (int32_t)ReturnAddressRegister);
-    if (!AugmentationData.empty()) {
-      OS << "  Augmentation data:    ";
-      for (uint8_t Byte : AugmentationData)
-        OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
-      OS << "\n";
-    }
-    OS << "\n";
-  }
-
-  static bool classof(const FrameEntry *FE) {
-    return FE->getKind() == FK_CIE;
-  }
-
-private:
-  /// The following fields are defined in section 6.4.1 of the DWARF standard v4
-  uint8_t Version;
-  SmallString<8> Augmentation;
-  uint8_t AddressSize;
-  uint8_t SegmentDescriptorSize;
-  uint64_t CodeAlignmentFactor;
-  int64_t DataAlignmentFactor;
-  uint64_t ReturnAddressRegister;
-
-  // The following are used when the CIE represents an EH frame entry.
-  SmallString<8> AugmentationData;
-  uint32_t FDEPointerEncoding;
-  uint32_t LSDAPointerEncoding;
-};
-
-/// \brief DWARF Frame Description Entry (FDE)
-class FDE : public FrameEntry {
-public:
-  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
-  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
-  // is obtained lazily once it's actually required.
-  FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
-      uint64_t InitialLocation, uint64_t AddressRange,
-      CIE *Cie)
-      : FrameEntry(FK_FDE, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
-        InitialLocation(InitialLocation), AddressRange(AddressRange),
-        LinkedCIE(Cie) {}
-
-  ~FDE() override = default;
-
-  CIE *getLinkedCIE() const { return LinkedCIE; }
-
-  void dumpHeader(raw_ostream &OS) const override {
-    OS << format("%08x %08x %08x FDE ",
-                 (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset);
-    OS << format("cie=%08x pc=%08x...%08x\n",
-                 (int32_t)LinkedCIEOffset,
-                 (uint32_t)InitialLocation,
-                 (uint32_t)InitialLocation + (uint32_t)AddressRange);
-  }
-
-  static bool classof(const FrameEntry *FE) {
-    return FE->getKind() == FK_FDE;
-  }
-
-private:
-  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
-  uint64_t LinkedCIEOffset;
-  uint64_t InitialLocation;
-  uint64_t AddressRange;
-  CIE *LinkedCIE;
-};
-
-/// \brief Types of operands to CF instructions.
-enum OperandType {
-  OT_Unset,
-  OT_None,
-  OT_Address,
-  OT_Offset,
-  OT_FactoredCodeOffset,
-  OT_SignedFactDataOffset,
-  OT_UnsignedFactDataOffset,
-  OT_Register,
-  OT_Expression
-};
 
 } // end anonymous namespace
 
-/// \brief Initialize the array describing the types of operands.
-static ArrayRef<OperandType[2]> getOperandTypes() {
+ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
   static OperandType OpTypes[DW_CFA_restore+1][2];
+  static bool Initialized = false;
+  if (Initialized) {
+    return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+  }
+  Initialized = true;
 
 #define DECLARE_OP2(OP, OPTYPE0, OPTYPE1)       \
   do {                                          \
@@ -396,15 +213,13 @@ static ArrayRef<OperandType[2]> getOpera
   return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
 }
 
-static ArrayRef<OperandType[2]> OpTypes = getOperandTypes();
-
-/// \brief Print \p Opcode's operand number \p OperandIdx which has
-/// value \p Operand.
-static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx,
-                         uint64_t Operand, uint64_t CodeAlignmentFactor,
-                         int64_t DataAlignmentFactor) {
+/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+void CFIProgram::printOperand(raw_ostream &OS, const MCRegisterInfo *MRI,
+                              bool IsEH, const Instruction &Instr,
+                              unsigned OperandIdx, uint64_t Operand) const {
   assert(OperandIdx < 2);
-  OperandType Type = OpTypes[Opcode][OperandIdx];
+  uint8_t Opcode = Instr.Opcode;
+  OperandType Type = getOperandTypes()[Opcode][OperandIdx];
 
   switch (Type) {
   case OT_Unset: {
@@ -449,36 +264,68 @@ static void printOperand(raw_ostream &OS
     OS << format(" reg%" PRId64, Operand);
     break;
   case OT_Expression:
-    OS << " expression";
+    assert(Instr.Expression && "missing DWARFExpression object");
+    OS << " ";
+    Instr.Expression->print(OS, MRI, IsEH);
     break;
   }
 }
 
-void FrameEntry::dumpInstructions(raw_ostream &OS) const {
-  uint64_t CodeAlignmentFactor = 0;
-  int64_t DataAlignmentFactor = 0;
-  const CIE *Cie = dyn_cast<CIE>(this);
-
-  if (!Cie)
-    Cie = cast<FDE>(this)->getLinkedCIE();
-  if (Cie) {
-    CodeAlignmentFactor = Cie->getCodeAlignmentFactor();
-    DataAlignmentFactor = Cie->getDataAlignmentFactor();
-  }
-
+void CFIProgram::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+                      unsigned IndentLevel) const {
   for (const auto &Instr : Instructions) {
     uint8_t Opcode = Instr.Opcode;
     if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
       Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
-    OS << "  " << CallFrameString(Opcode) << ":";
+    OS.indent(2 * IndentLevel);
+    OS << CallFrameString(Opcode) << ":";
     for (unsigned i = 0; i < Instr.Ops.size(); ++i)
-      printOperand(OS, Opcode, i, Instr.Ops[i], CodeAlignmentFactor,
-                   DataAlignmentFactor);
+      printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
     OS << '\n';
   }
 }
 
-DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {}
+void CIE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+  OS << format("%08x %08x %08x CIE", (uint32_t)Offset, (uint32_t)Length,
+               DW_CIE_ID)
+     << "\n";
+  OS << format("  Version:               %d\n", Version);
+  OS << "  Augmentation:          \"" << Augmentation << "\"\n";
+  if (Version >= 4) {
+    OS << format("  Address size:          %u\n", (uint32_t)AddressSize);
+    OS << format("  Segment desc size:     %u\n",
+                 (uint32_t)SegmentDescriptorSize);
+  }
+  OS << format("  Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
+  OS << format("  Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
+  OS << format("  Return address column: %d\n", (int32_t)ReturnAddressRegister);
+  if (Personality)
+    OS << format("  Personality Address: %08x\n", *Personality);
+  if (!AugmentationData.empty()) {
+    OS << "  Augmentation data:    ";
+    for (uint8_t Byte : AugmentationData)
+      OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
+    OS << "\n";
+  }
+  OS << "\n";
+  CFIs.dump(OS, MRI, IsEH);
+  OS << "\n";
+}
+
+void FDE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+  OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length,
+               (int32_t)LinkedCIEOffset);
+  OS << format("cie=%08x pc=%08x...%08x\n", (int32_t)LinkedCIEOffset,
+               (uint32_t)InitialLocation,
+               (uint32_t)InitialLocation + (uint32_t)AddressRange);
+  if (LSDAAddress)
+    OS << format("  LSDA Address: %08x\n", *LSDAAddress);
+  CFIs.dump(OS, MRI, IsEH);
+  OS << "\n";
+}
+
+DWARFDebugFrame::DWARFDebugFrame(bool IsEH, uint64_t EHFrameAddress)
+    : IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
 
 DWARFDebugFrame::~DWARFDebugFrame() = default;
 
@@ -492,40 +339,6 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDa
   errs() << "\n";
 }
 
-static unsigned getSizeForEncoding(const DataExtractor &Data,
-                                   unsigned symbolEncoding) {
-  unsigned format = symbolEncoding & 0x0f;
-  switch (format) {
-    default: llvm_unreachable("Unknown Encoding");
-    case DW_EH_PE_absptr:
-    case DW_EH_PE_signed:
-      return Data.getAddressSize();
-    case DW_EH_PE_udata2:
-    case DW_EH_PE_sdata2:
-      return 2;
-    case DW_EH_PE_udata4:
-    case DW_EH_PE_sdata4:
-      return 4;
-    case DW_EH_PE_udata8:
-    case DW_EH_PE_sdata8:
-      return 8;
-  }
-}
-
-static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset,
-                            unsigned Encoding) {
-  switch (getSizeForEncoding(Data, Encoding)) {
-    case 2:
-      return Data.getU16(&Offset);
-    case 4:
-      return Data.getU32(&Offset);
-    case 8:
-      return Data.getU64(&Offset);
-    default:
-      llvm_unreachable("Illegal data size");
-  }
-}
-
 // This is a workaround for old compilers which do not allow
 // noreturn attribute usage in lambdas. Once the support for those
 // compilers are phased out, we can remove this and return back to
@@ -539,7 +352,7 @@ static void LLVM_ATTRIBUTE_NORETURN Repo
   report_fatal_error(Str);
 }
 
-void DWARFDebugFrame::parse(DataExtractor Data) {
+void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
   uint32_t Offset = 0;
   DenseMap<uint32_t, CIE *> CIEs;
 
@@ -569,9 +382,8 @@ void DWARFDebugFrame::parse(DataExtracto
 
     // The Id field's size depends on the DWARF format
     Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
-    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) ||
-                  Id == DW_CIE_ID ||
-                  (IsEH && !Id));
+    bool IsCIE =
+        ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id));
 
     if (IsCIE) {
       uint8_t Version = Data.getU8(&Offset);
@@ -589,10 +401,9 @@ void DWARFDebugFrame::parse(DataExtracto
       StringRef AugmentationData("");
       uint32_t FDEPointerEncoding = DW_EH_PE_omit;
       uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
+      Optional<uint64_t> Personality;
+      Optional<uint32_t> PersonalityEncoding;
       if (IsEH) {
-        Optional<uint32_t> PersonalityEncoding;
-        Optional<uint64_t> Personality;
-
         Optional<uint64_t> AugmentationLength;
         uint32_t StartAugmentationOffset;
         uint32_t EndAugmentationOffset;
@@ -611,7 +422,9 @@ void DWARFDebugFrame::parse(DataExtracto
                 ReportError(StartOffset,
                             "Duplicate personality in entry at %lx");
               PersonalityEncoding = Data.getU8(&Offset);
-              Personality = readPointer(Data, Offset, *PersonalityEncoding);
+              Personality = Data.getEncodedPointer(
+                  &Offset, *PersonalityEncoding,
+                  EHFrameAddress ? EHFrameAddress + Offset : 0);
               break;
             }
             case 'R':
@@ -639,14 +452,11 @@ void DWARFDebugFrame::parse(DataExtracto
         }
       }
 
-      auto Cie = llvm::make_unique<CIE>(StartOffset, Length, Version,
-                                        AugmentationString, AddressSize,
-                                        SegmentDescriptorSize,
-                                        CodeAlignmentFactor,
-                                        DataAlignmentFactor,
-                                        ReturnAddressRegister,
-                                        AugmentationData, FDEPointerEncoding,
-                                        LSDAPointerEncoding);
+      auto Cie = llvm::make_unique<CIE>(
+          StartOffset, Length, Version, AugmentationString, AddressSize,
+          SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
+          ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
+          LSDAPointerEncoding, Personality, PersonalityEncoding);
       CIEs[StartOffset] = Cie.get();
       Entries.emplace_back(std::move(Cie));
     } else {
@@ -654,6 +464,7 @@ void DWARFDebugFrame::parse(DataExtracto
       uint64_t CIEPointer = Id;
       uint64_t InitialLocation = 0;
       uint64_t AddressRange = 0;
+      Optional<uint64_t> LSDAAddress;
       CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
 
       if (IsEH) {
@@ -662,10 +473,15 @@ void DWARFDebugFrame::parse(DataExtracto
           ReportError(StartOffset,
                       "Parsing FDE data at %lx failed due to missing CIE");
 
-        InitialLocation = readPointer(Data, Offset,
-                                      Cie->getFDEPointerEncoding());
-        AddressRange = readPointer(Data, Offset,
-                                   Cie->getFDEPointerEncoding());
+        if (auto Val = Data.getEncodedPointer(
+                &Offset, Cie->getFDEPointerEncoding(),
+                EHFrameAddress ? EHFrameAddress + Offset : 0)) {
+          InitialLocation = *Val;
+        }
+        if (auto Val = Data.getEncodedPointer(
+                &Offset, Cie->getFDEPointerEncoding(), 0)) {
+          AddressRange = *Val;
+        }
 
         StringRef AugmentationString = Cie->getAugmentationString();
         if (!AugmentationString.empty()) {
@@ -676,8 +492,11 @@ void DWARFDebugFrame::parse(DataExtracto
             Offset + static_cast<uint32_t>(AugmentationLength);
 
           // Decode the LSDA if the CIE augmentation string said we should.
-          if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit)
-            readPointer(Data, Offset, Cie->getLSDAPointerEncoding());
+          if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
+            LSDAAddress = Data.getEncodedPointer(
+                &Offset, Cie->getLSDAPointerEncoding(),
+                EHFrameAddress ? Offset + EHFrameAddress : 0);
+          }
 
           if (Offset != EndAugmentationOffset)
             ReportError(StartOffset, "Parsing augmentation data at %lx failed");
@@ -689,10 +508,13 @@ void DWARFDebugFrame::parse(DataExtracto
 
       Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
                                    InitialLocation, AddressRange,
-                                   Cie));
+                                   Cie, LSDAAddress));
     }
 
-    Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
+    if (Error E =
+            Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
+      report_fatal_error(toString(std::move(E)));
+    }
 
     if (Offset != EndStructureOffset)
       ReportError(StartOffset, "Parsing entry instructions at %lx failed");
@@ -709,14 +531,15 @@ FrameEntry *DWARFDebugFrame::getEntryAtO
   return nullptr;
 }
 
-void DWARFDebugFrame::dump(raw_ostream &OS, Optional<uint64_t> Offset) const {
+void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+                           Optional<uint64_t> Offset) const {
   if (Offset) {
     if (auto *Entry = getEntryAtOffset(*Offset))
-      Entry->dump(OS);
+      Entry->dump(OS, MRI, IsEH);
     return;
   }
 
   OS << "\n";
   for (const auto &Entry : Entries)
-    Entry->dump(OS);
+    Entry->dump(OS, MRI, IsEH);
 }

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp Wed Mar  7 11:19:51 2018
@@ -258,9 +258,10 @@ bool DWARFExpression::Operation::print(r
   return true;
 }
 
-void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo) {
+void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
+                            bool IsEH) const {
   for (auto &Op : *this) {
-    if (!Op.print(OS, this, RegInfo, /* isEH */ false)) {
+    if (!Op.print(OS, this, RegInfo, IsEH)) {
       uint32_t FailOffset = Op.getEndOffset();
       while (FailOffset < Data.getData().size())
         OS << format(" %02x", Data.getU8(&FailOffset));

Modified: llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/ELFYAML.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/ELFYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/ELFYAML.cpp Wed Mar  7 11:19:51 2018
@@ -50,6 +50,7 @@ void ScalarEnumerationTraits<ELFYAML::EL
   ECase(PT_SHLIB);
   ECase(PT_PHDR);
   ECase(PT_TLS);
+  ECase(PT_GNU_EH_FRAME);
 #undef ECase
   IO.enumFallback<Hex32>(Value);
 }

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml?rev=326932&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml (added)
+++ llvm/trunk/test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml Wed Mar  7 11:19:51 2018
@@ -0,0 +1,46 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+  Entry:           0x0000000000400000
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000400000
+    AddressAlign:    16
+    Content:         50C704240020400031C05AC3
+  - Name:            .eh_frame_hdr
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x00000000004013c0
+    AddressAlign:    4
+    Content:         011B033B3C00000006000000E0F0FFFF8800000010F1FFFF58000000F6F1FFFFB000000010F2FFFFD000000090FEFFFF0001000000FFFFFF30010000
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000401400
+    AddressAlign:    8
+    Content:         1400000000000000017A5200017810011B0C070890010710140000001C000000B0F0FFFF2A00000000000000000000001400000000000000017A5200017810011B0C070890010000240000001C00000050F0FFFF20000000000E10460E184A0F0B770880003F1A3B2A332422000000001C000000440000003EF1FFFF1000000000410E108602430D064B0C07080000002C0000006400000038F1FFFF7F0C000000450C0A00491006027600450F0376780603660C0C0A00450C070800000000002C0000009400000088FDFFFF6600000000410E108602430D06428F03458E04478D058C06488307024B0C07080000000014000000C4000000C8FDFFFF01000000000000000000000000000000
+Symbols:
+  Global:
+    - Name:            myfunc
+      Type:            STT_FUNC
+      Section:         .text
+      Value:           0x0000000000400000
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_R ]
+    VAddr: 0x00400000
+    PAddr: 0x00400000
+    Sections:
+      - Section: .text
+  - Type: PT_GNU_EH_FRAME
+    Flags: [ PF_X, PF_R ]
+    VAddr: 0x004013C0
+    PAddr: 0x004013C0
+    Sections:
+      - Section: .eh_frame_hdr
+...

Added: llvm/trunk/test/tools/llvm-readobj/unwind.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/unwind.test?rev=326932&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/unwind.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/unwind.test Wed Mar  7 11:19:51 2018
@@ -0,0 +1,170 @@
+RUN: yaml2obj %p/Inputs/dwarf-exprs.exe-x86-64.yaml > %t.exe
+RUN: llvm-readobj -unwind %t.exe | FileCheck %s
+
+CHECK:      EH_FRAME Header [
+CHECK-NEXT:  Address: 0x4013c0
+CHECK-NEXT:  Offset: 0x27c
+CHECK-NEXT:  Size: 0x3c
+CHECK-NEXT:  Corresponding Section: .eh_frame_hdr
+CHECK-NEXT:  Header {
+CHECK-NEXT:    version: 1
+CHECK-NEXT:    eh_frame_ptr_enc: 0x1b
+CHECK-NEXT:    fde_count_enc: 0x3
+CHECK-NEXT:    table_enc: 0x3b
+CHECK-NEXT:    eh_frame_ptr: 0x401400
+CHECK-NEXT:    fde_count: 6
+CHECK-NEXT:    entry 0 {
+CHECK-NEXT:      initial_location: 0x4004a0
+CHECK-NEXT:      address: 0x401448
+CHECK-NEXT:    }
+CHECK-NEXT:    entry 1 {
+CHECK-NEXT:      initial_location: 0x4004d0
+CHECK-NEXT:      address: 0x401418
+CHECK-NEXT:    }
+CHECK-NEXT:    entry 2 {
+CHECK-NEXT:      initial_location: 0x4005b6
+CHECK-NEXT:      address: 0x401470
+CHECK-NEXT:    }
+CHECK-NEXT:    entry 3 {
+CHECK-NEXT:      initial_location: 0x4005d0
+CHECK-NEXT:      address: 0x401490
+CHECK-NEXT:    }
+CHECK-NEXT:    entry 4 {
+CHECK-NEXT:      initial_location: 0x401250
+CHECK-NEXT:      address: 0x4014c0
+CHECK-NEXT:    }
+CHECK-NEXT:    entry 5 {
+CHECK-NEXT:      initial_location: 0x4012c0
+CHECK-NEXT:      address: 0x4014f0
+CHECK-NEXT:    }
+CHECK-NEXT:  }
+CHECK-NEXT:]
+
+CHECK:      .eh_frame section at offset 0x2b8 address 0x401400:
+CHECK-NEXT:  [0x401400] CIE length=20
+CHECK-NEXT:    version: 1
+CHECK-NEXT:    augmentation: zR
+CHECK-NEXT:    code_alignment_factor: 1
+CHECK-NEXT:    data_alignment_factor: -8
+CHECK-NEXT:    return_address_register: 16
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_def_cfa: reg7 +8
+CHECK-NEXT:      DW_CFA_offset: reg16 -8
+CHECK-NEXT:      DW_CFA_undefined: reg16
+
+CHECK:       [0x401418] FDE length=20 cie=[0x401400]
+CHECK-NEXT:    initial_location: 0x4004d0
+CHECK-NEXT:    address_range: 0x2a (end : 0x4004fa)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x401430] CIE length=20
+CHECK-NEXT:    version: 1
+CHECK-NEXT:    augmentation: zR
+CHECK-NEXT:    code_alignment_factor: 1
+CHECK-NEXT:    data_alignment_factor: -8
+CHECK-NEXT:    return_address_register: 16
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_def_cfa: reg7 +8
+CHECK-NEXT:      DW_CFA_offset: reg16 -8
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x401448] FDE length=36 cie=[0x401430]
+CHECK-NEXT:    initial_location: 0x4004a0
+CHECK-NEXT:    address_range: 0x20 (end : 0x4004c0)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_def_cfa_offset: +16
+CHECK-NEXT:      DW_CFA_advance_loc: 6
+CHECK-NEXT:      DW_CFA_def_cfa_offset: +24
+CHECK-NEXT:      DW_CFA_advance_loc: 10
+CHECK-NEXT:      DW_CFA_def_cfa_expression: DW_OP_breg7 +8, DW_OP_breg16 +0, DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, DW_OP_lit3, DW_OP_shl, DW_OP_plus
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x401470] FDE length=28 cie=[0x401430]
+CHECK-NEXT:    initial_location: 0x4005b6
+CHECK-NEXT:    address_range: 0x10 (end : 0x4005c6)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_advance_loc: 1
+CHECK-NEXT:      DW_CFA_def_cfa_offset: +16
+CHECK-NEXT:      DW_CFA_offset: reg6 -16
+CHECK-NEXT:      DW_CFA_advance_loc: 3
+CHECK-NEXT:      DW_CFA_def_cfa_register: reg6
+CHECK-NEXT:      DW_CFA_advance_loc: 11
+CHECK-NEXT:      DW_CFA_def_cfa: reg7 +8
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x401490] FDE length=44 cie=[0x401430]
+CHECK-NEXT:    initial_location: 0x4005d0
+CHECK-NEXT:    address_range: 0xc7f (end : 0x40124f)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_advance_loc: 5
+CHECK-NEXT:      DW_CFA_def_cfa: reg10 +0
+CHECK-NEXT:      DW_CFA_advance_loc: 9
+CHECK-NEXT:      DW_CFA_expression: reg6 DW_OP_breg6 +0
+CHECK-NEXT:      DW_CFA_advance_loc: 5
+CHECK-NEXT:      DW_CFA_def_cfa_expression: DW_OP_breg6 -8, DW_OP_deref
+CHECK-NEXT:      DW_CFA_advance_loc2: 3174
+CHECK-NEXT:      DW_CFA_def_cfa: reg10 +0
+CHECK-NEXT:      DW_CFA_advance_loc: 5
+CHECK-NEXT:      DW_CFA_def_cfa: reg7 +8
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x4014c0] FDE length=44 cie=[0x401430]
+CHECK-NEXT:    initial_location: 0x401250
+CHECK-NEXT:    address_range: 0x66 (end : 0x4012b6)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_advance_loc: 1
+CHECK-NEXT:      DW_CFA_def_cfa_offset: +16
+CHECK-NEXT:      DW_CFA_offset: reg6 -16
+CHECK-NEXT:      DW_CFA_advance_loc: 3
+CHECK-NEXT:      DW_CFA_def_cfa_register: reg6
+CHECK-NEXT:      DW_CFA_advance_loc: 2
+CHECK-NEXT:      DW_CFA_offset: reg15 -24
+CHECK-NEXT:      DW_CFA_advance_loc: 5
+CHECK-NEXT:      DW_CFA_offset: reg14 -32
+CHECK-NEXT:      DW_CFA_advance_loc: 7
+CHECK-NEXT:      DW_CFA_offset: reg13 -40
+CHECK-NEXT:      DW_CFA_offset: reg12 -48
+CHECK-NEXT:      DW_CFA_advance_loc: 8
+CHECK-NEXT:      DW_CFA_offset: reg3 -56
+CHECK-NEXT:      DW_CFA_advance_loc1: 75
+CHECK-NEXT:      DW_CFA_def_cfa: reg7 +8
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+
+CHECK:       [0x4014f0] FDE length=20 cie=[0x401430]
+CHECK-NEXT:    initial_location: 0x4012c0
+CHECK-NEXT:    address_range: 0x1 (end : 0x4012c1)
+
+CHECK:         Program:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:
+CHECK-NEXT:      DW_CFA_nop:

Modified: llvm/trunk/tools/llvm-readobj/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/CMakeLists.txt?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-readobj/CMakeLists.txt Wed Mar  7 11:19:51 2018
@@ -1,5 +1,6 @@
 set(LLVM_LINK_COMPONENTS
   DebugInfoCodeView
+  DebugInfoDWARF
   Object
   BinaryFormat
   Support

Added: llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h?rev=326932&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h (added)
+++ llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h Wed Mar  7 11:19:51 2018
@@ -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");
+
+  auto 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");
+
+  auto 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");
+
+  auto 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

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=326932&r1=326931&r2=326932&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Wed Mar  7 11:19:51 2018
@@ -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_
 
 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";
 }
 




More information about the llvm-commits mailing list