From: Djordje Todorovic Date: Thu, 27 Jun 2019 13:52:34 +0000 (+0000) Subject: [DWARF] Handle the DW_OP_entry_value operand X-Git-Tag: android-x86-9.0-r1~1224 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=192906bcfde8c1476bb6371e6d0d2411bdf73219;p=android-x86%2Fexternal-llvm.git [DWARF] Handle the DW_OP_entry_value operand Add the IR and the AsmPrinter parts for handling of the DW_OP_entry_values DWARF operation. ([11/13] Introduce the debug entry values.) Co-authored-by: Ananth Sowda Co-authored-by: Nikola Prica Co-authored-by: Ivan Baev Differential Revision: https://reviews.llvm.org/D60866 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364542 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 7b74971c817..2322bbfd7a6 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -4729,6 +4729,17 @@ The current supported opcode vocabulary is limited: 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 diff --git a/include/llvm/BinaryFormat/Dwarf.def b/include/llvm/BinaryFormat/Dwarf.def index 6506e04c659..b0f78d0fd61 100644 --- a/include/llvm/BinaryFormat/Dwarf.def +++ b/include/llvm/BinaryFormat/Dwarf.def @@ -633,6 +633,8 @@ HANDLE_DW_OP(0xa9, reinterpret, 5, DWARF) // 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) diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 429a38dc3f2..b1ac2767362 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -2482,11 +2482,12 @@ public: 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); @@ -2494,7 +2495,8 @@ public: /// stack value. static DIExpression *prependOpcodes(const DIExpression *Expr, SmallVectorImpl &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. @@ -2558,6 +2560,13 @@ public: 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, diff --git a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index 2435daa8861..ddd60575b6c 100644 --- a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -41,6 +41,10 @@ using EntryIndex = DbgValueHistoryMap::EntryIndex; 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(); diff --git a/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/lib/CodeGen/AsmPrinter/DebugLocEntry.h index b489220666b..17e39b3d326 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -66,6 +66,7 @@ public: 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 &); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 8e842f08bc0..71bb2b0858c 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1999,9 +1999,9 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, } } -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); @@ -2017,6 +2017,12 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, 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; @@ -2048,11 +2054,11 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, "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(); } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 012013901e6..3ac474e2bdd 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -52,6 +52,7 @@ class ByteStreamer; class DebugLocEntry; class DIE; class DwarfCompileUnit; +class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; class LexicalScope; @@ -735,6 +736,10 @@ public: 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 diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index d483a30e499..2858afaa1cf 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -248,6 +248,10 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, addReg(Reg.DwarfRegNo, Reg.Comment); addOpPiece(Reg.Size); } + + if (isEntryValue() && DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + DwarfRegs.clear(); return true; } @@ -296,6 +300,19 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, 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) { diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h index 3a9347a3e0a..ec2ef6e575f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -119,6 +119,9 @@ protected: /// 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; @@ -140,6 +143,10 @@ public: return LocationKind == Implicit; } + bool isEntryValue() const { + return LocationFlags & EntryValue; + } + Optional TagOffset; protected: @@ -252,6 +259,11 @@ public: 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. @@ -266,6 +278,9 @@ public: 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 diff --git a/lib/DebugInfo/DWARF/DWARFExpression.cpp b/lib/DebugInfo/DWARF/DWARFExpression.cpp index 644075011a3..470d4b5364b 100644 --- a/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -97,8 +97,10 @@ static DescVector getDescriptions() { 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; } @@ -275,7 +277,8 @@ bool DWARFExpression::Operation::print(raw_ostream &OS, } 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]); } } @@ -284,6 +287,7 @@ bool DWARFExpression::Operation::print(raw_ostream &OS, 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(); @@ -291,6 +295,20 @@ void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo, 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 << ", "; } diff --git a/lib/IR/DebugInfoMetadata.cpp b/lib/IR/DebugInfoMetadata.cpp index 76d9ce3332c..1607cf5104f 100644 --- a/lib/IR/DebugInfoMetadata.cpp +++ b/lib/IR/DebugInfoMetadata.cpp @@ -836,6 +836,7 @@ unsigned DIExpression::ExprOperand::getSize() const { 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; @@ -876,6 +877,13 @@ bool DIExpression::isValid() const { 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: @@ -994,15 +1002,24 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags, 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 &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; diff --git a/test/Verifier/diexpression-entry-value.ll b/test/Verifier/diexpression-entry-value.ll new file mode 100644 index 00000000000..477b20079aa --- /dev/null +++ b/test/Verifier/diexpression-entry-value.ll @@ -0,0 +1,7 @@ +; 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) diff --git a/test/Verifier/diexpression-valid-entry-value.ll b/test/Verifier/diexpression-valid-entry-value.ll new file mode 100644 index 00000000000..e162b8a50ed --- /dev/null +++ b/test/Verifier/diexpression-valid-entry-value.ll @@ -0,0 +1,5 @@ +; RUN: opt -S < %s 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK-NOT: invalid expression +!0 = !DIExpression(DW_OP_entry_value, 1) diff --git a/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s b/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s new file mode 100644 index 00000000000..90cfeda3eeb --- /dev/null +++ b/test/tools/llvm-dwarfdump/X86/debug_loc_OP_GNU_entry_value.s @@ -0,0 +1,59 @@ +# 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: diff --git a/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s b/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s new file mode 100644 index 00000000000..a5e246240ed --- /dev/null +++ b/test/tools/llvm-dwarfdump/X86/debug_loc_OP_entry_value.s @@ -0,0 +1,59 @@ +# 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: