[llvm] r326970 - Reland "[DebugInfo] Support DWARF expressions in eh_frame"

Rafael Auler via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 7 16:46:53 PST 2018


Author: rafauler
Date: Wed Mar  7 16:46:53 2018
New Revision: 326970

URL: http://llvm.org/viewvc/llvm-project?rev=326970&view=rev
Log:
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.

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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFExpression.h Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ScopedPrinter.h (original)
+++ llvm/trunk/include/llvm/Support/ScopedPrinter.h Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFExpression.cpp Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/ELFYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/ELFYAML.cpp Wed Mar  7 16:46:53 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=326970&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 16:46:53 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=326970&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/unwind.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/unwind.test Wed Mar  7 16:46:53 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=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-readobj/CMakeLists.txt Wed Mar  7 16:46:53 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=326970&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h (added)
+++ llvm/trunk/tools/llvm-readobj/DwarfCFIEHPrinter.h Wed Mar  7 16:46:53 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");
+
+  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

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=326970&r1=326969&r2=326970&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Wed Mar  7 16:46:53 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