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
#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
/// 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() ||
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;
void resetIndent() { IndentLevel = 0; }
+ int getIndentLevel() { return IndentLevel; }
+
void setPrefix(StringRef P) { Prefix = P; }
void printIndent() {
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()) {
// 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();
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();
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
using namespace llvm;
*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;
+}
//===----------------------------------------------------------------------===//
#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"
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.
// 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:
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 { \
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: {
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;
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
report_fatal_error(Str);
}
-void DWARFDebugFrame::parse(DataExtractor Data) {
+void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint32_t Offset = 0;
DenseMap<uint32_t, CIE *> CIEs;
// 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);
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;
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':
}
}
- 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 {
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) {
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()) {
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");
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");
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);
}
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));
ECase(PT_SHLIB);
ECase(PT_PHDR);
ECase(PT_TLS);
+ ECase(PT_GNU_EH_FRAME);
#undef ECase
IO.enumFallback<Hex32>(Value);
}
--- /dev/null
+--- !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
+...
--- /dev/null
+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:
set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
+ DebugInfoDWARF
Object
BinaryFormat
Support
--- /dev/null
+//===--- 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
//===----------------------------------------------------------------------===//
#include "ARMEHABIPrinter.h"
+#include "DwarfCFIEHPrinter.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StackMapPrinter.h"
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";
}