Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -10,10 +10,14 @@ #include "DbgValueHistoryCalculator.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/DebugInfo.h" #include "llvm/Support/Debug.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" #include #include #include @@ -173,9 +177,32 @@ void calculateDbgValueHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &Result) { + const MachineFrameInfo *MFI = MF->getFrameInfo(); + std::set ChangingRegs; collectChangingRegs(MF, TRI, ChangingRegs); + // Try to eliminate the frame base register from the ChangingRegs + // set. On X86 at least, RSP is marked as clobbered by calls and + // this prevents the logic bellow to preserve the DbgValue liveness + // accross any call. We know for sure that frame base won't move, + // thus try to guess the frame base register for the current + // function by looking into the MachineFrameInfo. + if (MFI->hasStackObjects()) { + unsigned Reg; + const TargetFrameLowering *TFI = + MF->getTarget().getSubtargetImpl()->getFrameLowering(); + int MaxFI = MFI->getObjectIndexEnd(); + // Look for a live stack object (otherwise getFrameIndexReference might assert) + for (int FI = MFI->getObjectIndexBegin(); FI < MaxFI; ++FI) { + if (MFI->isDeadObjectIndex(FI)) + continue; + TFI->getFrameIndexReference(*MF, FI, Reg); + ChangingRegs.erase(Reg); + break; + } + } + RegDescribedVarsMap RegVars; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { Index: test/DebugInfo/X86/asan.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/asan.ll @@ -0,0 +1,888 @@ +; REQUIRES: object-emission +; RUN: llc -O0 -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; This test checks that location information for debug values addressing the +; stack is propagated to the end of the function. The X86 backend has the +; call instructions marked as clobbering RSP which makes calculateDbgValueHistory +; useless for DbgValues located on the stack. +; ASAN generated code, even without optimizations, is really impacted by that. + +; Test was compiled with -g -fsanitize=address. +; int foo(void); +; void *malloc(unsigned long); +; int printf(const char *, ...); +; +; int main(int argc, const char * argv[]) +; { +; int x = 100; +; void *t = malloc(x); +; int u = foo(); +; printf("%d %p %d\n", x, t, u); +; return 0; +; } + +; CHECK:.debug_info contents: +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_high_pc {{.*}} ([[HIGHPC:.*]]) +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_formal_parameter +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location {{.*}} ([[LOC_ARGC:.*]]) +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_formal_parameter +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location {{.*}} ([[LOC_ARGV:.*]]) +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location {{.*}} ([[LOC_X:.*]]) +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location {{.*}} ([[LOC_T:.*]]) +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location {{.*}} ([[LOC_U:.*]]) +; +; CHECK:.debug_loc contents: +; CHECK: [[LOC_ARGC]]: Beginning address offset: 0x0000000000000000 +; CHECK: Ending address offset: 0x[[ARGC_SPLIT:[0-9a-f]*]] +; CHECK: Beginning address offset: 0x[[ARGC_SPLIT]] +; CHECK: Ending address offset: [[HIGHPC]] +; +; CHECK: [[LOC_ARGV]]: Beginning address offset: 0x0000000000000000 +; CHECK: Ending address offset: 0x[[ARGV_SPLIT:[0-9a-f]*]] +; CHECK: Beginning address offset: 0x[[ARGV_SPLIT]] +; CHECK: Ending address offset: [[HIGHPC]] +; +; CHECK: [[LOC_X]]: Beginning address offset: 0x00000000{{[0-9a-f]*}} +; CHECK: Ending address offset: 0x[[X_SPLIT:[0-9a-f]*]] +; CHECK: Beginning address offset: 0x[[X_SPLIT]] +; CHECK: Ending address offset: [[HIGHPC]] +; +; CHECK: [[LOC_T]]: Beginning address offset: 0x00000000{{[0-9a-f]*}} +; CHECK: Ending address offset: 0x[[T_SPLIT:[0-9a-f]*]] +; CHECK: Beginning address offset: 0x[[T_SPLIT]] +; CHECK: Ending address offset: [[HIGHPC]] +; +; CHECK: [[LOC_U]]: Beginning address offset: 0x00000000{{[0-9a-f]*}} +; CHECK: Ending address offset: 0x[[U_SPLIT:[0-9a-f]*]] +; CHECK: Beginning address offset: 0x[[U_SPLIT]] +; CHECK: Ending address offset: [[HIGHPC]] + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10" + +%0 = type opaque +%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* } +%struct._objc_cache = type opaque +%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* } +%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] } +%struct._objc_method = type { i8*, i8*, i8* } +%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] } +%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8** } +%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] } +%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 } +%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] } +%struct._prop_t = type { i8*, i8* } +%struct.dispatch_queue_s = type opaque +%struct.__block_byref_a = type { i8*, %struct.__block_byref_a*, i32, i32, i8* } + +@"OBJC_CLASS_$_NSObject" = external global %struct._class_t +@"\01L_OBJC_CLASSLIST_REFERENCES_$_" = private global %struct._class_t* @"OBJC_CLASS_$_NSObject", section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 +@"\01L_OBJC_METH_VAR_NAME_" = private global [6 x i8] c"alloc\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +@"\01L_OBJC_SELECTOR_REFERENCES_" = private externally_initialized global i8* getelementptr inbounds ([6 x i8]* @"\01L_OBJC_METH_VAR_NAME_", i32 0, i32 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" +@"\01L_OBJC_METH_VAR_NAME_1" = private global [5 x i8] c"init\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +@"\01L_OBJC_SELECTOR_REFERENCES_2" = private externally_initialized global i8* getelementptr inbounds ([5 x i8]* @"\01L_OBJC_METH_VAR_NAME_1", i32 0, i32 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" +@.str = internal unnamed_addr constant { [16 x i8], [48 x i8] } { [16 x i8] c"%d, %p, %p, %p\0A\00", [48 x i8] zeroinitializer }, align 32 +@_dispatch_main_q = external global %struct.dispatch_queue_s +@llvm.compiler.used = appending global [5 x i8*] [i8* bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_" to i8*), i8* getelementptr inbounds ([6 x i8]* @"\01L_OBJC_METH_VAR_NAME_", i32 0, i32 0), i8* bitcast (i8** @"\01L_OBJC_SELECTOR_REFERENCES_" to i8*), i8* getelementptr inbounds ([5 x i8]* @"\01L_OBJC_METH_VAR_NAME_1", i32 0, i32 0), i8* bitcast (i8** @"\01L_OBJC_SELECTOR_REFERENCES_2" to i8*)], section "llvm.metadata" +@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 [160 x i8] c"10 32 4 6 retval 48 4 9 argc.addr 64 8 9 argv.addr 96 4 1 x 112 32 1 a 176 8 1 q 208 8 1 o 240 8 8 exn.slot 272 4 15 ehselector.slot 288 4 17 cleanup.dest.slot\00", align 1 +@__asan_gen_3 = private constant [7 x i8] c"asan.m\00", align 1 +@__asan_gen_4 = private unnamed_addr constant [17 x i8] c"\00", align 1 +@__asan_gen_5 = private unnamed_addr constant [7 x i8] c"asan.m\00", align 1 +@__asan_gen_6 = private unnamed_addr constant { [7 x i8]*, i32, i32 } { [7 x i8]* @__asan_gen_5, i32 9, i32 12 } +@0 = internal global [1 x { i64, i64, i64, i64, i64, i64, i64 }] [{ i64, i64, i64, i64, i64, i64, i64 } { i64 ptrtoint ({ [16 x i8], [48 x i8] }* @.str to i64), i64 16, i64 64, i64 ptrtoint ([17 x i8]* @__asan_gen_4 to i64), i64 ptrtoint ([7 x i8]* @__asan_gen_3 to i64), i64 0, i64 ptrtoint ({ [7 x i8]*, i32, i32 }* @__asan_gen_6 to i64) }] +@llvm.global_dtors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 1, void ()* @asan.module_dtor }] + +; Function Attrs: ssp sanitize_address uwtable +define i32 @main(i32 %argc, i8** %argv) #0 { +entry: + %MyAlloca = alloca [320 x i8], align 32 + %0 = ptrtoint [320 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 + +;