From b572f6421296e7688973014d253e46c54fd64ba3 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 26 Jul 2018 20:56:53 +0000 Subject: [DebugInfo] LowerDbgDeclare: Add derefs when handling CallInst users LowerDbgDeclare inserts a dbg.value before each use of an address described by a dbg.declare. When inserting a dbg.value before a CallInst use, however, it fails to append DW_OP_deref to the DIExpression. The DW_OP_deref is needed to reflect the fact that a dbg.value describes a source variable directly (as opposed to a dbg.declare, which relies on pointer indirection). This patch adds in the DW_OP_deref where needed. This results in the correct values being shown during a debug session for a program compiled with ASan and optimizations (see https://reviews.llvm.org/D49520). Note that ConvertDebugDeclareToDebugValue is already correct -- no changes there were needed. One complication is that SelectionDAG is unable to distinguish between direct and indirect frame-index (FRAMEIX) SDDbgValues. This patch also fixes this long-standing issue in order to not regress integration tests relying on the incorrect assumption that all frame-index SDDbgValues are indirect. This is a necessary fix: the newly-added DW_OP_derefs cannot be lowered properly otherwise. Basically the fix prevents a direct SDDbgValue with DIExpression(DW_OP_deref) from being dereferenced twice by a debugger. There were a handful of tests relying on this incorrect "FRAMEIX => indirect" assumption which actually had incorrect DW_AT_locations: these are all fixed up in this patch. Testing: - check-llvm, and an end-to-end test using lldb to debug an optimized program. - Existing unit tests for DIExpression::appendToStack fully cover the new DIExpression::append utility. - check-debuginfo (the debug info integration tests) Differential Revision: https://reviews.llvm.org/D49454 llvm-svn: 338069 --- llvm/lib/IR/DebugInfoMetadata.cpp | 59 ++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 20 deletions(-) (limited to 'llvm/lib/IR/DebugInfoMetadata.cpp') diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index db28d9a242b..910e8c2fb74 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -841,9 +841,37 @@ DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, return DIExpression::get(Expr->getContext(), Ops); } +DIExpression *DIExpression::append(const DIExpression *Expr, + ArrayRef Ops) { + assert(Expr && !Ops.empty() && "Can't append ops to this expression"); + + // Copy Expr's current op list. + SmallVector NewOps; + for (auto Op : Expr->expr_ops()) { + // Append new opcodes before DW_OP_{stack_value, LLVM_fragment}. + if (Op.getOp() == dwarf::DW_OP_stack_value || + Op.getOp() == dwarf::DW_OP_LLVM_fragment) { + NewOps.append(Ops.begin(), Ops.end()); + + // Ensure that the new opcodes are only appended once. + Ops = None; + } + Op.appendToVector(NewOps); + } + + NewOps.append(Ops.begin(), Ops.end()); + return DIExpression::get(Expr->getContext(), NewOps); +} + DIExpression *DIExpression::appendToStack(const DIExpression *Expr, ArrayRef Ops) { assert(Expr && !Ops.empty() && "Can't append ops to this expression"); + assert(none_of(Ops, + [](uint64_t Op) { + return Op == dwarf::DW_OP_stack_value || + Op == dwarf::DW_OP_LLVM_fragment; + }) && + "Can't append this op"); // Append a DW_OP_deref after Expr's current op list if it's non-empty and // has no DW_OP_stack_value. @@ -851,30 +879,21 @@ DIExpression *DIExpression::appendToStack(const DIExpression *Expr, // Match .* DW_OP_stack_value (DW_OP_LLVM_fragment A B)?. Optional FI = Expr->getFragmentInfo(); unsigned DropUntilStackValue = FI.hasValue() ? 3 : 0; - bool NeedsDeref = - (Expr->getNumElements() > DropUntilStackValue) && - (Expr->getElements().drop_back(DropUntilStackValue).back() != - dwarf::DW_OP_stack_value); - - // Copy Expr's current op list, add a DW_OP_deref if needed, and ensure that - // a DW_OP_stack_value is present. + ArrayRef ExprOpsBeforeFragment = + Expr->getElements().drop_back(DropUntilStackValue); + bool NeedsDeref = (Expr->getNumElements() > DropUntilStackValue) && + (ExprOpsBeforeFragment.back() != dwarf::DW_OP_stack_value); + bool NeedsStackValue = NeedsDeref || ExprOpsBeforeFragment.empty(); + + // Append a DW_OP_deref after Expr's current op list if needed, then append + // the new ops, and finally ensure that a single DW_OP_stack_value is present. SmallVector NewOps; - for (auto Op : Expr->expr_ops()) { - if (Op.getOp() == dwarf::DW_OP_stack_value || - Op.getOp() == dwarf::DW_OP_LLVM_fragment) - break; - Op.appendToVector(NewOps); - } if (NeedsDeref) NewOps.push_back(dwarf::DW_OP_deref); NewOps.append(Ops.begin(), Ops.end()); - NewOps.push_back(dwarf::DW_OP_stack_value); - - // If Expr is a fragment, make the new expression a fragment as well. - if (FI) - NewOps.append( - {dwarf::DW_OP_LLVM_fragment, FI->OffsetInBits, FI->SizeInBits}); - return DIExpression::get(Expr->getContext(), NewOps); + if (NeedsStackValue) + NewOps.push_back(dwarf::DW_OP_stack_value); + return DIExpression::append(Expr, NewOps); } Optional DIExpression::createFragmentExpression( -- cgit v1.2.3