of the stack is treated as an address. The second stack entry is treated as an
address space identifier.
- ``DW_OP_stack_value`` marks a constant value.
+- If an expression is marked with ``DW_OP_entry_value`` all register and
+ memory read operations refer to the respective value at the function entry.
+ The first operand of ``DW_OP_entry_value`` is the size of following
+ DWARF expression.
+ ``DW_OP_entry_value`` may appear after the ``LiveDebugValues`` pass.
+ LLVM only supports entry values for function parameters
+ that are unmodified throughout a function and that are described as
+ simple register location descriptions.
+ ``DW_OP_entry_value`` may also appear after the ``AsmPrinter`` pass when
+ a call site parameter value (``DW_AT_call_site_parameter_value``)
+ is represented as entry value of the parameter.
DWARF specifies three kinds of simple location descriptions: Register, memory,
and implicit location descriptions. Note that a location description is
// Vendor extensions:
// Extensions for GNU-style thread-local storage.
HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU)
+// The GNU entry value extension.
+HANDLE_DW_OP(0xf3, GNU_entry_value, 0, GNU)
// Extensions for Fission proposal.
HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
ApplyOffset = 0,
DerefBefore = 1 << 0,
DerefAfter = 1 << 1,
- StackValue = 1 << 2
+ StackValue = 1 << 2,
+ EntryValue = 1 << 3
};
/// Prepend \p DIExpr with a deref and offset operation and optionally turn it
- /// into a stack value.
+ /// into a stack value or/and an entry value.
static DIExpression *prepend(const DIExpression *Expr, uint8_t Flags,
int64_t Offset = 0);
/// stack value.
static DIExpression *prependOpcodes(const DIExpression *Expr,
SmallVectorImpl<uint64_t> &Ops,
- bool StackValue = false);
+ bool StackValue = false,
+ bool EntryValue = false);
/// Append the opcodes \p Ops to \p DIExpr. Unlike \ref appendToStack, the
/// returned expression is a stack value only if \p DIExpr is a stack value.
return true;
return fragmentCmp(Other) == 0;
}
+
+ /// Check if the expression consists of exactly one entry value operand.
+ /// (This is the only configuration of entry values that is supported.)
+ bool isEntryValue() const {
+ return getNumElements() > 0 &&
+ getElement(0) == dwarf::DW_OP_entry_value;
+ }
};
inline bool operator==(const DIExpression::FragmentInfo &A,
static Register isDescribedByReg(const MachineInstr &MI) {
assert(MI.isDebugValue());
assert(MI.getNumOperands() == 4);
+ // If the location of variable is an entry value (DW_OP_entry_value)
+ // do not consider it as a register location.
+ if (MI.getDebugExpression()->isEntryValue())
+ return 0;
// If location of variable is described using a register (directly or
// indirectly), this register is always a first operand.
return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : Register();
const ConstantInt *getConstantInt() const { return Constant.CIP; }
MachineLocation getLoc() const { return Loc; }
bool isFragment() const { return getExpression()->isFragment(); }
+ bool isEntryVal() const { return getExpression()->isEntryValue(); }
const DIExpression *getExpression() const { return Expression; }
friend bool operator==(const DbgValueLoc &, const DbgValueLoc &);
friend bool operator<(const DbgValueLoc &, const DbgValueLoc &);
}
}
-static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
- const DbgValueLoc &Value,
- DwarfExpression &DwarfExpr) {
+void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
+ const DbgValueLoc &Value,
+ DwarfExpression &DwarfExpr) {
auto *DIExpr = Value.getExpression();
DIExpressionCursor ExprCursor(DIExpr);
DwarfExpr.addFragmentOffset(DIExpr);
if (Location.isIndirect())
DwarfExpr.setMemoryLocationKind();
DIExpressionCursor Cursor(DIExpr);
+
+ if (DIExpr->isEntryValue()) {
+ DwarfExpr.setEntryValueFlag();
+ DwarfExpr.addEntryValueExpression(Cursor);
+ }
+
const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
return;
"fragments are expected to be sorted");
for (auto Fragment : Values)
- emitDebugLocValue(AP, BT, Fragment, DwarfExpr);
+ DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr);
} else {
assert(Values.size() == 1 && "only fragments may have >1 value");
- emitDebugLocValue(AP, BT, Value, DwarfExpr);
+ DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr);
}
DwarfExpr.finalize();
}
class DebugLocEntry;
class DIE;
class DwarfCompileUnit;
+class DwarfExpression;
class DwarfTypeUnit;
class DwarfUnit;
class LexicalScope;
void addSectionLabel(const MCSymbol *Sym);
const MCSymbol *getSectionLabel(const MCSection *S);
+
+ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
+ const DbgValueLoc &Value,
+ DwarfExpression &DwarfExpr);
};
} // end namespace llvm
addReg(Reg.DwarfRegNo, Reg.Comment);
addOpPiece(Reg.Size);
}
+
+ if (isEntryValue() && DwarfVersion >= 4)
+ emitOp(dwarf::DW_OP_stack_value);
+
DwarfRegs.clear();
return true;
}
return true;
}
+void DwarfExpression::addEntryValueExpression(DIExpressionCursor &ExprCursor) {
+ auto Op = ExprCursor.take();
+ assert(Op && Op->getOp() == dwarf::DW_OP_entry_value);
+ assert(!isMemoryLocation() &&
+ "We don't support entry values of memory locations yet");
+
+ if (DwarfVersion >= 5)
+ emitOp(dwarf::DW_OP_entry_value);
+ else
+ emitOp(dwarf::DW_OP_GNU_entry_value);
+ emitUnsigned(Op->getArg(0));
+}
+
/// Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?".
static bool isMemoryLocation(DIExpressionCursor ExprCursor) {
while (ExprCursor) {
/// The kind of location description being produced.
enum { Unknown = 0, Register, Memory, Implicit };
+ /// The flags of location description being produced.
+ enum { EntryValue = 1 };
+
unsigned LocationKind : 3;
unsigned LocationFlags : 2;
unsigned DwarfVersion : 4;
return LocationKind == Implicit;
}
+ bool isEntryValue() const {
+ return LocationFlags & EntryValue;
+ }
+
Optional<uint8_t> TagOffset;
protected:
LocationKind = Memory;
}
+ /// Lock this down to become an entry value location.
+ void setEntryValueFlag() {
+ LocationFlags |= EntryValue;
+ }
+
/// Emit a machine register location. As an optimization this may also consume
/// the prefix of a DwarfExpression if a more efficient representation for
/// combining the register location and the first operation exists.
DIExpressionCursor &Expr, unsigned MachineReg,
unsigned FragmentOffsetInBits = 0);
+ /// Emit entry value dwarf operation.
+ void addEntryValueExpression(DIExpressionCursor &ExprCursor);
+
/// Emit all remaining operations in the DIExpressionCursor.
///
/// \param FragmentOffsetInBits If this is one fragment out of multiple
Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
+ Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
return Descriptions;
}
} else {
if (Signed)
OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
- else
+ else if (Opcode != DW_OP_entry_value &&
+ Opcode != DW_OP_GNU_entry_value)
OS << format(" 0x%" PRIx64, Operands[Operand]);
}
}
void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
DWARFUnit *U, bool IsEH) const {
+ uint32_t EntryValExprSize = 0;
for (auto &Op : *this) {
if (!Op.print(OS, this, RegInfo, U, IsEH)) {
uint32_t FailOffset = Op.getEndOffset();
OS << format(" %02x", Data.getU8(&FailOffset));
return;
}
+
+ if (Op.getCode() == DW_OP_entry_value ||
+ Op.getCode() == DW_OP_GNU_entry_value) {
+ OS << "(";
+ EntryValExprSize = Op.getRawOperand(0);
+ continue;
+ }
+
+ if (EntryValExprSize) {
+ EntryValExprSize--;
+ if (EntryValExprSize == 0)
+ OS << ")";
+ }
+
if (Op.getEndOffset() < Data.getData().size())
OS << ", ";
}
case dwarf::DW_OP_deref_size:
case dwarf::DW_OP_plus_uconst:
case dwarf::DW_OP_LLVM_tag_offset:
+ case dwarf::DW_OP_entry_value:
return 2;
default:
return 1;
return false;
break;
}
+ case dwarf::DW_OP_entry_value: {
+ // An entry value operator must appear at the begin and the size
+ // of following expression should be 1, because we support only
+ // entry values of a simple register location.
+ return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 &&
+ getNumElements() == 2;
+ }
case dwarf::DW_OP_LLVM_convert:
case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_constu:
Ops.push_back(dwarf::DW_OP_deref);
bool StackValue = Flags & DIExpression::StackValue;
+ bool EntryValue = Flags & DIExpression::EntryValue;
- return prependOpcodes(Expr, Ops, StackValue);
+ return prependOpcodes(Expr, Ops, StackValue, EntryValue);
}
DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr,
SmallVectorImpl<uint64_t> &Ops,
- bool StackValue) {
+ bool StackValue,
+ bool EntryValue) {
assert(Expr && "Can't prepend ops to this expression");
+ if (EntryValue) {
+ Ops.push_back(dwarf::DW_OP_entry_value);
+ // Add size info needed for entry value expression.
+ // Add plus one for target register operand.
+ Ops.push_back(Expr->getNumElements() + 1);
+ }
+
// If there are no ops to prepend, do not even add the DW_OP_stack_value.
if (Ops.empty())
StackValue = false;
--- /dev/null
+; RUN: not opt -S < %s 2>&1 | FileCheck %s
+
+!named = !{!0, !1, !2}
+; CHECK: invalid expression
+!0 = !DIExpression(DW_OP_entry_value, 4, DW_OP_constu, 0, DW_OP_stack_value)
+!1 = !DIExpression(DW_OP_constu, 0, DW_OP_entry_value, 1, DW_OP_constu, 0)
+!2 = !DIExpression(DW_OP_entry_value, 100, DW_OP_constu, 0)
--- /dev/null
+; RUN: opt -S < %s 2>&1 | FileCheck %s
+
+!named = !{!0}
+; CHECK-NOT: invalid expression
+!0 = !DIExpression(DW_OP_entry_value, 1)
--- /dev/null
+# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | llvm-dwarfdump - | FileCheck %s
+#
+# CHECK: DW_TAG_variable
+# CHECK-NEXT: DW_AT_name ("a")
+# CHECK-NEXT: DW_AT_location
+# CHECK-NEXT: DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value)
+
+ .section .debug_str,"MS",@progbits,1
+.Linfo_producer:
+ .asciz "hand-written DWARF"
+.Lname_a:
+ .asciz "a"
+
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+ .quad 0
+ .quad 1
+ .short .Lloc0_end-.Lloc0_start # Loc expr size
+.Lloc0_start:
+ .byte 243 # DW_OP_GNU_entry_value
+ .byte 1 # 1
+ .byte 85 # super-register DW_OP_reg5
+ .byte 159 # DW_OP_stack_value
+.Lloc0_end:
+ .quad 0
+ .quad 0
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 2 # DW_AT_location
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Lcu_end0-.Lcu_start0 # Length of Unit
+.Lcu_start0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .long .Linfo_producer # DW_AT_producer
+ .byte 5 # Abbrev [5] DW_TAG_variable
+ .long .Lname_a # DW_AT_name
+ .long .Ldebug_loc0 # DW_AT_location
+ .byte 0 # End Of Children Mark
+.Lcu_end0:
--- /dev/null
+# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | llvm-dwarfdump - | FileCheck %s
+#
+# CHECK: DW_TAG_variable
+# CHECK-NEXT: DW_AT_name ("a")
+# CHECK-NEXT: DW_AT_location
+# CHECK-NEXT: DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value)
+
+ .section .debug_str,"MS",@progbits,1
+.Linfo_producer:
+ .asciz "hand-written DWARF"
+.Lname_a:
+ .asciz "a"
+
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+ .quad 0
+ .quad 1
+ .short .Lloc0_end-.Lloc0_start # Loc expr size
+.Lloc0_start:
+ .byte 163 # DW_OP_entry_value
+ .byte 1 # 1
+ .byte 85 # super-register DW_OP_reg5
+ .byte 159 # DW_OP_stack_value
+.Lloc0_end:
+ .quad 0
+ .quad 0
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 2 # DW_AT_location
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Lcu_end0-.Lcu_start0 # Length of Unit
+.Lcu_start0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .long .Linfo_producer # DW_AT_producer
+ .byte 5 # Abbrev [5] DW_TAG_variable
+ .long .Lname_a # DW_AT_name
+ .long .Ldebug_loc0 # DW_AT_location
+ .byte 0 # End Of Children Mark
+.Lcu_end0: