--- /dev/null
+// XFAIL:*
+//// Suboptimal coverage, see description below.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder 'clang-c' --cflags "-O3 -glldb" -- %s
+
+//// Adapted from https://bugs.llvm.org/show_bug.cgi?id=34136#c1
+//// LowerDbgDeclare has since been updated to look through bitcasts. We still
+//// get suboptimal coverage at the beginning of 'main' though. For each local,
+//// LowerDbgDeclare inserts a dbg.value and a dbg.value+DW_OP_deref before the
+//// store (after the call to 'getint') and the call to 'alias' respectively.
+//// The first dbg.value describes the result of the 'getint' call, eventually
+//// becoming a register location. The second points back into the stack
+//// home. There is a gap in the coverage between the quickly clobbered register
+//// location and the stack location, even though the stack location is valid
+//// during that gap. For x86 we end up with this code at the start of main:
+//// 00000000004004b0 <main>:
+//// 4004b0: sub rsp,0x18
+//// 4004b4: mov edi,0x5
+//// 4004b9: call 400480 <getint>
+//// 4004be: mov DWORD PTR [rsp+0x14],eax
+//// 4004c2: mov edi,0x5
+//// 4004c7: call 400480 <getint>
+//// 4004cc: mov DWORD PTR [rsp+0x10],eax
+//// 4004d0: mov edi,0x5
+//// 4004d5: call 400480 <getint>
+//// 4004da: mov DWORD PTR [rsp+0xc],eax
+//// ...
+//// With these variable locations:
+//// DW_TAG_variable
+//// DW_AT_location (0x00000000:
+//// [0x00000000004004be, 0x00000000004004cc): DW_OP_reg0 RAX
+//// [0x00000000004004de, 0x0000000000400503): DW_OP_breg7 RSP+20)
+//// DW_AT_name ("x")
+//// ...
+//// DW_TAG_variable
+//// DW_AT_location (0x00000037:
+//// [0x00000000004004cc, 0x00000000004004da): DW_OP_reg0 RAX
+//// [0x00000000004004e8, 0x0000000000400503): DW_OP_breg7 RSP+16)
+//// DW_AT_name ("y")
+//// ...
+//// DW_TAG_variable
+//// DW_AT_location (0x0000006e:
+//// [0x00000000004004da, 0x00000000004004e8): DW_OP_reg0 RAX
+//// [0x00000000004004f2, 0x0000000000400503): DW_OP_breg7 RSP+12)
+//// DW_AT_name ("z")
+//// ...
+
+char g = 1;
+int five = 5;
+__attribute__((__noinline__))
+int getint(int x) {
+ g = x - 4;
+ return x * g;
+}
+
+__attribute__((__noinline__))
+void alias(char* c) {
+ g = *c;
+ *c = (char)five;
+}
+
+int main() {
+ int x = getint(5);
+ int y = getint(5); // DexLabel('s1')
+ int z = getint(5); // DexLabel('s2')
+ alias((char*)&x); // DexLabel('s3')
+ alias((char*)&y);
+ alias((char*)&z);
+ return 0; // DexLabel('s4')
+}
+
+// DexExpectWatchValue('x', '5', from_line='s1', to_line='s4')
+// DexExpectWatchValue('y', '5', from_line='s2', to_line='s4')
+// DexExpectWatchValue('z', '5', from_line='s3', to_line='s4')
--- /dev/null
+// XFAIL:*
+//// Suboptimal coverage, see inlined comments.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder 'clang-c' --cflags "-O3 -glldb" -- %s
+
+//// Adapted from https://bugs.llvm.org/show_bug.cgi?id=34136#c4
+
+int g;
+
+__attribute__((__noinline__))
+void esc(int* p) {
+ g = *p;
+ *p = 5;
+}
+
+__attribute__((__noinline__))
+void thing(int x) {
+ g = x;
+}
+
+__attribute__((__noinline__))
+int fun(int param) {
+ esc(¶m); //// alloca is live until here DexLabel('s1')
+ if (param == 0) { //// end of alloca live range
+ //// param is now a constant, but without lowering to dbg.value we can't
+ //// capture that and would still point to the stack slot that may even have
+ //// been reused by now.
+ ////
+ //// Right now we get suboptimal coverage for x86: the param load below is
+ //// CSE'd with the if condition.
+ //// Instcombine runs LowerDbgDeclare and inserts a dbg.value after the load.
+ //// SelectionDAG combines the load and cmp. We go from this IR:
+ //// %0 = load i32, i32* %param.addr, align 4, !dbg !42, !tbaa !20
+ //// call void @llvm.dbg.value(metadata i32 %0, ...
+ //// %cmp = icmp eq i32 %0, 0, !dbg !44
+ //// to this MIR:
+ //// DBG_VALUE $noreg, $noreg, !"param"...
+ //// CMP32mi8 %param.addr, 1, $noreg, 0, $noreg, 0, implicit-def $eflags, debug-location !44
+ thing(param);
+ }
+ return 0; // DexLabel('s2')
+}
+
+int main() {
+ return fun(5);
+}
+
+// DexExpectWatchValue('param', '5', from_line='s1', to_line='s2')
+
--- /dev/null
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder clang-c --cflags "-O2 -glldb" -- %s
+
+//// Check that we give good locations to a variable ('local') which is escaped
+//// down some control paths and not others. This example is handled well currently.
+
+int g;
+__attribute__((__noinline__))
+void leak(int *ptr) {
+ g = *ptr;
+ *ptr = 2;
+}
+
+__attribute__((__noinline__))
+int fun(int cond) {
+ int local = 0; // DexLabel('s1')
+ if (cond)
+ leak(&local);
+ else
+ local = 1;
+ return local; // DexLabel('s2')
+}
+
+int main() {
+ int a = fun(1);
+ int b = fun(0);
+ return a + b;
+}
+
+//// fun(1) fun(0)
+// DexExpectWatchValue('local', '0', '0', on_line='s1')
+// DexExpectWatchValue('local', '2', '1', on_line='s2')
--- /dev/null
+// XFAIL:*
+//// We don't yet support DW_OP_implicit_pointer in llvm.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder 'clang-c' --cflags "-O3 -glldb" -- %s
+
+//// Check that 'param' in 'fun' can be read throughout, and that 'pa' and 'pb'
+//// can be dereferenced in the debugger even if we can't provide the pointer
+//// value itself.
+
+int globa;
+int globb;
+
+//// A no-inline, read-only function with internal linkage is a good candidate
+//// for arg promotion.
+__attribute__((__noinline__))
+static void use_promote(const int* pa) {
+ //// Promoted args would be a good candidate for an DW_OP_implicit_pointer.
+ globa = *pa; // DexLabel('s2')
+}
+
+__attribute__((__always_inline__))
+static void use_inline(const int* pb) {
+ //// Inlined pointer to callee local would be a good candidate for an
+ //// DW_OP_implicit_pointer.
+ globb = *pb; // DexLabel('s3')
+}
+
+__attribute__((__noinline__))
+int fun(int param) {
+ volatile int step = 0; // DexLabel('s1')
+ use_promote(¶m);
+ use_inline(¶m);
+ return step; // DexLabel('s4')
+}
+
+int main() {
+ return fun(5);
+}
+
+// DexExpectWatchValue('param', 5, from_line='s1', to_line='s4')
+// DexExpectWatchValue('*pa', 5, on_line='s2')
+// DexExpectWatchValue('*pb', 5, on_line='s3')
--- /dev/null
+// XFAIL:*
+//// See PR47946.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder clang-c --cflags "-O2 -glldb" -- %s
+//
+//// Check that once-escaped variable 'param' can still be read after we
+//// perform inlining + mem2reg, and that we see the DSE'd value 255.
+
+
+int g;
+__attribute__((__always_inline__))
+static void use(int* p) {
+ g = *p;
+ *p = 255;
+ volatile int step = 0; // DexLabel('use1')
+}
+
+__attribute__((__noinline__))
+void fun(int param) {
+ //// Make sure first step is in 'fun'.
+ volatile int step = 0; // DexLabel('fun1')
+ use(¶m);
+ return; // DexLabel('fun2')
+}
+
+int main() {
+ fun(5);
+}
+
+/*
+# Expect param == 5 before stepping through inlined 'use'.
+DexExpectWatchValue('param', '5', on_line='fun1')
+
+# Expect param == 255 after assignment in inlined frame 'use'.
+DexExpectProgramState({
+ 'frames': [
+ { 'function': 'use',
+ 'location': { 'lineno': 'use1' },
+ },
+ { 'function': 'fun',
+ 'location': { 'lineno': 20 },
+ 'watches': { 'param': '255' }
+ },
+ ]
+})
+
+# Expect param == 255 after inlined call to 'use'.
+DexExpectWatchValue('param', '255', on_line='fun2')
+*/
--- /dev/null
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder clang-c --cflags "-O2 -glldb" -- %s
+//
+//// Check that the once-escaped variable 'param' can still be read after
+//// we perform inlining + mem2reg. See D89810 and D85555.
+
+int g;
+__attribute__((__always_inline__))
+static void use(int* p) {
+ g = *p;
+}
+
+__attribute__((__noinline__))
+void fun(int param) {
+ volatile int step1 = 0; // DexLabel('s1')
+ use(¶m);
+ volatile int step2 = 0; // DexLabel('s2')
+}
+
+int main() {
+ fun(5);
+}
+
+// DexExpectWatchValue('param', '5', from_line='s1', to_line='s2')
--- /dev/null
+// XFAIL: *
+//// Suboptimal coverage, see below.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder 'clang-c' --cflags "-O3 -glldb" -- %s
+
+//// Check that escaped local 'param' in function 'fun' has sensible debug info
+//// after the escaping function 'use' gets arg promotion (int* -> int). Currently
+//// we lose track of param after the loop header.
+
+int g = 0;
+//// A no-inline, read-only function with internal linkage is a good candidate
+//// for arg promotion.
+__attribute__((__noinline__))
+static void use(const int* p) {
+ //// Promoted args would be a good candidate for an DW_OP_implicit_pointer.
+ //// This desirable behaviour is checked for in the test implicit-ptr.c.
+ g = *p;
+}
+
+__attribute__((__noinline__))
+void do_thing(int x) {
+ g *= x;
+}
+
+__attribute__((__noinline__))
+int fun(int param) {
+ do_thing(0); // DexLabel('s2')
+ for (int i = 0; i < param; ++i) {
+ use(¶m);
+ }
+
+ //// x86 loop body looks like this, with param in ebx:
+ //// 4004b0: mov edi,ebx
+ //// 4004b2: call 4004d0 <_ZL3usePKi>
+ //// 4004b7: add ebp,0xffffffff
+ //// 4004ba: jne 4004b0 <_Z3funi+0x20>
+
+ //// But we lose track of param's location before the loop:
+ //// DW_TAG_formal_parameter
+ //// DW_AT_location (0x00000039:
+ //// [0x0000000000400490, 0x0000000000400495): DW_OP_reg5 RDI
+ //// [0x0000000000400495, 0x00000000004004a2): DW_OP_reg3 RBX)
+ //// DW_AT_name ("param")
+
+ return g; // DexLabel('s3')
+}
+
+int main() {
+ return fun(5);
+}
+
+// DexExpectWatchValue('*p', 5, 5, 5, 5, 5, on_line='s1')
+// DexExpectWatchValue('param', 5, from_line='s2', to_line='s3')
--- /dev/null
+// XFAIL:*
+//// Currently debug info for 'local' behaves, but 'plocal' dereferences to
+//// the incorrect value 0xFF after the call to esc.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder clang-c --cflags "-O2 -glldb" -- %s
+//
+//// Check that a pointer to a variable living on the stack dereferences to the
+//// variable value.
+
+int glob;
+__attribute__((__noinline__))
+void esc(int* p) {
+ glob = *p;
+ *p = 0xFF;
+}
+
+int main() {
+ int local = 0xA;
+ int *plocal = &local;
+ esc(plocal); // DexLabel('s1')
+ local = 0xB; //// DSE
+ return 0; // DexLabel('s2')
+}
+
+
+// DexExpectWatchValue('local', 0xA, on_line='s1')
+// DexExpectWatchValue('local', 0xB, on_line='s2')
+// DexExpectWatchValue('*plocal', 0xA, on_line='s1')
+// DexExpectWatchValue('*plocal', 0xB, on_line='s2')
+//// Ideally we should be able to observe the dead store to local (0xB) through
+//// plocal here.
+// DexExpectWatchValue('(local == *plocal)', 'true', from_line='s1', to_line='s2')
--- /dev/null
+// XFAIL:*
+//// Currently, LowerDbgDeclare doesn't lower dbg.declares pointing at allocas
+//// for structs.
+
+// REQUIRES: lldb
+// UNSUPPORTED: system-windows
+// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
+// RUN: --builder clang-c --cflags "-O2 -glldb" -- %s
+//
+//// Check debug-info for the escaped struct variable num is reasonable.
+
+#include <stdio.h>
+struct Nums { int a, b, c; };
+struct Nums glob;
+__attribute__((__noinline__))
+void esc(struct Nums* nums) {
+ glob = *nums;
+}
+
+__attribute__((__noinline__))
+int main() {
+ struct Nums nums = { .c=1 }; //// Dead store.
+ printf("s1 nums.c: %d\n", nums.c); // DexLabel('s1')
+
+ nums.c = 2; //// Killing store.
+ printf("s2 nums.c: %d\n", nums.c); // DexLabel('s2')
+
+ esc(&nums); //// Force nums to live on the stack.
+ return 0; // DexLabel('s3')
+}
+
+// DexExpectWatchValue('nums.c', '1', on_line='s1')
+// DexExpectWatchValue('nums.c', '2', from_line='s2', to_line='s3')