mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
Implement DW_CFA_LLVM_* for Heterogeneous Debugging
Add support in MC/MIR for writing/parsing, and DebugInfo. This is part of the Extensions for Heterogeneous Debugging defined at https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html Specifically the CFI instructions implemented here are defined at https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html#cfa-definition-instructions Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D76877
This commit is contained in:
parent
d436515539
commit
a2306da6e0
@ -1114,6 +1114,10 @@ HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
|
|||||||
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
|
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
|
||||||
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
|
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
|
||||||
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
|
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
|
||||||
|
// Heterogeneous Debugging Extension defined at
|
||||||
|
// https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html#cfa-definition-instructions
|
||||||
|
HANDLE_DW_CFA(0x30, LLVM_def_aspace_cfa)
|
||||||
|
HANDLE_DW_CFA(0x31, LLVM_def_aspace_cfa_sf)
|
||||||
|
|
||||||
// Apple Objective-C Property Attributes.
|
// Apple Objective-C Property Attributes.
|
||||||
// Keep this list in sync with clang's DeclObjCCommon.h
|
// Keep this list in sync with clang's DeclObjCCommon.h
|
||||||
|
@ -46,11 +46,12 @@ public:
|
|||||||
/// reg = CFA + offset
|
/// reg = CFA + offset
|
||||||
/// reg = defef(CFA + offset)
|
/// reg = defef(CFA + offset)
|
||||||
CFAPlusOffset,
|
CFAPlusOffset,
|
||||||
/// Register it in or at a register plus offset:
|
/// Register or CFA is in or at a register plus offset, optionally in
|
||||||
/// reg = reg + offset
|
/// an address space:
|
||||||
/// reg = deref(reg + offset)
|
/// reg = reg + offset [in addrspace]
|
||||||
|
/// reg = deref(reg + offset [in addrspace])
|
||||||
RegPlusOffset,
|
RegPlusOffset,
|
||||||
/// Register value is in or at a value found by evaluating a DWARF
|
/// Register or CFA value is in or at a value found by evaluating a DWARF
|
||||||
/// expression:
|
/// expression:
|
||||||
/// reg = eval(dwarf_expr)
|
/// reg = eval(dwarf_expr)
|
||||||
/// reg = deref(eval(dwarf_expr))
|
/// reg = deref(eval(dwarf_expr))
|
||||||
@ -64,6 +65,8 @@ private:
|
|||||||
Location Kind; /// The type of the location that describes how to unwind it.
|
Location Kind; /// The type of the location that describes how to unwind it.
|
||||||
uint32_t RegNum; /// The register number for Kind == RegPlusOffset.
|
uint32_t RegNum; /// The register number for Kind == RegPlusOffset.
|
||||||
int32_t Offset; /// The offset for Kind == CFAPlusOffset or RegPlusOffset.
|
int32_t Offset; /// The offset for Kind == CFAPlusOffset or RegPlusOffset.
|
||||||
|
Optional<uint32_t> AddrSpace; /// The address space for Kind == RegPlusOffset
|
||||||
|
/// for CFA.
|
||||||
Optional<DWARFExpression> Expr; /// The DWARF expression for Kind ==
|
Optional<DWARFExpression> Expr; /// The DWARF expression for Kind ==
|
||||||
/// DWARFExpression.
|
/// DWARFExpression.
|
||||||
bool Dereference; /// If true, the resulting location must be dereferenced
|
bool Dereference; /// If true, the resulting location must be dereferenced
|
||||||
@ -72,10 +75,12 @@ private:
|
|||||||
// Constructors are private to force people to use the create static
|
// Constructors are private to force people to use the create static
|
||||||
// functions.
|
// functions.
|
||||||
UnwindLocation(Location K)
|
UnwindLocation(Location K)
|
||||||
: Kind(K), RegNum(InvalidRegisterNumber), Offset(0), Dereference(false) {}
|
: Kind(K), RegNum(InvalidRegisterNumber), Offset(0), AddrSpace(None),
|
||||||
|
Dereference(false) {}
|
||||||
|
|
||||||
UnwindLocation(Location K, uint32_t Reg, int32_t Off, bool Deref)
|
UnwindLocation(Location K, uint32_t Reg, int32_t Off, Optional<uint32_t> AS,
|
||||||
: Kind(K), RegNum(Reg), Offset(Off), Dereference(Deref) {}
|
bool Deref)
|
||||||
|
: Kind(K), RegNum(Reg), Offset(Off), AddrSpace(AS), Dereference(Deref) {}
|
||||||
|
|
||||||
UnwindLocation(DWARFExpression E, bool Deref)
|
UnwindLocation(DWARFExpression E, bool Deref)
|
||||||
: Kind(DWARFExpr), RegNum(InvalidRegisterNumber), Offset(0), Expr(E),
|
: Kind(DWARFExpr), RegNum(InvalidRegisterNumber), Offset(0), Expr(E),
|
||||||
@ -101,14 +106,19 @@ public:
|
|||||||
static UnwindLocation createIsCFAPlusOffset(int32_t Off);
|
static UnwindLocation createIsCFAPlusOffset(int32_t Off);
|
||||||
static UnwindLocation createAtCFAPlusOffset(int32_t Off);
|
static UnwindLocation createAtCFAPlusOffset(int32_t Off);
|
||||||
/// Create a location where the saved value is in (Deref == false) or at
|
/// Create a location where the saved value is in (Deref == false) or at
|
||||||
/// (Deref == true) a regiser plus an offset.
|
/// (Deref == true) a regiser plus an offset and, optionally, in the specified
|
||||||
|
/// address space (used mostly for the CFA).
|
||||||
///
|
///
|
||||||
/// The CFA is usually defined using this rule by using the stack pointer or
|
/// The CFA is usually defined using this rule by using the stack pointer or
|
||||||
/// frame pointer as the register, with an offset that accounts for all
|
/// frame pointer as the register, with an offset that accounts for all
|
||||||
/// spilled registers and all local variables in a function, and Deref ==
|
/// spilled registers and all local variables in a function, and Deref ==
|
||||||
/// false.
|
/// false.
|
||||||
static UnwindLocation createIsRegisterPlusOffset(uint32_t Reg, int32_t Off);
|
static UnwindLocation
|
||||||
static UnwindLocation createAtRegisterPlusOffset(uint32_t Reg, int32_t Off);
|
createIsRegisterPlusOffset(uint32_t Reg, int32_t Off,
|
||||||
|
Optional<uint32_t> AddrSpace = None);
|
||||||
|
static UnwindLocation
|
||||||
|
createAtRegisterPlusOffset(uint32_t Reg, int32_t Off,
|
||||||
|
Optional<uint32_t> AddrSpace = None);
|
||||||
/// Create a location whose value is the result of evaluating a DWARF
|
/// Create a location whose value is the result of evaluating a DWARF
|
||||||
/// expression. This allows complex expressions to be evaluated in order to
|
/// expression. This allows complex expressions to be evaluated in order to
|
||||||
/// unwind a register or CFA value.
|
/// unwind a register or CFA value.
|
||||||
@ -119,13 +129,17 @@ public:
|
|||||||
Location getLocation() const { return Kind; }
|
Location getLocation() const { return Kind; }
|
||||||
uint32_t getRegister() const { return RegNum; }
|
uint32_t getRegister() const { return RegNum; }
|
||||||
int32_t getOffset() const { return Offset; }
|
int32_t getOffset() const { return Offset; }
|
||||||
|
uint32_t getAddressSpace() const {
|
||||||
|
assert(Kind == RegPlusOffset && AddrSpace.hasValue());
|
||||||
|
return *AddrSpace;
|
||||||
|
}
|
||||||
int32_t getConstant() const { return Offset; }
|
int32_t getConstant() const { return Offset; }
|
||||||
/// Some opcodes will modify the CFA location's register only, so we need
|
/// Some opcodes will modify the CFA location's register only, so we need
|
||||||
/// to be able to modify the CFA register when evaluating DWARF Call Frame
|
/// to be able to modify the CFA register when evaluating DWARF Call Frame
|
||||||
/// Information opcodes.
|
/// Information opcodes.
|
||||||
void setRegister(uint32_t NewRegNum) { RegNum = NewRegNum; }
|
void setRegister(uint32_t NewRegNum) { RegNum = NewRegNum; }
|
||||||
/// Some opcodes will modify the CFA location's offset only, so we need
|
/// Some opcodes will modify the CFA location's offset only, so we need
|
||||||
/// to be able to modify the CFA register when evaluating DWARF Call Frame
|
/// to be able to modify the CFA offset when evaluating DWARF Call Frame
|
||||||
/// Information opcodes.
|
/// Information opcodes.
|
||||||
void setOffset(int32_t NewOffset) { Offset = NewOffset; }
|
void setOffset(int32_t NewOffset) { Offset = NewOffset; }
|
||||||
/// Some opcodes modify a constant value and we need to be able to update
|
/// Some opcodes modify a constant value and we need to be able to update
|
||||||
@ -388,7 +402,8 @@ raw_ostream &operator<<(raw_ostream &OS, const UnwindTable &Rows);
|
|||||||
/// manual, "6.4.1 Structure of Call Frame Information".
|
/// manual, "6.4.1 Structure of Call Frame Information".
|
||||||
class CFIProgram {
|
class CFIProgram {
|
||||||
public:
|
public:
|
||||||
typedef SmallVector<uint64_t, 2> Operands;
|
static constexpr size_t MaxOperands = 3;
|
||||||
|
typedef SmallVector<uint64_t, MaxOperands> Operands;
|
||||||
|
|
||||||
/// An instruction consists of a DWARF CFI opcode and an optional sequence of
|
/// 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
|
/// operands. If it refers to an expression, then this expression has its own
|
||||||
@ -467,6 +482,15 @@ private:
|
|||||||
Instructions.back().Ops.push_back(Operand2);
|
Instructions.back().Ops.push_back(Operand2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a new instruction that has three operands.
|
||||||
|
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2,
|
||||||
|
uint64_t Operand3) {
|
||||||
|
Instructions.push_back(Instruction(Opcode));
|
||||||
|
Instructions.back().Ops.push_back(Operand1);
|
||||||
|
Instructions.back().Ops.push_back(Operand2);
|
||||||
|
Instructions.back().Ops.push_back(Operand3);
|
||||||
|
}
|
||||||
|
|
||||||
/// Types of operands to CFI instructions
|
/// Types of operands to CFI instructions
|
||||||
/// In DWARF, this type is implicitly tied to a CFI instruction opcode and
|
/// 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
|
/// thus this type doesn't need to be explictly written to the file (this is
|
||||||
@ -482,6 +506,7 @@ private:
|
|||||||
OT_SignedFactDataOffset,
|
OT_SignedFactDataOffset,
|
||||||
OT_UnsignedFactDataOffset,
|
OT_UnsignedFactDataOffset,
|
||||||
OT_Register,
|
OT_Register,
|
||||||
|
OT_AddressSpace,
|
||||||
OT_Expression
|
OT_Expression
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -490,7 +515,7 @@ private:
|
|||||||
|
|
||||||
/// Retrieve the array describing the types of operands according to the enum
|
/// Retrieve the array describing the types of operands according to the enum
|
||||||
/// above. This is indexed by opcode.
|
/// above. This is indexed by opcode.
|
||||||
static ArrayRef<OperandType[2]> getOperandTypes();
|
static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
|
||||||
|
|
||||||
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
|
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
|
||||||
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
|
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
|
||||||
|
@ -445,6 +445,7 @@ public:
|
|||||||
OpRememberState,
|
OpRememberState,
|
||||||
OpRestoreState,
|
OpRestoreState,
|
||||||
OpOffset,
|
OpOffset,
|
||||||
|
OpLLVMDefAspaceCfa,
|
||||||
OpDefCfaRegister,
|
OpDefCfaRegister,
|
||||||
OpDefCfaOffset,
|
OpDefCfaOffset,
|
||||||
OpDefCfa,
|
OpDefCfa,
|
||||||
@ -467,6 +468,7 @@ private:
|
|||||||
int Offset;
|
int Offset;
|
||||||
unsigned Register2;
|
unsigned Register2;
|
||||||
};
|
};
|
||||||
|
unsigned AddressSpace;
|
||||||
std::vector<char> Values;
|
std::vector<char> Values;
|
||||||
std::string Comment;
|
std::string Comment;
|
||||||
|
|
||||||
@ -474,7 +476,7 @@ private:
|
|||||||
StringRef Comment = "")
|
StringRef Comment = "")
|
||||||
: Operation(Op), Label(L), Register(R), Offset(O),
|
: Operation(Op), Label(L), Register(R), Offset(O),
|
||||||
Values(V.begin(), V.end()), Comment(Comment) {
|
Values(V.begin(), V.end()), Comment(Comment) {
|
||||||
assert(Op != OpRegister);
|
assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa);
|
||||||
}
|
}
|
||||||
|
|
||||||
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
|
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
|
||||||
@ -482,6 +484,11 @@ private:
|
|||||||
assert(Op == OpRegister);
|
assert(Op == OpRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, unsigned AS)
|
||||||
|
: Operation(Op), Label(L), Register(R), Offset(O), AddressSpace(AS) {
|
||||||
|
assert(Op == OpLLVMDefAspaceCfa);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
|
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
|
||||||
/// Register and add Offset to it.
|
/// Register and add Offset to it.
|
||||||
@ -510,6 +517,17 @@ public:
|
|||||||
return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
|
return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Update the remaining docs to use the new proposal wording.
|
||||||
|
/// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to
|
||||||
|
/// be the result of evaluating the DWARF operation expression
|
||||||
|
/// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description.
|
||||||
|
static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register,
|
||||||
|
int Offset,
|
||||||
|
unsigned AddressSpace) {
|
||||||
|
return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset,
|
||||||
|
AddressSpace);
|
||||||
|
}
|
||||||
|
|
||||||
/// .cfi_offset Previous value of Register is saved at offset Offset
|
/// .cfi_offset Previous value of Register is saved at offset Offset
|
||||||
/// from CFA.
|
/// from CFA.
|
||||||
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
|
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
|
||||||
@ -590,7 +608,8 @@ public:
|
|||||||
assert(Operation == OpDefCfa || Operation == OpOffset ||
|
assert(Operation == OpDefCfa || Operation == OpOffset ||
|
||||||
Operation == OpRestore || Operation == OpUndefined ||
|
Operation == OpRestore || Operation == OpUndefined ||
|
||||||
Operation == OpSameValue || Operation == OpDefCfaRegister ||
|
Operation == OpSameValue || Operation == OpDefCfaRegister ||
|
||||||
Operation == OpRelOffset || Operation == OpRegister);
|
Operation == OpRelOffset || Operation == OpRegister ||
|
||||||
|
Operation == OpLLVMDefAspaceCfa);
|
||||||
return Register;
|
return Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,10 +618,16 @@ public:
|
|||||||
return Register2;
|
return Register2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned getAddressSpace() const {
|
||||||
|
assert(Operation == OpLLVMDefAspaceCfa);
|
||||||
|
return AddressSpace;
|
||||||
|
}
|
||||||
|
|
||||||
int getOffset() const {
|
int getOffset() const {
|
||||||
assert(Operation == OpDefCfa || Operation == OpOffset ||
|
assert(Operation == OpDefCfa || Operation == OpOffset ||
|
||||||
Operation == OpRelOffset || Operation == OpDefCfaOffset ||
|
Operation == OpRelOffset || Operation == OpDefCfaOffset ||
|
||||||
Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
|
Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
|
||||||
|
Operation == OpLLVMDefAspaceCfa);
|
||||||
return Offset;
|
return Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,6 +979,8 @@ public:
|
|||||||
virtual void emitCFIDefCfa(int64_t Register, int64_t Offset);
|
virtual void emitCFIDefCfa(int64_t Register, int64_t Offset);
|
||||||
virtual void emitCFIDefCfaOffset(int64_t Offset);
|
virtual void emitCFIDefCfaOffset(int64_t Offset);
|
||||||
virtual void emitCFIDefCfaRegister(int64_t Register);
|
virtual void emitCFIDefCfaRegister(int64_t Register);
|
||||||
|
virtual void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
|
||||||
|
int64_t AddressSpace);
|
||||||
virtual void emitCFIOffset(int64_t Register, int64_t Offset);
|
virtual void emitCFIOffset(int64_t Register, int64_t Offset);
|
||||||
virtual void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding);
|
virtual void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding);
|
||||||
virtual void emitCFILsda(const MCSymbol *Sym, unsigned Encoding);
|
virtual void emitCFILsda(const MCSymbol *Sym, unsigned Encoding);
|
||||||
|
@ -245,6 +245,10 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
|
|||||||
case MCCFIInstruction::OpDefCfaRegister:
|
case MCCFIInstruction::OpDefCfaRegister:
|
||||||
OutStreamer->emitCFIDefCfaRegister(Inst.getRegister());
|
OutStreamer->emitCFIDefCfaRegister(Inst.getRegister());
|
||||||
break;
|
break;
|
||||||
|
case MCCFIInstruction::OpLLVMDefAspaceCfa:
|
||||||
|
OutStreamer->emitCFILLVMDefAspaceCfa(Inst.getRegister(), Inst.getOffset(),
|
||||||
|
Inst.getAddressSpace());
|
||||||
|
break;
|
||||||
case MCCFIInstruction::OpOffset:
|
case MCCFIInstruction::OpOffset:
|
||||||
OutStreamer->emitCFIOffset(Inst.getRegister(), Inst.getOffset());
|
OutStreamer->emitCFIOffset(Inst.getRegister(), Inst.getOffset());
|
||||||
break;
|
break;
|
||||||
|
@ -219,6 +219,14 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||||||
case MCCFIInstruction::OpRestore:
|
case MCCFIInstruction::OpRestore:
|
||||||
CSRRestored.set(CFI.getRegister());
|
CSRRestored.set(CFI.getRegister());
|
||||||
break;
|
break;
|
||||||
|
case MCCFIInstruction::OpLLVMDefAspaceCfa:
|
||||||
|
// TODO: Add support for handling cfi_def_aspace_cfa.
|
||||||
|
#ifndef NDEBUG
|
||||||
|
report_fatal_error(
|
||||||
|
"Support for cfi_llvm_def_aspace_cfa not implemented! Value of CFA "
|
||||||
|
"may be incorrect!\n");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
case MCCFIInstruction::OpRememberState:
|
case MCCFIInstruction::OpRememberState:
|
||||||
// TODO: Add support for handling cfi_remember_state.
|
// TODO: Add support for handling cfi_remember_state.
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -226,6 +226,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
|
|||||||
.Case("adjust_cfa_offset", MIToken::kw_cfi_adjust_cfa_offset)
|
.Case("adjust_cfa_offset", MIToken::kw_cfi_adjust_cfa_offset)
|
||||||
.Case("escape", MIToken::kw_cfi_escape)
|
.Case("escape", MIToken::kw_cfi_escape)
|
||||||
.Case("def_cfa", MIToken::kw_cfi_def_cfa)
|
.Case("def_cfa", MIToken::kw_cfi_def_cfa)
|
||||||
|
.Case("llvm_def_aspace_cfa", MIToken::kw_cfi_llvm_def_aspace_cfa)
|
||||||
.Case("remember_state", MIToken::kw_cfi_remember_state)
|
.Case("remember_state", MIToken::kw_cfi_remember_state)
|
||||||
.Case("restore", MIToken::kw_cfi_restore)
|
.Case("restore", MIToken::kw_cfi_restore)
|
||||||
.Case("restore_state", MIToken::kw_cfi_restore_state)
|
.Case("restore_state", MIToken::kw_cfi_restore_state)
|
||||||
|
@ -83,6 +83,7 @@ struct MIToken {
|
|||||||
kw_cfi_adjust_cfa_offset,
|
kw_cfi_adjust_cfa_offset,
|
||||||
kw_cfi_escape,
|
kw_cfi_escape,
|
||||||
kw_cfi_def_cfa,
|
kw_cfi_def_cfa,
|
||||||
|
kw_cfi_llvm_def_aspace_cfa,
|
||||||
kw_cfi_register,
|
kw_cfi_register,
|
||||||
kw_cfi_remember_state,
|
kw_cfi_remember_state,
|
||||||
kw_cfi_restore,
|
kw_cfi_restore,
|
||||||
|
@ -472,6 +472,7 @@ public:
|
|||||||
bool parseMetadataOperand(MachineOperand &Dest);
|
bool parseMetadataOperand(MachineOperand &Dest);
|
||||||
bool parseCFIOffset(int &Offset);
|
bool parseCFIOffset(int &Offset);
|
||||||
bool parseCFIRegister(Register &Reg);
|
bool parseCFIRegister(Register &Reg);
|
||||||
|
bool parseCFIAddressSpace(unsigned &AddressSpace);
|
||||||
bool parseCFIEscapeValues(std::string& Values);
|
bool parseCFIEscapeValues(std::string& Values);
|
||||||
bool parseCFIOperand(MachineOperand &Dest);
|
bool parseCFIOperand(MachineOperand &Dest);
|
||||||
bool parseIRBlock(BasicBlock *&BB, const Function &F);
|
bool parseIRBlock(BasicBlock *&BB, const Function &F);
|
||||||
@ -2207,6 +2208,16 @@ bool MIParser::parseCFIRegister(Register &Reg) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MIParser::parseCFIAddressSpace(unsigned &AddressSpace) {
|
||||||
|
if (Token.isNot(MIToken::IntegerLiteral))
|
||||||
|
return error("expected a cfi address space literal");
|
||||||
|
if (Token.integerValue().isSigned())
|
||||||
|
return error("expected an unsigned integer (cfi address space)");
|
||||||
|
AddressSpace = Token.integerValue().getZExtValue();
|
||||||
|
lex();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MIParser::parseCFIEscapeValues(std::string &Values) {
|
bool MIParser::parseCFIEscapeValues(std::string &Values) {
|
||||||
do {
|
do {
|
||||||
if (Token.isNot(MIToken::HexLiteral))
|
if (Token.isNot(MIToken::HexLiteral))
|
||||||
@ -2227,6 +2238,7 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
|
|||||||
lex();
|
lex();
|
||||||
int Offset;
|
int Offset;
|
||||||
Register Reg;
|
Register Reg;
|
||||||
|
unsigned AddressSpace;
|
||||||
unsigned CFIIndex;
|
unsigned CFIIndex;
|
||||||
switch (Kind) {
|
switch (Kind) {
|
||||||
case MIToken::kw_cfi_same_value:
|
case MIToken::kw_cfi_same_value:
|
||||||
@ -2273,6 +2285,14 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
|
|||||||
CFIIndex =
|
CFIIndex =
|
||||||
MF.addFrameInst(MCCFIInstruction::cfiDefCfa(nullptr, Reg, Offset));
|
MF.addFrameInst(MCCFIInstruction::cfiDefCfa(nullptr, Reg, Offset));
|
||||||
break;
|
break;
|
||||||
|
case MIToken::kw_cfi_llvm_def_aspace_cfa:
|
||||||
|
if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
|
||||||
|
parseCFIOffset(Offset) || expectAndConsume(MIToken::comma) ||
|
||||||
|
parseCFIAddressSpace(AddressSpace))
|
||||||
|
return true;
|
||||||
|
CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMDefAspaceCfa(
|
||||||
|
nullptr, Reg, Offset, AddressSpace));
|
||||||
|
break;
|
||||||
case MIToken::kw_cfi_remember_state:
|
case MIToken::kw_cfi_remember_state:
|
||||||
CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
|
CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
|
||||||
break;
|
break;
|
||||||
@ -2620,6 +2640,7 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
|
|||||||
case MIToken::kw_cfi_adjust_cfa_offset:
|
case MIToken::kw_cfi_adjust_cfa_offset:
|
||||||
case MIToken::kw_cfi_escape:
|
case MIToken::kw_cfi_escape:
|
||||||
case MIToken::kw_cfi_def_cfa:
|
case MIToken::kw_cfi_def_cfa:
|
||||||
|
case MIToken::kw_cfi_llvm_def_aspace_cfa:
|
||||||
case MIToken::kw_cfi_register:
|
case MIToken::kw_cfi_register:
|
||||||
case MIToken::kw_cfi_remember_state:
|
case MIToken::kw_cfi_remember_state:
|
||||||
case MIToken::kw_cfi_restore:
|
case MIToken::kw_cfi_restore:
|
||||||
|
@ -653,6 +653,14 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
|
|||||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||||
OS << ", " << CFI.getOffset();
|
OS << ", " << CFI.getOffset();
|
||||||
break;
|
break;
|
||||||
|
case MCCFIInstruction::OpLLVMDefAspaceCfa:
|
||||||
|
OS << "llvm_def_aspace_cfa ";
|
||||||
|
if (MCSymbol *Label = CFI.getLabel())
|
||||||
|
MachineOperand::printSymbol(OS, *Label);
|
||||||
|
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||||
|
OS << ", " << CFI.getOffset();
|
||||||
|
OS << ", " << CFI.getAddressSpace();
|
||||||
|
break;
|
||||||
case MCCFIInstruction::OpRelOffset:
|
case MCCFIInstruction::OpRelOffset:
|
||||||
OS << "rel_offset ";
|
OS << "rel_offset ";
|
||||||
if (MCSymbol *Label = CFI.getLabel())
|
if (MCSymbol *Label = CFI.getLabel())
|
||||||
|
@ -48,24 +48,27 @@ UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
|
|||||||
UnwindLocation UnwindLocation::createSame() { return {Same}; }
|
UnwindLocation UnwindLocation::createSame() { return {Same}; }
|
||||||
|
|
||||||
UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
|
UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
|
||||||
return {Constant, InvalidRegisterNumber, Value, false};
|
return {Constant, InvalidRegisterNumber, Value, None, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
|
UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
|
||||||
return {CFAPlusOffset, InvalidRegisterNumber, Offset, false};
|
return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
|
UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
|
||||||
return {CFAPlusOffset, InvalidRegisterNumber, Offset, true};
|
return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindLocation UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum,
|
UnwindLocation
|
||||||
int32_t Offset) {
|
UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
|
||||||
return {RegPlusOffset, RegNum, Offset, false};
|
Optional<uint32_t> AddrSpace) {
|
||||||
|
return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
|
||||||
}
|
}
|
||||||
UnwindLocation UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum,
|
|
||||||
int32_t Offset) {
|
UnwindLocation
|
||||||
return {RegPlusOffset, RegNum, Offset, true};
|
UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
|
||||||
|
Optional<uint32_t> AddrSpace) {
|
||||||
|
return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
|
UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
|
||||||
@ -100,11 +103,13 @@ void UnwindLocation::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
|
|||||||
break;
|
break;
|
||||||
case RegPlusOffset:
|
case RegPlusOffset:
|
||||||
printRegister(OS, MRI, IsEH, RegNum);
|
printRegister(OS, MRI, IsEH, RegNum);
|
||||||
if (Offset == 0)
|
if (Offset == 0 && !AddrSpace)
|
||||||
break;
|
break;
|
||||||
if (Offset > 0)
|
if (Offset >= 0)
|
||||||
OS << "+";
|
OS << "+";
|
||||||
OS << Offset;
|
OS << Offset;
|
||||||
|
if (AddrSpace)
|
||||||
|
OS << " in addrspace" << *AddrSpace;
|
||||||
break;
|
break;
|
||||||
case DWARFExpr:
|
case DWARFExpr:
|
||||||
Expr->print(OS, DIDumpOptions(), MRI, nullptr, IsEH);
|
Expr->print(OS, DIDumpOptions(), MRI, nullptr, IsEH);
|
||||||
@ -313,6 +318,16 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
|
|||||||
// Operands: SLEB128
|
// Operands: SLEB128
|
||||||
addInstruction(Opcode, Data.getSLEB128(C));
|
addInstruction(Opcode, Data.getSLEB128(C));
|
||||||
break;
|
break;
|
||||||
|
case DW_CFA_LLVM_def_aspace_cfa:
|
||||||
|
case DW_CFA_LLVM_def_aspace_cfa_sf: {
|
||||||
|
auto RegNum = Data.getULEB128(C);
|
||||||
|
auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa
|
||||||
|
? Data.getULEB128(C)
|
||||||
|
: Data.getSLEB128(C);
|
||||||
|
auto AddressSpace = Data.getULEB128(C);
|
||||||
|
addInstruction(Opcode, RegNum, CfaOffset, AddressSpace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DW_CFA_offset_extended:
|
case DW_CFA_offset_extended:
|
||||||
case DW_CFA_register:
|
case DW_CFA_register:
|
||||||
case DW_CFA_def_cfa:
|
case DW_CFA_def_cfa:
|
||||||
@ -390,6 +405,7 @@ const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) {
|
|||||||
ENUM_TO_CSTR(OT_SignedFactDataOffset);
|
ENUM_TO_CSTR(OT_SignedFactDataOffset);
|
||||||
ENUM_TO_CSTR(OT_UnsignedFactDataOffset);
|
ENUM_TO_CSTR(OT_UnsignedFactDataOffset);
|
||||||
ENUM_TO_CSTR(OT_Register);
|
ENUM_TO_CSTR(OT_Register);
|
||||||
|
ENUM_TO_CSTR(OT_AddressSpace);
|
||||||
ENUM_TO_CSTR(OT_Expression);
|
ENUM_TO_CSTR(OT_Expression);
|
||||||
}
|
}
|
||||||
return "<unknown CFIProgram::OperandType>";
|
return "<unknown CFIProgram::OperandType>";
|
||||||
@ -398,7 +414,7 @@ const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) {
|
|||||||
llvm::Expected<uint64_t>
|
llvm::Expected<uint64_t>
|
||||||
CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
|
CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
|
||||||
uint32_t OperandIdx) const {
|
uint32_t OperandIdx) const {
|
||||||
if (OperandIdx >= 2)
|
if (OperandIdx >= MaxOperands)
|
||||||
return createStringError(errc::invalid_argument,
|
return createStringError(errc::invalid_argument,
|
||||||
"operand index %" PRIu32 " is not valid",
|
"operand index %" PRIu32 " is not valid",
|
||||||
OperandIdx);
|
OperandIdx);
|
||||||
@ -423,6 +439,7 @@ CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
|
|||||||
|
|
||||||
case OT_Address:
|
case OT_Address:
|
||||||
case OT_Register:
|
case OT_Register:
|
||||||
|
case OT_AddressSpace:
|
||||||
return Operand;
|
return Operand;
|
||||||
|
|
||||||
case OT_FactoredCodeOffset: {
|
case OT_FactoredCodeOffset: {
|
||||||
@ -442,7 +459,7 @@ CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
|
|||||||
llvm::Expected<int64_t>
|
llvm::Expected<int64_t>
|
||||||
CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
|
CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
|
||||||
uint32_t OperandIdx) const {
|
uint32_t OperandIdx) const {
|
||||||
if (OperandIdx >= 2)
|
if (OperandIdx >= MaxOperands)
|
||||||
return createStringError(errc::invalid_argument,
|
return createStringError(errc::invalid_argument,
|
||||||
"operand index %" PRIu32 " is not valid",
|
"operand index %" PRIu32 " is not valid",
|
||||||
OperandIdx);
|
OperandIdx);
|
||||||
@ -458,6 +475,7 @@ CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
|
|||||||
|
|
||||||
case OT_Address:
|
case OT_Address:
|
||||||
case OT_Register:
|
case OT_Register:
|
||||||
|
case OT_AddressSpace:
|
||||||
return createStringError(
|
return createStringError(
|
||||||
errc::invalid_argument,
|
errc::invalid_argument,
|
||||||
"op[%" PRIu32 "] has OperandType %s which produces an unsigned result, "
|
"op[%" PRIu32 "] has OperandType %s which produces an unsigned result, "
|
||||||
@ -745,6 +763,23 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case dwarf::DW_CFA_LLVM_def_aspace_cfa:
|
||||||
|
case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
|
||||||
|
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
|
||||||
|
if (!RegNum)
|
||||||
|
return RegNum.takeError();
|
||||||
|
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
|
||||||
|
if (!Offset)
|
||||||
|
return Offset.takeError();
|
||||||
|
llvm::Expected<uint32_t> CFAAddrSpace =
|
||||||
|
Inst.getOperandAsUnsigned(CFIP, 2);
|
||||||
|
if (!CFAAddrSpace)
|
||||||
|
return CFAAddrSpace.takeError();
|
||||||
|
Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
|
||||||
|
*RegNum, *Offset, *CFAAddrSpace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case dwarf::DW_CFA_def_cfa_expression:
|
case dwarf::DW_CFA_def_cfa_expression:
|
||||||
Row.getCFAValue() =
|
Row.getCFAValue() =
|
||||||
UnwindLocation::createIsDWARFExpression(*Inst.Expression);
|
UnwindLocation::createIsDWARFExpression(*Inst.Expression);
|
||||||
@ -754,19 +789,23 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
|
ArrayRef<CFIProgram::OperandType[CFIProgram::MaxOperands]>
|
||||||
static OperandType OpTypes[DW_CFA_restore+1][2];
|
CFIProgram::getOperandTypes() {
|
||||||
|
static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
|
||||||
static bool Initialized = false;
|
static bool Initialized = false;
|
||||||
if (Initialized) {
|
if (Initialized) {
|
||||||
return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
|
return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
|
||||||
}
|
}
|
||||||
Initialized = true;
|
Initialized = true;
|
||||||
|
|
||||||
#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
|
#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \
|
||||||
do { \
|
do { \
|
||||||
OpTypes[OP][0] = OPTYPE0; \
|
OpTypes[OP][0] = OPTYPE0; \
|
||||||
OpTypes[OP][1] = OPTYPE1; \
|
OpTypes[OP][1] = OPTYPE1; \
|
||||||
|
OpTypes[OP][2] = OPTYPE2; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
|
||||||
|
DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None)
|
||||||
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
|
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
|
||||||
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
|
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
|
||||||
|
|
||||||
@ -779,6 +818,10 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
|
|||||||
DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
|
DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
|
||||||
DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
|
DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
|
||||||
DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
|
DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
|
||||||
|
DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset,
|
||||||
|
OT_AddressSpace);
|
||||||
|
DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register,
|
||||||
|
OT_SignedFactDataOffset, OT_AddressSpace);
|
||||||
DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
|
DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
|
||||||
DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
|
DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
|
||||||
DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
|
DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
|
||||||
@ -804,7 +847,7 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
|
|||||||
#undef DECLARE_OP1
|
#undef DECLARE_OP1
|
||||||
#undef DECLARE_OP2
|
#undef DECLARE_OP2
|
||||||
|
|
||||||
return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
|
return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
|
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
|
||||||
@ -812,7 +855,7 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
|
|||||||
const MCRegisterInfo *MRI, bool IsEH,
|
const MCRegisterInfo *MRI, bool IsEH,
|
||||||
const Instruction &Instr, unsigned OperandIdx,
|
const Instruction &Instr, unsigned OperandIdx,
|
||||||
uint64_t Operand) const {
|
uint64_t Operand) const {
|
||||||
assert(OperandIdx < 2);
|
assert(OperandIdx < MaxOperands);
|
||||||
uint8_t Opcode = Instr.Opcode;
|
uint8_t Opcode = Instr.Opcode;
|
||||||
OperandType Type = getOperandTypes()[Opcode][OperandIdx];
|
OperandType Type = getOperandTypes()[Opcode][OperandIdx];
|
||||||
|
|
||||||
@ -859,6 +902,9 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
|
|||||||
OS << ' ';
|
OS << ' ';
|
||||||
printRegister(OS, MRI, IsEH, Operand);
|
printRegister(OS, MRI, IsEH, Operand);
|
||||||
break;
|
break;
|
||||||
|
case OT_AddressSpace:
|
||||||
|
OS << format(" in addrspace%" PRId64, Operand);
|
||||||
|
break;
|
||||||
case OT_Expression:
|
case OT_Expression:
|
||||||
assert(Instr.Expression && "missing DWARFExpression object");
|
assert(Instr.Expression && "missing DWARFExpression object");
|
||||||
OS << " ";
|
OS << " ";
|
||||||
|
@ -315,6 +315,8 @@ public:
|
|||||||
void emitCFIDefCfa(int64_t Register, int64_t Offset) override;
|
void emitCFIDefCfa(int64_t Register, int64_t Offset) override;
|
||||||
void emitCFIDefCfaOffset(int64_t Offset) override;
|
void emitCFIDefCfaOffset(int64_t Offset) override;
|
||||||
void emitCFIDefCfaRegister(int64_t Register) override;
|
void emitCFIDefCfaRegister(int64_t Register) override;
|
||||||
|
void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
|
||||||
|
int64_t AddressSpace) override;
|
||||||
void emitCFIOffset(int64_t Register, int64_t Offset) override;
|
void emitCFIOffset(int64_t Register, int64_t Offset) override;
|
||||||
void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
|
void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
|
||||||
void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
|
void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
|
||||||
@ -1810,6 +1812,16 @@ void MCAsmStreamer::emitCFIDefCfaOffset(int64_t Offset) {
|
|||||||
EmitEOL();
|
EmitEOL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCAsmStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
|
||||||
|
int64_t AddressSpace) {
|
||||||
|
MCStreamer::emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace);
|
||||||
|
OS << "\t.cfi_llvm_def_aspace_cfa ";
|
||||||
|
EmitRegisterName(Register);
|
||||||
|
OS << ", " << Offset;
|
||||||
|
OS << ", " << AddressSpace;
|
||||||
|
EmitEOL();
|
||||||
|
}
|
||||||
|
|
||||||
static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
|
static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
|
||||||
OS << "\t.cfi_escape ";
|
OS << "\t.cfi_escape ";
|
||||||
if (!Values.empty()) {
|
if (!Values.empty()) {
|
||||||
|
@ -1405,6 +1405,19 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// TODO: Implement `_sf` variants if/when they need to be emitted.
|
||||||
|
case MCCFIInstruction::OpLLVMDefAspaceCfa: {
|
||||||
|
unsigned Reg = Instr.getRegister();
|
||||||
|
if (!IsEH)
|
||||||
|
Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
|
||||||
|
Streamer.emitIntValue(dwarf::DW_CFA_LLVM_def_aspace_cfa, 1);
|
||||||
|
Streamer.emitULEB128IntValue(Reg);
|
||||||
|
CFAOffset = Instr.getOffset();
|
||||||
|
Streamer.emitULEB128IntValue(CFAOffset);
|
||||||
|
Streamer.emitULEB128IntValue(Instr.getAddressSpace());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
case MCCFIInstruction::OpOffset:
|
case MCCFIInstruction::OpOffset:
|
||||||
case MCCFIInstruction::OpRelOffset: {
|
case MCCFIInstruction::OpRelOffset: {
|
||||||
const bool IsRelative =
|
const bool IsRelative =
|
||||||
|
@ -499,6 +499,7 @@ private:
|
|||||||
DK_CFI_DEF_CFA_OFFSET,
|
DK_CFI_DEF_CFA_OFFSET,
|
||||||
DK_CFI_ADJUST_CFA_OFFSET,
|
DK_CFI_ADJUST_CFA_OFFSET,
|
||||||
DK_CFI_DEF_CFA_REGISTER,
|
DK_CFI_DEF_CFA_REGISTER,
|
||||||
|
DK_CFI_LLVM_DEF_ASPACE_CFA,
|
||||||
DK_CFI_OFFSET,
|
DK_CFI_OFFSET,
|
||||||
DK_CFI_REL_OFFSET,
|
DK_CFI_REL_OFFSET,
|
||||||
DK_CFI_PERSONALITY,
|
DK_CFI_PERSONALITY,
|
||||||
@ -600,6 +601,7 @@ private:
|
|||||||
bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);
|
bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);
|
||||||
bool parseDirectiveCFIAdjustCfaOffset();
|
bool parseDirectiveCFIAdjustCfaOffset();
|
||||||
bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);
|
bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);
|
||||||
|
bool parseDirectiveCFILLVMDefAspaceCfa(SMLoc DirectiveLoc);
|
||||||
bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);
|
bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);
|
||||||
bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);
|
bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);
|
||||||
bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);
|
bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);
|
||||||
@ -2186,6 +2188,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
|
|||||||
return parseDirectiveCFIAdjustCfaOffset();
|
return parseDirectiveCFIAdjustCfaOffset();
|
||||||
case DK_CFI_DEF_CFA_REGISTER:
|
case DK_CFI_DEF_CFA_REGISTER:
|
||||||
return parseDirectiveCFIDefCfaRegister(IDLoc);
|
return parseDirectiveCFIDefCfaRegister(IDLoc);
|
||||||
|
case DK_CFI_LLVM_DEF_ASPACE_CFA:
|
||||||
|
return parseDirectiveCFILLVMDefAspaceCfa(IDLoc);
|
||||||
case DK_CFI_OFFSET:
|
case DK_CFI_OFFSET:
|
||||||
return parseDirectiveCFIOffset(IDLoc);
|
return parseDirectiveCFIOffset(IDLoc);
|
||||||
case DK_CFI_REL_OFFSET:
|
case DK_CFI_REL_OFFSET:
|
||||||
@ -4260,6 +4264,19 @@ bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// parseDirectiveCFILLVMDefAspaceCfa
|
||||||
|
/// ::= .cfi_llvm_def_aspace_cfa register, offset, address_space
|
||||||
|
bool AsmParser::parseDirectiveCFILLVMDefAspaceCfa(SMLoc DirectiveLoc) {
|
||||||
|
int64_t Register = 0, Offset = 0, AddressSpace = 0;
|
||||||
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||
|
||||||
|
parseAbsoluteExpression(Offset) || parseComma() ||
|
||||||
|
parseAbsoluteExpression(AddressSpace) || parseEOL())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
getStreamer().emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// parseDirectiveCFIOffset
|
/// parseDirectiveCFIOffset
|
||||||
/// ::= .cfi_offset register, offset
|
/// ::= .cfi_offset register, offset
|
||||||
bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {
|
bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {
|
||||||
@ -5497,6 +5514,7 @@ void AsmParser::initializeDirectiveKindMap() {
|
|||||||
DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;
|
DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;
|
||||||
DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;
|
DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;
|
||||||
DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
|
DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
|
||||||
|
DirectiveKindMap[".cfi_llvm_def_aspace_cfa"] = DK_CFI_LLVM_DEF_ASPACE_CFA;
|
||||||
DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
|
DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
|
||||||
DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
|
DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
|
||||||
DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
|
DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
|
||||||
|
@ -444,7 +444,8 @@ void MCStreamer::emitCFIStartProc(bool IsSimple, SMLoc Loc) {
|
|||||||
if (MAI) {
|
if (MAI) {
|
||||||
for (const MCCFIInstruction& Inst : MAI->getInitialFrameState()) {
|
for (const MCCFIInstruction& Inst : MAI->getInitialFrameState()) {
|
||||||
if (Inst.getOperation() == MCCFIInstruction::OpDefCfa ||
|
if (Inst.getOperation() == MCCFIInstruction::OpDefCfa ||
|
||||||
Inst.getOperation() == MCCFIInstruction::OpDefCfaRegister) {
|
Inst.getOperation() == MCCFIInstruction::OpDefCfaRegister ||
|
||||||
|
Inst.getOperation() == MCCFIInstruction::OpLLVMDefAspaceCfa) {
|
||||||
Frame.CurrentCfaRegister = Inst.getRegister();
|
Frame.CurrentCfaRegister = Inst.getRegister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,6 +518,18 @@ void MCStreamer::emitCFIDefCfaRegister(int64_t Register) {
|
|||||||
CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register);
|
CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
|
||||||
|
int64_t AddressSpace) {
|
||||||
|
MCSymbol *Label = emitCFILabel();
|
||||||
|
MCCFIInstruction Instruction = MCCFIInstruction::createLLVMDefAspaceCfa(
|
||||||
|
Label, Register, Offset, AddressSpace);
|
||||||
|
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
|
||||||
|
if (!CurFrame)
|
||||||
|
return;
|
||||||
|
CurFrame->Instructions.push_back(Instruction);
|
||||||
|
CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register);
|
||||||
|
}
|
||||||
|
|
||||||
void MCStreamer::emitCFIOffset(int64_t Register, int64_t Offset) {
|
void MCStreamer::emitCFIOffset(int64_t Register, int64_t Offset) {
|
||||||
MCSymbol *Label = emitCFILabel();
|
MCSymbol *Label = emitCFILabel();
|
||||||
MCCFIInstruction Instruction =
|
MCCFIInstruction Instruction =
|
||||||
|
@ -23,6 +23,8 @@ body: |
|
|||||||
frame-setup CFI_INSTRUCTION def_cfa_register $w29
|
frame-setup CFI_INSTRUCTION def_cfa_register $w29
|
||||||
; CHECK: CFI_INSTRUCTION def_cfa_offset -8
|
; CHECK: CFI_INSTRUCTION def_cfa_offset -8
|
||||||
frame-setup CFI_INSTRUCTION def_cfa_offset -8
|
frame-setup CFI_INSTRUCTION def_cfa_offset -8
|
||||||
|
; CHECK: CFI_INSTRUCTION llvm_def_aspace_cfa $w29, 16, 6
|
||||||
|
frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $w29, 16, 6
|
||||||
; CHECK: CFI_INSTRUCTION offset $w30, -8
|
; CHECK: CFI_INSTRUCTION offset $w30, -8
|
||||||
frame-setup CFI_INSTRUCTION offset $w30, -8
|
frame-setup CFI_INSTRUCTION offset $w30, -8
|
||||||
; CHECK: CFI_INSTRUCTION rel_offset $w30, -8
|
; CHECK: CFI_INSTRUCTION rel_offset $w30, -8
|
||||||
|
25
test/MC/ELF/cfi-llvm-def-cfa-aspace-errors.s
Normal file
25
test/MC/ELF/cfi-llvm-def-cfa-aspace-errors.s
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o /dev/null 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
// Check that we diagnose malformed .cfi_llvm_def_aspace_cfa directives.
|
||||||
|
|
||||||
|
.cfi_startproc
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: invalid register name
|
||||||
|
.cfi_llvm_def_aspace_cfa foo
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: expected comma
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx .
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: expected absolute expression
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx, .+1
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: expected comma
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx, 1 .
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: expected absolute expression
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx, 1, .+1
|
||||||
|
|
||||||
|
// CHECK: [[#@LINE+1]]:{{[0-9]+}}: error: expected newline
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx, 1, 1,
|
||||||
|
|
||||||
|
.cfi_endproc
|
30
test/MC/ELF/cfi-llvm-def-cfa-aspace.s
Normal file
30
test/MC/ELF/cfi-llvm-def-cfa-aspace.s
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
|
||||||
|
# RUN: llvm-readelf -S -r -x .eh_frame %t | FileCheck --check-prefix=READELF %s
|
||||||
|
|
||||||
|
f:
|
||||||
|
.cfi_startproc
|
||||||
|
nop
|
||||||
|
.cfi_llvm_def_aspace_cfa %rcx, 0, 6
|
||||||
|
nop
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
# ASM: f:
|
||||||
|
# ASM-NEXT: .cfi_startproc
|
||||||
|
# ASM-NEXT: nop
|
||||||
|
# ASM-NEXT: .cfi_llvm_def_aspace_cfa %rcx, 0, 6
|
||||||
|
# ASM-NEXT: nop
|
||||||
|
# ASM-NEXT: .cfi_endproc
|
||||||
|
|
||||||
|
# READELF: Section Headers:
|
||||||
|
# READELF: Name Type Address Off Size ES Flg Lk Inf Al
|
||||||
|
# READELF: .eh_frame X86_64_UNWIND 0000000000000000 000048 000030 00 A 0 0 8
|
||||||
|
|
||||||
|
# READELF: Relocation section '.rela.eh_frame' at offset 0xc0 contains 1 entries:
|
||||||
|
# READELF-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
|
||||||
|
# READELF-NEXT: 0000000000000020 0000000100000002 R_X86_64_PC32 0000000000000000 .text + 0
|
||||||
|
|
||||||
|
# READELF: Hex dump of section '.eh_frame':
|
||||||
|
# READELF-NEXT: 0x00000000 14000000 00000000 017a5200 01781001
|
||||||
|
# READELF-NEXT: 0x00000010 1b0c0708 90010000 14000000 1c000000
|
||||||
|
# READELF-NEXT: 0x00000020 00000000 02000000 00413002 00060000
|
@ -0,0 +1,16 @@
|
|||||||
|
# RUN: llvm-mc %s -filetype=obj -triple=i686-pc-linux -o %t
|
||||||
|
# RUN: llvm-dwarfdump -v %t | FileCheck %s
|
||||||
|
|
||||||
|
# CHECK: .eh_frame contents:
|
||||||
|
# CHECK: FDE
|
||||||
|
# CHECK-NEXT: Format:
|
||||||
|
# CHECK-NEXT: DW_CFA_LLVM_def_aspace_cfa: EDX +0 in addrspace6
|
||||||
|
# CHECK-NEXT: DW_CFA_nop:
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl foo
|
||||||
|
.type foo,@function
|
||||||
|
foo:
|
||||||
|
.cfi_startproc
|
||||||
|
.cfi_llvm_def_aspace_cfa %edx, 0, 6
|
||||||
|
.cfi_endproc
|
@ -162,6 +162,8 @@ TEST(DWARFDebugFrame, InvalidCFIOpcodesTest) {
|
|||||||
dwarf::DW_CFA_offset_extended_sf,
|
dwarf::DW_CFA_offset_extended_sf,
|
||||||
dwarf::DW_CFA_def_cfa_sf,
|
dwarf::DW_CFA_def_cfa_sf,
|
||||||
dwarf::DW_CFA_def_cfa_offset_sf,
|
dwarf::DW_CFA_def_cfa_offset_sf,
|
||||||
|
dwarf::DW_CFA_LLVM_def_aspace_cfa,
|
||||||
|
dwarf::DW_CFA_LLVM_def_aspace_cfa_sf,
|
||||||
dwarf::DW_CFA_val_offset,
|
dwarf::DW_CFA_val_offset,
|
||||||
dwarf::DW_CFA_val_offset_sf,
|
dwarf::DW_CFA_val_offset_sf,
|
||||||
dwarf::DW_CFA_val_expression,
|
dwarf::DW_CFA_val_expression,
|
||||||
@ -268,7 +270,8 @@ TEST(DWARFDebugFrame, ParseTruncatedCFITest) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (uint8_t Inst : {dwarf::DW_CFA_offset_extended, dwarf::DW_CFA_register,
|
for (uint8_t Inst : {dwarf::DW_CFA_offset_extended, dwarf::DW_CFA_register,
|
||||||
dwarf::DW_CFA_def_cfa, dwarf::DW_CFA_val_offset})
|
dwarf::DW_CFA_def_cfa, dwarf::DW_CFA_LLVM_def_aspace_cfa,
|
||||||
|
dwarf::DW_CFA_val_offset})
|
||||||
CheckOp_ULEB128_ULEB128(Inst);
|
CheckOp_ULEB128_ULEB128(Inst);
|
||||||
|
|
||||||
// A test for an instruction with two operands: ULEB128, SLEB128.
|
// A test for an instruction with two operands: ULEB128, SLEB128.
|
||||||
@ -284,8 +287,9 @@ TEST(DWARFDebugFrame, ParseTruncatedCFITest) {
|
|||||||
"malformed sleb128, extends past end"));
|
"malformed sleb128, extends past end"));
|
||||||
};
|
};
|
||||||
|
|
||||||
for (uint8_t Inst : {dwarf::DW_CFA_offset_extended_sf,
|
for (uint8_t Inst :
|
||||||
dwarf::DW_CFA_def_cfa_sf, dwarf::DW_CFA_val_offset_sf})
|
{dwarf::DW_CFA_offset_extended_sf, dwarf::DW_CFA_def_cfa_sf,
|
||||||
|
dwarf::DW_CFA_LLVM_def_aspace_cfa_sf, dwarf::DW_CFA_val_offset_sf})
|
||||||
CheckOp_ULEB128_SLEB128(Inst);
|
CheckOp_ULEB128_SLEB128(Inst);
|
||||||
|
|
||||||
// Unable to read a truncated DW_CFA_def_cfa_expression instruction.
|
// Unable to read a truncated DW_CFA_def_cfa_expression instruction.
|
||||||
@ -1545,4 +1549,102 @@ TEST(DWARFDebugFrame, UnwindTable_DW_CFA_def_cfa) {
|
|||||||
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
|
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DWARFDebugFrame, UnwindTable_DW_CFA_LLVM_def_aspace_cfa) {
|
||||||
|
// Test that DW_CFA_LLVM_def_aspace_cfa, DW_CFA_LLVM_def_aspace_cfa_sf,
|
||||||
|
// DW_CFA_def_cfa_register, DW_CFA_def_cfa_offset, and
|
||||||
|
// DW_CFA_def_cfa_offset_sf works as expected when parsed in the state
|
||||||
|
// machine.
|
||||||
|
dwarf::CIE TestCIE = createCIE(/*IsDWARF64=*/false,
|
||||||
|
/*Offset=*/0x0,
|
||||||
|
/*Length=*/0xff);
|
||||||
|
|
||||||
|
dwarf::FDE TestFDE(/*IsDWARF64=*/true,
|
||||||
|
/*Offset=*/0x3333abcdabcd,
|
||||||
|
/*Length=*/0x4444abcdabcd,
|
||||||
|
/*CIEPointer=*/0x1111abcdabcd,
|
||||||
|
/*InitialLocation=*/0x1000,
|
||||||
|
/*AddressRange=*/0x1000,
|
||||||
|
/*Cie=*/&TestCIE,
|
||||||
|
/*LSDAAddress=*/None,
|
||||||
|
/*Arch=*/Triple::x86_64);
|
||||||
|
|
||||||
|
// Make a CIE that has a valid CFA definition and a single register unwind
|
||||||
|
// rule for register that we will verify is in all of the pushed rows.
|
||||||
|
constexpr uint8_t CFAReg1 = 12;
|
||||||
|
constexpr uint8_t CFAOff1 = 32;
|
||||||
|
constexpr uint8_t CFAReg2 = 13;
|
||||||
|
constexpr uint8_t CFAOff2 = 48;
|
||||||
|
constexpr uint8_t Reg = 13;
|
||||||
|
constexpr uint8_t InReg = 14;
|
||||||
|
constexpr uint8_t AddrSpace = 2;
|
||||||
|
|
||||||
|
EXPECT_THAT_ERROR(
|
||||||
|
parseCFI(TestCIE, {dwarf::DW_CFA_LLVM_def_aspace_cfa, CFAReg1, CFAOff1,
|
||||||
|
AddrSpace, dwarf::DW_CFA_register, Reg, InReg}),
|
||||||
|
Succeeded());
|
||||||
|
|
||||||
|
// Make a FDE with DWARF call frame instruction opcodes that use all of the
|
||||||
|
// DW_CFA_def_cfa* opcodes. This will verify that all opcodes that should
|
||||||
|
// create a row are correctly working.
|
||||||
|
EXPECT_THAT_ERROR(
|
||||||
|
parseCFI(
|
||||||
|
TestFDE,
|
||||||
|
{
|
||||||
|
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_register,
|
||||||
|
CFAReg2, dwarf::DW_CFA_advance_loc | 4,
|
||||||
|
dwarf::DW_CFA_def_cfa_offset, CFAOff2,
|
||||||
|
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_offset_sf,
|
||||||
|
0x7c, // -4 SLEB to make offset = 32 (CFAOff1)
|
||||||
|
dwarf::DW_CFA_advance_loc | 4, dwarf::DW_CFA_def_cfa_sf, CFAReg1,
|
||||||
|
0x7a, // -6 SLEB to make CFA offset 48 (CFAOff2)
|
||||||
|
}),
|
||||||
|
Succeeded());
|
||||||
|
|
||||||
|
// Create locations that we expect the UnwindRow objects to contain after
|
||||||
|
// parsing the DWARF call frame instructions.
|
||||||
|
dwarf::RegisterLocations VerifyLocs;
|
||||||
|
VerifyLocs.setRegisterLocation(
|
||||||
|
Reg, dwarf::UnwindLocation::createIsRegisterPlusOffset(InReg, 0));
|
||||||
|
|
||||||
|
// Verify we catch state machine error.
|
||||||
|
Expected<dwarf::UnwindTable> RowsOrErr = dwarf::UnwindTable::create(&TestFDE);
|
||||||
|
EXPECT_THAT_ERROR(RowsOrErr.takeError(), Succeeded());
|
||||||
|
const dwarf::UnwindTable &Rows = RowsOrErr.get();
|
||||||
|
EXPECT_EQ(Rows.size(), 5u);
|
||||||
|
EXPECT_EQ(Rows[0].getAddress(), 0x1000u);
|
||||||
|
EXPECT_EQ(Rows[0].getCFAValue(),
|
||||||
|
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff1,
|
||||||
|
AddrSpace));
|
||||||
|
EXPECT_EQ(Rows[0].getRegisterLocations().size(), 1u);
|
||||||
|
EXPECT_EQ(Rows[0].getRegisterLocations(), VerifyLocs);
|
||||||
|
|
||||||
|
EXPECT_EQ(Rows[1].getAddress(), 0x1004u);
|
||||||
|
EXPECT_EQ(Rows[1].getCFAValue(),
|
||||||
|
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,
|
||||||
|
AddrSpace));
|
||||||
|
EXPECT_EQ(Rows[1].getRegisterLocations().size(), 1u);
|
||||||
|
EXPECT_EQ(Rows[1].getRegisterLocations(), VerifyLocs);
|
||||||
|
|
||||||
|
EXPECT_EQ(Rows[2].getAddress(), 0x1008u);
|
||||||
|
EXPECT_EQ(Rows[2].getCFAValue(),
|
||||||
|
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff2,
|
||||||
|
AddrSpace));
|
||||||
|
EXPECT_EQ(Rows[2].getRegisterLocations().size(), 1u);
|
||||||
|
EXPECT_EQ(Rows[2].getRegisterLocations(), VerifyLocs);
|
||||||
|
|
||||||
|
EXPECT_EQ(Rows[3].getAddress(), 0x100cu);
|
||||||
|
EXPECT_EQ(Rows[3].getCFAValue(),
|
||||||
|
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg2, CFAOff1,
|
||||||
|
AddrSpace));
|
||||||
|
EXPECT_EQ(Rows[3].getRegisterLocations().size(), 1u);
|
||||||
|
EXPECT_EQ(Rows[3].getRegisterLocations(), VerifyLocs);
|
||||||
|
|
||||||
|
EXPECT_EQ(Rows[4].getAddress(), 0x1010u);
|
||||||
|
EXPECT_EQ(Rows[4].getCFAValue(),
|
||||||
|
dwarf::UnwindLocation::createIsRegisterPlusOffset(CFAReg1, CFAOff2,
|
||||||
|
AddrSpace));
|
||||||
|
EXPECT_EQ(Rows[4].getRegisterLocations().size(), 1u);
|
||||||
|
EXPECT_EQ(Rows[4].getRegisterLocations(), VerifyLocs);
|
||||||
|
}
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user