mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
Reland "[DebugInfo] Support DWARF expressions in eh_frame"
Summary: Original change was D43313 (r326932) and reverted by r326953 because it broke an LLD test and a windows build. The LLD test was already fixed in lld commit r326944 (thanks maskray). This is the original change with the windows build fixed. llvm-svn: 326970
This commit is contained in:
parent
f016668754
commit
0e7b0fcc48
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -80,6 +80,8 @@ public:
|
||||
|
||||
void resetIndent() { IndentLevel = 0; }
|
||||
|
||||
int getIndentLevel() { return IndentLevel; }
|
||||
|
||||
void setPrefix(StringRef P) { Prefix = P; }
|
||||
|
||||
void printIndent() {
|
||||
|
@ -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::getDebugFrame() {
|
||||
// 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::getEHFrame() {
|
||||
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();
|
||||
|
@ -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::getRelocatedValue(uint32_t Size, uint32_t *Off,
|
||||
*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;
|
||||
}
|
||||
|
@ -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(DataExtractor Data, uint32_t *Offset,
|
||||
// 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(DataExtractor Data, uint32_t *Offset,
|
||||
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]> getOperandTypes() {
|
||||
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, uint8_t Opcode, unsigned OperandIdx,
|
||||
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 dumpDataAux(DataExtractor Data,
|
||||
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 ReportError(uint32_t StartOffset,
|
||||
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(DataExtractor Data) {
|
||||
|
||||
// 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(DataExtractor Data) {
|
||||
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(DataExtractor Data) {
|
||||
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(DataExtractor Data) {
|
||||
}
|
||||
}
|
||||
|
||||
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(DataExtractor Data) {
|
||||
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(DataExtractor Data) {
|
||||
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(DataExtractor Data) {
|
||||
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(DataExtractor Data) {
|
||||
|
||||
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::getEntryAtOffset(uint64_t Offset) const {
|
||||
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);
|
||||
}
|
||||
|
@ -258,9 +258,10 @@ bool DWARFExpression::Operation::print(raw_ostream &OS,
|
||||
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));
|
||||
|
@ -50,6 +50,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_PT>::enumeration(
|
||||
ECase(PT_SHLIB);
|
||||
ECase(PT_PHDR);
|
||||
ECase(PT_TLS);
|
||||
ECase(PT_GNU_EH_FRAME);
|
||||
#undef ECase
|
||||
IO.enumFallback<Hex32>(Value);
|
||||
}
|
||||
|
46
test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml
Normal file
46
test/tools/llvm-readobj/Inputs/dwarf-exprs.exe-x86-64.yaml
Normal file
@ -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
|
||||
...
|
170
test/tools/llvm-readobj/unwind.test
Normal file
170
test/tools/llvm-readobj/unwind.test
Normal file
@ -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:
|
@ -1,5 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
DebugInfoCodeView
|
||||
DebugInfoDWARF
|
||||
Object
|
||||
BinaryFormat
|
||||
Support
|
||||
|
244
tools/llvm-readobj/DwarfCFIEHPrinter.h
Normal file
244
tools/llvm-readobj/DwarfCFIEHPrinter.h
Normal file
@ -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
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMEHABIPrinter.h"
|
||||
#include "DwarfCFIEHPrinter.h"
|
||||
#include "Error.h"
|
||||
#include "ObjDumper.h"
|
||||
#include "StackMapPrinter.h"
|
||||
@ -1808,6 +1809,11 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printUnwindInfo() {
|
||||
const unsigned Machine = Obj->getHeader()->e_machine;
|
||||
if (Machine == EM_386 || Machine == EM_X86_64) {
|
||||
DwarfCFIEH::PrinterContext<ELFT> Ctx(W, Obj);
|
||||
return Ctx.printUnwindInformation();
|
||||
}
|
||||
W.startLine() << "UnwindInfo not implemented.\n";
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user