Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -15,6 +15,7 @@ #include "llvm/Target/TargetRegisterInfo.h" #include #include +#include #define DEBUG_TYPE "dwarfdebug" @@ -51,9 +52,6 @@ auto &Ranges = VarInstrRanges[Var]; // Verify that the current instruction range is not yet closed. assert(!Ranges.empty() && Ranges.back().second == nullptr); - // For now, instruction ranges are not allowed to cross basic block - // boundaries. - assert(Ranges.back().first->getParent() == MI.getParent()); Ranges.back().second = &MI; } @@ -110,45 +108,41 @@ RegVars.erase(I); } -// \brief Terminate location ranges for all variables, described by registers -// clobbered by @MI. -static void clobberRegisterUses(RegDescribedVarsMap &RegVars, - const MachineInstr &MI, - const TargetRegisterInfo *TRI, - DbgValueHistoryMap &HistMap) { +// \brief Collect all registers clobbered by @MI and add them to @Regs. +static void collectClobberedRegisters(const MachineInstr &MI, + const TargetRegisterInfo *TRI, + std::set &Regs) { for (const MachineOperand &MO : MI.operands()) { if (!MO.isReg() || !MO.isDef() || !MO.getReg()) continue; - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) { - unsigned RegNo = *AI; - clobberRegisterUses(RegVars, RegNo, HistMap, MI); - } + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) + Regs.insert(*AI); } } -// \brief Terminate the location range for all register-described variables -// by inserting @ClobberingInstr to their history. -static void clobberAllRegistersUses(RegDescribedVarsMap &RegVars, - DbgValueHistoryMap &HistMap, - const MachineInstr &ClobberingInstr) { - for (const auto &I : RegVars) - for (const auto &Var : I.second) - HistMap.endInstrRange(Var, ClobberingInstr); - RegVars.clear(); -} - void calculateDbgValueHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &Result) { - RegDescribedVarsMap RegVars; + // Collect registers that are modified in the function body (their contents + // is changed after the frame setup and before the last basic block). + std::set ChangingRegs; + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { + if (!MI.getFlag(MachineInstr::FrameSetup) && &MBB != &MF->back()) + collectClobberedRegisters(MI, TRI, ChangingRegs); + } + } + RegDescribedVarsMap RegVars; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { if (!MI.isDebugValue()) { // Not a DBG_VALUE instruction. It may clobber registers which describe // some variables. - clobberRegisterUses(RegVars, MI, TRI, Result); + std::set MIClobberedRegs; + collectClobberedRegisters(MI, TRI, MIClobberedRegs); + for (unsigned RegNo : MIClobberedRegs) + clobberRegisterUses(RegVars, RegNo, Result, MI); continue; } @@ -167,8 +161,10 @@ // Make sure locations for register-described variables are valid only // until the end of the basic block (unless it's the last basic block, in // which case let their liveness run off to the end of the function). - if (!MBB.empty() && &MBB != &MF->back()) - clobberAllRegistersUses(RegVars, Result, MBB.back()); + if (!MBB.empty() && &MBB != &MF->back()) { + for (unsigned RegNo : ChangingRegs) + clobberRegisterUses(RegVars, RegNo, Result, MBB.back()); + } } } Index: test/DebugInfo/X86/debug-loc-asan.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/debug-loc-asan.ll @@ -0,0 +1,189 @@ +; RUN: llc -O0 -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s + +; Verify that we have correct debug info for local variables in code +; instrumented with AddressSanitizer. + +; Generated from the source file test.cc: +; int bar(int y) { +; return y + 2; +; } +; with "clang++ -S -emit-llvm -fsanitize=address -O0 -g test.cc" + +; First, argument variable "y" resides in %rdi: +; CHECK: DEBUG_VALUE: bar:y <- RDI + +; Then its address is stored in a location on a stack: +; CHECK: movq %rdi, [[OFFSET:[0-9]+]](%rsp) +; CHECK-NEXT: [[START_LABEL:.Ltmp[0-9]+]] +; CHECK-NEXT: DEBUG_VALUE: bar:y <- [RSP+[[OFFSET]]] + +; This location should be valid until the function epilogue: +; CHECK: movq %rbp, %rsp +; CHECK-NEXT: [[END_LABEL:.Ltmp[0-9]+]] + +; CHECK: .Ldebug_loc{{[0-9]+}}: +; We expect two location ranges for the variable. + +; First, it is stored in %rdi: +; CHECK: .Lset{{[0-9]+}} = .Lfunc_begin0-.Lfunc_begin0 +; CHECK-NEXT: .quad .Lset{{[0-9]+}} +; CHECK-NEXT: .Lset{{[0-9]+}} = [[START_LABEL]]-.Lfunc_begin0 +; CHECK-NEXT: .quad .Lset{{[0-9]+}} +; CHECK: DW_OP_reg5 + +; Then it's addressed via %rsp: +; CHECK: .Lset{{[0-9]+}} = [[START_LABEL]]-.Lfunc_begin0 +; CHECK-NEXT: .quad .Lset{{[0-9]+}} +; CHECK-NEXT: .Lset{{[0-9]+}} = [[END_LABEL]]-.Lfunc_begin0 +; CHECK-NEXT: .quad .Lset{{[0-9]+}} +; CHECK: DW_OP_breg7 +; CHECK-NEXT: [[OFFSET]] +; CHECK: DW_OP_deref + +; ModuleID = 'test.cc' +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 1, void ()* @asan.module_ctor }] +@__asan_option_detect_stack_use_after_return = external global i32 +@__asan_gen_ = private unnamed_addr constant [16 x i8] c"1 32 4 6 y.addr\00", align 1 + +; Function Attrs: nounwind sanitize_address uwtable +define i32 @_Z3bari(i32 %y) #0 { +entry: + %MyAlloca = alloca [64 x i8], align 32 + %0 = ptrtoint [64 x i8]* %MyAlloca to i64 + %1 = load i32* @__asan_option_detect_stack_use_after_return + %2 = icmp ne i32 %1, 0 + br i1 %2, label %3, label %5 + +;