summaryrefslogtreecommitdiff
path: root/debuginfo-tests/llgdb-tests
diff options
context:
space:
mode:
Diffstat (limited to 'debuginfo-tests/llgdb-tests')
-rw-r--r--debuginfo-tests/llgdb-tests/apple-accel.cpp24
-rw-r--r--debuginfo-tests/llgdb-tests/asan-blocks.c41
-rw-r--r--debuginfo-tests/llgdb-tests/asan-deque.cpp46
-rw-r--r--debuginfo-tests/llgdb-tests/asan.c31
-rw-r--r--debuginfo-tests/llgdb-tests/block_var.m32
-rw-r--r--debuginfo-tests/llgdb-tests/blocks.m43
-rw-r--r--debuginfo-tests/llgdb-tests/foreach.m31
-rw-r--r--debuginfo-tests/llgdb-tests/forward-declare-class.cpp27
-rw-r--r--debuginfo-tests/llgdb-tests/lit.local.cfg5
-rwxr-xr-xdebuginfo-tests/llgdb-tests/llgdb.py162
-rw-r--r--debuginfo-tests/llgdb-tests/nested-struct.cpp21
-rw-r--r--debuginfo-tests/llgdb-tests/nrvo-string.cpp52
-rw-r--r--debuginfo-tests/llgdb-tests/safestack.c52
-rw-r--r--debuginfo-tests/llgdb-tests/static-member-2.cpp39
-rw-r--r--debuginfo-tests/llgdb-tests/static-member.cpp36
-rwxr-xr-xdebuginfo-tests/llgdb-tests/test_debuginfo.pl81
16 files changed, 723 insertions, 0 deletions
diff --git a/debuginfo-tests/llgdb-tests/apple-accel.cpp b/debuginfo-tests/llgdb-tests/apple-accel.cpp
new file mode 100644
index 000000000000..4a73afe80113
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/apple-accel.cpp
@@ -0,0 +1,24 @@
+// REQUIRES: system-darwin
+// Test that clang produces the __apple accelerator tables,
+// e.g., __apple_types, correctly.
+// These sections are going to be retired in DWARF 5, so we hardcode
+// the DWARF version in the tests.
+// RUN: %clang %s %target_itanium_abi_host_triple -gdwarf-2 -O0 -c -g -o %t-ex
+// RUN: llvm-objdump -section-headers %t-ex | FileCheck %s
+// RUN: %clang %s %target_itanium_abi_host_triple -gdwarf-4 -O0 -c -g -o %t-ex
+// RUN: llvm-objdump -section-headers %t-ex | FileCheck %s
+
+// A function in a different section forces the compiler to create the
+// __debug_ranges section.
+__attribute__((section("1,__text_foo"))) void foo() {}
+int main (int argc, char const *argv[]) { return argc; }
+
+// CHECK: __debug_str
+// CHECK-NEXT: __debug_abbrev
+// CHECK-NEXT: __debug_info
+// CHECK-NEXT: __debug_ranges
+// CHECK-NEXT: __debug_macinfo
+// CHECK-NEXT: __apple_names
+// CHECK-NEXT: __apple_objc
+// CHECK-NEXT: __apple_namespac
+// CHECK-NEXT: __apple_types
diff --git a/debuginfo-tests/llgdb-tests/asan-blocks.c b/debuginfo-tests/llgdb-tests/asan-blocks.c
new file mode 100644
index 000000000000..33f44cd66590
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/asan-blocks.c
@@ -0,0 +1,41 @@
+// RUN: %clang -fblocks %target_itanium_abi_host_triple -arch x86_64 %s -o %t.out -g -fsanitize=address
+// RUN: %test_debuginfo %s %t.out
+// FIXME: Remove system-darwin when we build BlocksRuntime everywhere.
+// REQUIRES: !asan, system-darwin
+// Zorg configures the ASAN stage2 bots to not build the asan
+// compiler-rt. Only run this test on non-asanified configurations.
+void b();
+struct S {
+ int a[8];
+};
+
+int f(struct S s, unsigned i) {
+ // DEBUGGER: break 17
+ // DEBUGGER: r
+ // DEBUGGER: p s
+ // CHECK: a = ([0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7)
+ return s.a[i];
+}
+
+int main(int argc, const char **argv) {
+ struct S s = {{0, 1, 2, 3, 4, 5, 6, 7}};
+ if (f(s, 4) == 4) {
+ // DEBUGGER: break 27
+ // DEBUGGER: c
+ // DEBUGGER: p s
+ // CHECK: a = ([0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7)
+ b();
+ }
+ return 0;
+}
+
+void c() {}
+
+void b() {
+ // DEBUGGER: break 40
+ // DEBUGGER: c
+ // DEBUGGER: p x
+ // CHECK: 42
+ __block int x = 42;
+ c();
+}
diff --git a/debuginfo-tests/llgdb-tests/asan-deque.cpp b/debuginfo-tests/llgdb-tests/asan-deque.cpp
new file mode 100644
index 000000000000..f3f55aae0ff6
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/asan-deque.cpp
@@ -0,0 +1,46 @@
+// RUN: %clangxx -arch x86_64 %target_itanium_abi_host_triple -O1 -g %s -o %t.out -fsanitize=address
+// RUN: %test_debuginfo %s %t.out
+// REQUIRES: !asan
+// Zorg configures the ASAN stage2 bots to not build the asan
+// compiler-rt. Only run this test on non-asanified configurations.
+// UNSUPPORTED: apple-lldb-pre-1000
+#include <deque>
+
+struct A {
+ int a;
+ A(int a) : a(a) {}
+};
+
+using log_t = std::deque<A>;
+
+static void __attribute__((noinline, optnone)) escape(log_t &log) {
+ static volatile log_t *sink;
+ sink = &log;
+}
+
+int main() {
+ log_t log;
+ log.push_back(1234);
+ log.push_back(56789);
+ escape(log);
+ // DEBUGGER: break 25
+ while (!log.empty()) {
+ auto record = log.front();
+ log.pop_front();
+ escape(log);
+ // DEBUGGER: break 30
+ }
+}
+
+// DEBUGGER: r
+
+// (at line 25)
+// DEBUGGER: p log
+// CHECK: 1234
+// CHECK: 56789
+
+// DEBUGGER: c
+
+// (at line 30)
+// DEBUGGER: p log
+// CHECK: 56789
diff --git a/debuginfo-tests/llgdb-tests/asan.c b/debuginfo-tests/llgdb-tests/asan.c
new file mode 100644
index 000000000000..96dffb348d43
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/asan.c
@@ -0,0 +1,31 @@
+// RUN: %clang -fblocks %target_itanium_abi_host_triple -arch x86_64 %s -o %t.out -g -fsanitize=address
+// RUN: %test_debuginfo %s %t.out
+// REQUIRES: !asan
+// Zorg configures the ASAN stage2 bots to not build the asan
+// compiler-rt. Only run this test on non-asanified configurations.
+//
+
+struct S {
+ int a[8];
+};
+
+int f(struct S s, unsigned i) {
+ // DEBUGGER: break 14
+ return s.a[i];
+}
+
+int main(int argc, const char **argv) {
+ struct S s = {{0, 1, 2, 3, 4, 5, 6, 7}};
+ if (f(s, 4) == 4)
+ return f(s, 0);
+ return 0;
+}
+
+// DEBUGGER: r
+// DEBUGGER: p s
+// CHECK: a =
+// DEBUGGER: p s.a[0]
+// CHECK: = 0
+// DEBUGGER: p s.a[1]
+// CHECK: = 1
+// DEBUGGER: p s.a[7]
diff --git a/debuginfo-tests/llgdb-tests/block_var.m b/debuginfo-tests/llgdb-tests/block_var.m
new file mode 100644
index 000000000000..7ec786f17987
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/block_var.m
@@ -0,0 +1,32 @@
+// RUN: %clang %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
+// RUN: %clang %target_itanium_abi_host_triple %t.o -o %t.out -framework Foundation
+// RUN: %test_debuginfo %s %t.out
+
+// REQUIRES: system-darwin
+
+// DEBUGGER: break 24
+// DEBUGGER: r
+// DEBUGGER: p result
+// CHECK: ${{[0-9]}} = 42
+
+void doBlock(void (^block)(void))
+{
+ block();
+}
+
+int I(int n)
+{
+ __block int result;
+ int i = 2;
+ doBlock(^{
+ result = n;
+ });
+ return result + i; /* Check value of 'result' */
+}
+
+
+int main (int argc, const char * argv[]) {
+ return I(42);
+}
+
+
diff --git a/debuginfo-tests/llgdb-tests/blocks.m b/debuginfo-tests/llgdb-tests/blocks.m
new file mode 100644
index 000000000000..8e5a21213200
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/blocks.m
@@ -0,0 +1,43 @@
+// RUN: %clang %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
+// RUN: %clang %target_itanium_abi_host_triple %t.o -o %t.out -framework Foundation
+// RUN: %test_debuginfo %s %t.out
+
+// REQUIRES: system-darwin
+// Radar 9279956
+
+// DEBUGGER: break 31
+// DEBUGGER: r
+// DEBUGGER: p m2
+// CHECK: ${{[0-9]}} = 1
+// DEBUGGER: p dbTransaction
+// CHECK: ${{[0-9]}} = 0
+// DEBUGGER: p master
+// CHECK: ${{[0-9]}} = 0
+
+#include <Cocoa/Cocoa.h>
+
+extern void foo(void(^)(void));
+
+@interface A:NSObject @end
+@implementation A
+- (void) helper {
+ int master = 0;
+ __block int m2 = 0;
+ __block int dbTransaction = 0;
+ int (^x)(void) = ^(void) { (void) self;
+ (void) master;
+ (void) dbTransaction;
+ m2++;
+ return m2;
+ };
+ master = x();
+}
+@end
+
+void foo(void(^x)(void)) {}
+
+int main() {
+ A *a = [A alloc];
+ [a helper];
+ return 0;
+}
diff --git a/debuginfo-tests/llgdb-tests/foreach.m b/debuginfo-tests/llgdb-tests/foreach.m
new file mode 100644
index 000000000000..2e3c312c877c
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/foreach.m
@@ -0,0 +1,31 @@
+// RUN: %clang %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
+// RUN: %clang %target_itanium_abi_host_triple %t.o -o %t.out -framework Foundation
+// RUN: %test_debuginfo %s %t.out
+//
+// REQUIRES: system-darwin
+// Radar 8757124
+
+// DEBUGGER: break 25
+// DEBUGGER: r
+// DEBUGGER: po thing
+// CHECK: aaa
+
+#import <Foundation/Foundation.h>
+
+int main (int argc, const char * argv[]) {
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSArray *things = [NSArray arrayWithObjects:@"one", @"two", @"three" , nil];
+ for (NSString *thing in things) {
+ NSLog (@"%@", thing);
+ }
+
+ things = [NSArray arrayWithObjects:@"aaa", @"bbb", @"ccc" , nil];
+ for (NSString *thing in things) {
+ NSLog (@"%@", thing);
+ }
+ [pool release];
+ return 0;
+}
+
+
diff --git a/debuginfo-tests/llgdb-tests/forward-declare-class.cpp b/debuginfo-tests/llgdb-tests/forward-declare-class.cpp
new file mode 100644
index 000000000000..132420009bd1
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/forward-declare-class.cpp
@@ -0,0 +1,27 @@
+// RUN: %clangxx %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
+// RUN: %test_debuginfo %s %t.o
+// Radar 9168773
+
+// DEBUGGER: ptype A
+// Work around a gdb bug where it believes that a class is a
+// struct if there aren't any methods - even though it's tagged
+// as a class.
+// CHECK: type = {{struct|class}} A {
+// CHECK-NEXT: {{(public:){0,1}}}
+// CHECK-NEXT: int MyData;
+// CHECK-NEXT: }
+class A;
+class B {
+public:
+ void foo(const A *p);
+};
+
+B iEntry;
+
+class A {
+public:
+ int MyData;
+};
+
+A irp;
+
diff --git a/debuginfo-tests/llgdb-tests/lit.local.cfg b/debuginfo-tests/llgdb-tests/lit.local.cfg
new file mode 100644
index 000000000000..725aa59ab593
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/lit.local.cfg
@@ -0,0 +1,5 @@
+# debuginfo-tests are not expected to pass in a cross-compilation setup.
+if 'native' not in config.available_features or config.is_msvc:
+ config.unsupported = True
+
+
diff --git a/debuginfo-tests/llgdb-tests/llgdb.py b/debuginfo-tests/llgdb-tests/llgdb.py
new file mode 100755
index 000000000000..5f14497f628f
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/llgdb.py
@@ -0,0 +1,162 @@
+#!/bin/env python
+"""
+A gdb-compatible frontend for lldb that implements just enough
+commands to run the tests in the debuginfo-tests repository with lldb.
+"""
+
+# ----------------------------------------------------------------------
+# Auto-detect lldb python module.
+import commands, platform, os, sys
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup.
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform.
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # On Darwin, try the currently selected Xcode directory
+ xcode_dir = commands.getoutput("xcode-select --print-path")
+ if xcode_dir:
+ lldb_python_dirs.append(os.path.realpath(xcode_dir +
+'/../SharedFrameworks/LLDB.framework/Resources/Python'))
+ lldb_python_dirs.append(xcode_dir +
+'/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
+ lldb_python_dirs.append(
+'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
+ success = False
+ for lldb_python_dir in lldb_python_dirs:
+ if os.path.exists(lldb_python_dir):
+ if not (sys.path.__contains__(lldb_python_dir)):
+ sys.path.append(lldb_python_dir)
+ try:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+ sys.exit(1)
+# ----------------------------------------------------------------------
+
+# Command line option handling.
+import argparse
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('--quiet', '-q', action="store_true", help='ignored')
+parser.add_argument('-batch', action="store_true",
+ help='exit after processing comand line')
+parser.add_argument('-n', action="store_true", help='ignore .lldb file')
+parser.add_argument('-x', dest='script', type=file, help='execute commands from file')
+parser.add_argument("target", help="the program to debug")
+args = parser.parse_args()
+
+
+# Create a new debugger instance.
+debugger = lldb.SBDebugger.Create()
+debugger.SkipLLDBInitFiles(args.n)
+
+# Make sure to clean up the debugger on exit.
+import atexit
+def on_exit():
+ debugger.Terminate()
+atexit.register(on_exit)
+
+# Don't return from lldb function calls until the process stops.
+debugger.SetAsync(False)
+
+# Create a target from a file and arch.
+arch = os.popen("file "+args.target).read().split()[-1]
+target = debugger.CreateTargetWithFileAndArch(args.target, arch)
+
+if not target:
+ print "Could not create target", args.target
+ sys.exit(1)
+
+if not args.script:
+ print "Interactive mode is not implemented."
+ sys.exit(1)
+
+import re
+for command in args.script:
+ # Strip newline and whitespaces and split into words.
+ cmd = command[:-1].strip().split()
+ if not cmd:
+ continue
+
+ print '> %s'% command[:-1]
+
+ try:
+ if re.match('^r|(run)$', cmd[0]):
+ error = lldb.SBError()
+ launchinfo = lldb.SBLaunchInfo([])
+ launchinfo.SetWorkingDirectory(os.getcwd())
+ process = target.Launch(launchinfo, error)
+ print error
+ if not process or error.fail:
+ state = process.GetState()
+ print "State = %d" % state
+ print """
+ERROR: Could not launch process.
+NOTE: There are several reasons why this may happen:
+ * Root needs to run "DevToolsSecurity --enable".
+ * Older versions of lldb cannot launch more than one process simultaneously.
+"""
+ sys.exit(1)
+
+ elif re.match('^b|(break)$', cmd[0]) and len(cmd) == 2:
+ if re.match('[0-9]+', cmd[1]):
+ # b line
+ mainfile = target.FindFunctions('main')[0].compile_unit.file
+ print target.BreakpointCreateByLocation(mainfile, int(cmd[1]))
+ else:
+ # b file:line
+ file, line = cmd[1].split(':')
+ print target.BreakpointCreateByLocation(file, int(line))
+
+ elif re.match('^ptype$', cmd[0]) and len(cmd) == 2:
+ # GDB's ptype has multiple incarnations depending on its
+ # argument (global variable, function, type). The definition
+ # here is for looking up the signature of a function and only
+ # if that fails it looks for a type with that name.
+ # Type lookup in LLDB would be "image lookup --type".
+ for elem in target.FindFunctions(cmd[1]):
+ print elem.function.type
+ continue
+ print target.FindFirstType(cmd[1])
+
+ elif re.match('^po$', cmd[0]) and len(cmd) > 1:
+ try:
+ opts = lldb.SBExpressionOptions()
+ opts.SetFetchDynamicValue(True)
+ opts.SetCoerceResultToId(True)
+ print target.EvaluateExpression(' '.join(cmd[1:]), opts)
+ except:
+ # FIXME: This is a fallback path for the lab.llvm.org
+ # buildbot running OS X 10.7; it should be removed.
+ thread = process.GetThreadAtIndex(0)
+ frame = thread.GetFrameAtIndex(0)
+ print frame.EvaluateExpression(' '.join(cmd[1:]))
+
+ elif re.match('^p|(print)$', cmd[0]) and len(cmd) > 1:
+ thread = process.GetThreadAtIndex(0)
+ frame = thread.GetFrameAtIndex(0)
+ print frame.EvaluateExpression(' '.join(cmd[1:]))
+
+ elif re.match('^n|(next)$', cmd[0]):
+ thread = process.GetThreadAtIndex(0)
+ thread.StepOver()
+
+ elif re.match('^q|(quit)$', cmd[0]):
+ sys.exit(0)
+
+ else:
+ print debugger.HandleCommand(' '.join(cmd))
+
+ except SystemExit:
+ raise
+ except:
+ print 'Could not handle the command "%s"' % ' '.join(cmd)
+
diff --git a/debuginfo-tests/llgdb-tests/nested-struct.cpp b/debuginfo-tests/llgdb-tests/nested-struct.cpp
new file mode 100644
index 000000000000..7533e6a81518
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/nested-struct.cpp
@@ -0,0 +1,21 @@
+// RUN: %clangxx %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
+// RUN: %test_debuginfo %s %t.o
+// Radar 9440721
+// If debug info for my_number() is emitted outside function foo's scope
+// then a debugger may not be able to handle it. At least one version of
+// gdb crashes in such cases.
+
+// DEBUGGER: ptype foo
+// CHECK: int (void)
+
+int foo() {
+ struct Local {
+ static int my_number() {
+ return 42;
+ }
+ };
+
+ int i = 0;
+ i = Local::my_number();
+ return i + 1;
+}
diff --git a/debuginfo-tests/llgdb-tests/nrvo-string.cpp b/debuginfo-tests/llgdb-tests/nrvo-string.cpp
new file mode 100644
index 000000000000..ba8d9d42f6f4
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/nrvo-string.cpp
@@ -0,0 +1,52 @@
+// This ensures that DW_OP_deref is inserted when necessary, such as when NRVO
+// of a string object occurs in C++.
+//
+// RUN: %clangxx -O0 -fno-exceptions %target_itanium_abi_host_triple %s -o %t.out -g
+// RUN: %test_debuginfo %s %t.out
+// RUN: %clangxx -O1 -fno-exceptions %target_itanium_abi_host_triple %s -o %t.out -g
+// RUN: %test_debuginfo %s %t.out
+//
+// PR34513
+volatile int sideeffect = 0;
+void __attribute__((noinline)) stop() { sideeffect++; }
+
+struct string {
+ string() {}
+ string(int i) : i(i) {}
+ ~string() {}
+ int i = 0;
+};
+string get_string() {
+ string unused;
+ string result = 3;
+ // DEBUGGER: break 23
+ stop();
+ return result;
+}
+void some_function(int) {}
+struct string2 {
+ string2() = default;
+ string2(string2 &&other) { i = other.i; }
+ int i;
+};
+string2 get_string2() {
+ string2 result;
+ result.i = 5;
+ some_function(result.i);
+ // Test that the debugger can get the value of result after another
+ // function is called.
+ // DEBUGGER: break 39
+ stop();
+ return result;
+}
+int main() {
+ get_string();
+ get_string2();
+}
+
+// DEBUGGER: r
+// DEBUGGER: print result.i
+// CHECK: = 3
+// DEBUGGER: c
+// DEBUGGER: print result.i
+// CHECK: = 5
diff --git a/debuginfo-tests/llgdb-tests/safestack.c b/debuginfo-tests/llgdb-tests/safestack.c
new file mode 100644
index 000000000000..cf3efc75239a
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/safestack.c
@@ -0,0 +1,52 @@
+// RUN: %clang %target_itanium_abi_host_triple -arch x86_64 %s -o %t.out -g -fsanitize=safe-stack
+// RUN: %test_debuginfo %s %t.out
+// UNSUPPORTED: system-darwin
+// REQUIRES: !asan
+// Zorg configures the ASAN stage2 bots to not build the
+// safestack compiler-rt. Only run this test on
+// non-asanified configurations.
+
+struct S {
+ int a[8];
+};
+
+int f(struct S s, unsigned i);
+
+int main(int argc, const char **argv) {
+ struct S s = {{0, 1, 2, 3, 4, 5, 6, 7}};
+ // DEBUGGER: break 17
+ f(s, 4);
+ // DEBUGGER: break 19
+ return 0;
+}
+
+int f(struct S s, unsigned i) {
+ // DEBUGGER: break 24
+ return s.a[i];
+}
+
+// DEBUGGER: r
+// DEBUGGER: p s
+// CHECK: a =
+// DEBUGGER: p s.a[0]
+// CHECK: = 0
+// DEBUGGER: p s.a[1]
+// CHECK: = 1
+// DEBUGGER: p s.a[7]
+// CHECK: = 7
+// DEBUGGER: c
+// DEBUGGER: p s
+// CHECK: a =
+// DEBUGGER: p s.a[0]
+// CHECK: = 0
+// DEBUGGER: p s.a[1]
+// CHECK: = 1
+// DEBUGGER: p s.a[7]
+// DEBUGGER: c
+// DEBUGGER: p s
+// CHECK: a =
+// DEBUGGER: p s.a[0]
+// CHECK: = 0
+// DEBUGGER: p s.a[1]
+// CHECK: = 1
+// DEBUGGER: p s.a[7]
diff --git a/debuginfo-tests/llgdb-tests/static-member-2.cpp b/debuginfo-tests/llgdb-tests/static-member-2.cpp
new file mode 100644
index 000000000000..4edb2b060f1a
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/static-member-2.cpp
@@ -0,0 +1,39 @@
+// RUN: %clangxx %target_itanium_abi_host_triple -O0 -g %s -o %t -c
+// RUN: %clangxx %target_itanium_abi_host_triple %t -o %t.out
+// RUN: %test_debuginfo %s %t.out
+
+// FIXME: LLDB finds the wrong symbol for "C". rdar://problem/14933867
+// XFAIL: darwin
+
+// DEBUGGER: delete breakpoints
+// DEBUGGER: break static-member.cpp:33
+// DEBUGGER: r
+// DEBUGGER: ptype C
+// CHECK: {{struct|class}} C {
+// CHECK: static const int a;
+// CHECK-NEXT: static int b;
+// CHECK-NEXT: static int c;
+// CHECK-NEXT: int d;
+// CHECK-NEXT: }
+// DEBUGGER: p C::a
+// CHECK: ${{[0-9]}} = 4
+// DEBUGGER: p C::c
+// CHECK: ${{[0-9]}} = 15
+
+// PR14471, PR14734
+
+class C {
+public:
+ const static int a = 4;
+ static int b;
+ static int c;
+ int d;
+};
+
+int C::c = 15;
+const int C::a;
+
+int main() {
+ C instance_C;
+ return C::a;
+}
diff --git a/debuginfo-tests/llgdb-tests/static-member.cpp b/debuginfo-tests/llgdb-tests/static-member.cpp
new file mode 100644
index 000000000000..1d8ad62c5b88
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/static-member.cpp
@@ -0,0 +1,36 @@
+// RUN: %clangxx %target_itanium_abi_host_triple -O0 -g %s -o %t -c
+// RUN: %clangxx %target_itanium_abi_host_triple %t -o %t.out
+// RUN: %test_debuginfo %s %t.out
+
+// DEBUGGER: delete breakpoints
+// DEBUGGER: break static-member.cpp:33
+// DEBUGGER: r
+// DEBUGGER: ptype MyClass
+// CHECK: {{struct|class}} MyClass {
+// CHECK: static const int a;
+// CHECK-NEXT: static int b;
+// CHECK-NEXT: static int c;
+// CHECK-NEXT: int d;
+// CHECK-NEXT: }
+// DEBUGGER: p MyClass::a
+// CHECK: ${{[0-9]}} = 4
+// DEBUGGER: p MyClass::c
+// CHECK: ${{[0-9]}} = 15
+
+// PR14471, PR14734
+
+class MyClass {
+public:
+ const static int a = 4;
+ static int b;
+ static int c;
+ int d;
+};
+
+int MyClass::c = 15;
+const int MyClass::a;
+
+int main() {
+ MyClass instance_MyClass;
+ return MyClass::a;
+}
diff --git a/debuginfo-tests/llgdb-tests/test_debuginfo.pl b/debuginfo-tests/llgdb-tests/test_debuginfo.pl
new file mode 100755
index 000000000000..e4c2a5ea24c1
--- /dev/null
+++ b/debuginfo-tests/llgdb-tests/test_debuginfo.pl
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+#
+# This script tests debugging information generated by a compiler.
+# Input arguments
+# - Input source program. Usually this source file is decorated using
+# special comments to communicate debugger commands.
+# - Executable file. This file is generated by the compiler.
+#
+# This perl script extracts debugger commands from input source program
+# comments in a script. A debugger is used to load the executable file
+# and run the script generated from source program comments. Finally,
+# the debugger output is checked, using FileCheck, to validate
+# debugging information.
+#
+# On Darwin the default is to use the llgdb.py wrapper script which
+# translates gdb commands into their lldb equivalents.
+
+use File::Basename;
+use Config;
+use Cwd;
+
+my $testcase_file = $ARGV[0];
+my $executable_file = $ARGV[1];
+
+my $input_filename = basename $testcase_file;
+my $output_dir = dirname $executable_file;
+
+my $debugger_script_file = "$output_dir/$input_filename.debugger.script";
+my $output_file = "$output_dir/$input_filename.gdb.output";
+
+my %cmd_map = ();
+# Assume lldb to be the debugger on Darwin.
+my $use_lldb = 0;
+$use_lldb = 1 if ($Config{osname} eq "darwin");
+
+# Extract debugger commands from testcase. They are marked with DEBUGGER:
+# at the beginning of a comment line.
+open(INPUT, $testcase_file);
+open(OUTPUT, ">$debugger_script_file");
+while(<INPUT>) {
+ my($line) = $_;
+ $i = index($line, "DEBUGGER:");
+ if ( $i >= 0) {
+ $l = length("DEBUGGER:");
+ $s = substr($line, $i + $l);
+ print OUTPUT "$s";
+ }
+}
+print OUTPUT "\n";
+print OUTPUT "quit\n";
+close(INPUT);
+close(OUTPUT);
+
+# setup debugger and debugger options to run a script.
+my $my_debugger = $ENV{'DEBUGGER'};
+if (!$my_debugger) {
+ if ($use_lldb) {
+ my $path = dirname(Cwd::abs_path($0));
+ # At least on darwin, LLDB needs te system python.
+ $my_debugger = "/usr/bin/python $path/llgdb.py";
+ } else {
+ $my_debugger = "gdb";
+ }
+}
+
+# quiet / exit after cmdline / no init file / execute script
+my $debugger_options = "-q -batch -n -x";
+
+# run debugger and capture output.
+system("$my_debugger $debugger_options $debugger_script_file $executable_file > $output_file 2>&1");
+
+# validate output.
+system("FileCheck", "-input-file", "$output_file", "$testcase_file");
+if ($?>>8 == 1) {
+ print "Debugger output was:\n";
+ system("cat", "$output_file");
+ exit 1;
+}
+else {
+ exit 0;
+}