summaryrefslogtreecommitdiffstats
path: root/packages/Python/lldbsuite/test/tools
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
committerdim <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
commit78b9749c0a4ea980a8b934645da6ae98fcc665e8 (patch)
treedd2a1ddf0476664c2b823409c36cbccd52662ca7 /packages/Python/lldbsuite/test/tools
parent60cb593f9d55fa5ca7a5372b731f2330345b4b9a (diff)
downloadFreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.zip
FreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.tar.gz
Vendor import of lldb trunk r256945:
https://llvm.org/svn/llvm-project/lldb/trunk@256945
Diffstat (limited to 'packages/Python/lldbsuite/test/tools')
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/TestMiExit.py84
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/TestMiFile.py77
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/TestMiGdbSetShow.py190
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/TestMiLibraryLoaded.py33
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/TestMiPrompt.py54
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/TestMiBreak.py246
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/main.cpp27
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/control/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py457
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/control/main.cpp33
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/data/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/data/TestMiData.py337
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/data/main.cpp59
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiCliSupport.py206
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiInterpreterExec.py229
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/main.cpp19
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/lldbmi_testcase.py54
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/main.cpp19
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/signal/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/signal/TestMiSignal.py197
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/signal/main.cpp33
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/stack/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/stack/TestMiStack.py479
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/stack/main.cpp127
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py290
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/main.cpp15
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_error2
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_exit7
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py81
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp18
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp39
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h24
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp38
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/syntax/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/syntax/TestMiSyntax.py80
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/syntax/main.cpp17
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/target/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/target/TestMiTarget.py125
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/target/test_attach.cpp21
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/variable/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiGdbSetShowPrint.py227
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiVar.py396
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-mi/variable/main.cpp152
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/Makefile8
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGDBRemoteMemoryRead.py41
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAttach.py60
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAuxvSupport.py201
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteExpeditedRegisters.py144
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteKill.py53
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py179
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteRegisterState.py126
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py25
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py164
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_qThreadStopInfo.py150
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py116
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py1473
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubReverseConnect.py87
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubSetSID.py82
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py1299
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/Makefile8
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteAbort.py42
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteSegFault.py40
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/main.cpp39
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py843
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/main.cpp404
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py56
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp7
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/socket_packet_pump.py187
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/test/test_lldbgdbserverutils.py49
76 files changed, 10445 insertions, 0 deletions
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/Makefile
new file mode 100644
index 0000000..8a7102e
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiExit.py b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiExit.py
new file mode 100644
index 0000000..86a0a65
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiExit.py
@@ -0,0 +1,84 @@
+"""
+Test that the lldb-mi driver exits properly.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiExitTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_exit(self):
+ """Test that '-gdb-exit' terminates local debug session and exits."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -gdb-exit: try to exit and check that program is finished
+ self.runCmd("-gdb-exit")
+ self.expect("\^exit")
+ import pexpect
+ self.expect(pexpect.EOF)
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_quit(self):
+ """Test that 'quit' exits immediately."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test quit: try to exit and check that program is finished
+ self.runCmd("quit")
+ import pexpect
+ self.expect(pexpect.EOF)
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_q(self):
+ """Test that 'q' exits immediately."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test q: try to exit and check that program is finished
+ self.runCmd("q")
+ import pexpect
+ self.expect(pexpect.EOF)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiFile.py b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiFile.py
new file mode 100644
index 0000000..8b4eac1
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiFile.py
@@ -0,0 +1,77 @@
+"""
+Test lldb-mi -file-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiFileTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_file_exec_and_symbols_file(self):
+ """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols exe."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -file-exec-and-symbols works for filename
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_file_exec_and_symbols_absolute_path(self):
+ """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols fullpath/exe."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -file-exec-and-symbols works for absolute path
+ import os
+ path = os.path.join(os.getcwd(), self.myexe)
+ self.runCmd("-file-exec-and-symbols \"%s\"" % path)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_file_exec_and_symbols_relative_path(self):
+ """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols relpath/exe."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -file-exec-and-symbols works for relative path
+ path = "./%s" % self.myexe
+ self.runCmd("-file-exec-and-symbols %s" % path)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_file_exec_and_symbols_unknown_path(self):
+ """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols badpath/exe."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -file-exec-and-symbols fails on unknown path
+ path = "unknown_dir/%s" % self.myexe
+ self.runCmd("-file-exec-and-symbols %s" % path)
+ self.expect("\^error")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiGdbSetShow.py b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiGdbSetShow.py
new file mode 100644
index 0000000..ab3eb1f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiGdbSetShow.py
@@ -0,0 +1,190 @@
+"""
+Test lldb-mi -gdb-set and -gdb-show commands.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiGdbSetShowTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_set_target_async_default(self):
+ """Test that 'lldb-mi --interpreter' switches to async mode by default."""
+
+ self.spawnLldbMi(args = None)
+
+ # Switch to sync mode
+ self.runCmd("-gdb-set target-async off")
+ self.expect("\^done")
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"off\"")
+
+ # Test that -gdb-set switches to async by default
+ self.runCmd("-gdb-set target-async")
+ self.expect("\^done")
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"on\"")
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFlakeyLinux("llvm.org/pr26028") # Fails in ~1% of cases
+ def test_lldbmi_gdb_set_target_async_on(self):
+ """Test that 'lldb-mi --interpreter' can execute commands in async mode."""
+
+ self.spawnLldbMi(args = None)
+
+ # Switch to sync mode
+ self.runCmd("-gdb-set target-async off")
+ self.expect("\^done")
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"off\"")
+
+ # Test that -gdb-set can switch to async mode
+ self.runCmd("-gdb-set target-async on")
+ self.expect("\^done")
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"on\"")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that program is executed in async mode
+ self.runCmd("-exec-run")
+ self.expect("\*running")
+ self.expect("@\"argc=1")
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # Failing in ~11/600 dosep runs (build 3120-3122)
+ def test_lldbmi_gdb_set_target_async_off(self):
+ """Test that 'lldb-mi --interpreter' can execute commands in sync mode."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -gdb-set can switch to sync mode
+ self.runCmd("-gdb-set target-async off")
+ self.expect("\^done")
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"off\"")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that program is executed in async mode
+ self.runCmd("-exec-run")
+ unexpected = [ "\*running" ] # "\*running" is async notification
+ it = self.expect(unexpected + [ "@\"argc=1\\\\r\\\\n" ])
+ if it < len(unexpected):
+ self.fail("unexpected found: %s" % unexpected[it])
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_show_target_async(self):
+ """Test that 'lldb-mi --interpreter' in async mode by default."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that default target-async value is "on"
+ self.runCmd("-gdb-show target-async")
+ self.expect("\^done,value=\"on\"")
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_show_language(self):
+ """Test that 'lldb-mi --interpreter' can get current language."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -gdb-show language gets current language
+ self.runCmd("-gdb-show language")
+ self.expect("\^done,value=\"c\+\+\"")
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @unittest2.expectedFailure("-gdb-set ignores unknown properties")
+ def test_lldbmi_gdb_set_unknown(self):
+ """Test that 'lldb-mi --interpreter' fails when setting an unknown property."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -gdb-set fails if property is unknown
+ self.runCmd("-gdb-set unknown some_value")
+ self.expect("\^error")
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @unittest2.expectedFailure("-gdb-show ignores unknown properties")
+ def test_lldbmi_gdb_show_unknown(self):
+ """Test that 'lldb-mi --interpreter' fails when showing an unknown property."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -gdb-show fails if property is unknown
+ self.runCmd("-gdb-show unknown")
+ self.expect("\^error")
+
+
+ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_gdb_set_ouptut_radix(self):
+ """Test that 'lldb-mi --interpreter' works for -gdb-set output-radix."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_printf
+ line = line_number('main.cpp', '// BP_printf')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running");
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Setup variable
+ self.runCmd("-var-create var_a * a");
+ self.expect("\^done,name=\"var_a\",numchild=\"0\",value=\"10\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test default output
+ self.runCmd("-var-evaluate-expression var_a");
+ self.expect("\^done,value=\"10\"");
+
+ # Test hex output
+ self.runCmd("-gdb-set output-radix 16");
+ self.expect("\^done");
+ self.runCmd("-var-evaluate-expression var_a");
+ self.expect("\^done,value=\"0xa\"");
+
+ # Test octal output
+ self.runCmd("-gdb-set output-radix 8");
+ self.expect("\^done");
+ self.runCmd("-var-evaluate-expression var_a");
+ self.expect("\^done,value=\"012\"");
+
+ # Test decimal output
+ self.runCmd("-gdb-set output-radix 10");
+ self.expect("\^done");
+ self.runCmd("-var-evaluate-expression var_a");
+ self.expect("\^done,value=\"10\"");
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiLibraryLoaded.py b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiLibraryLoaded.py
new file mode 100644
index 0000000..4d9c935
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiLibraryLoaded.py
@@ -0,0 +1,33 @@
+"""
+Test lldb-mi =library-loaded notifications.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiLibraryLoadedTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_library_loaded(self):
+ """Test that 'lldb-mi --interpreter' shows the =library-loaded notifications."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test =library-loaded
+ import os
+ path = os.path.join(os.getcwd(), self.myexe)
+ symbols_path = os.path.join(path + ".dSYM", "Contents", "Resources", "DWARF", self.myexe)
+ def add_slashes(x): return x.replace("\\", "\\\\").replace("\"", "\\\"").replace("\'", "\\\'").replace("\0", "\\\0")
+ self.expect([ "=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded=\"1\",symbols-path=\"%s\",loaded_addr=\"-\",size=\"[0-9]+\"" % (add_slashes(path), add_slashes(path), add_slashes(path), add_slashes(symbols_path)),
+ "=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded=\"0\",loaded_addr=\"-\",size=\"[0-9]+\"" % (add_slashes(path), add_slashes(path), add_slashes(path)) ])
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiPrompt.py b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiPrompt.py
new file mode 100644
index 0000000..d810267
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/TestMiPrompt.py
@@ -0,0 +1,54 @@
+"""
+Test that the lldb-mi driver prints prompt properly.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiPromptTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_prompt(self):
+ """Test that 'lldb-mi --interpreter' echos '(gdb)' after commands and events."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that lldb-mi is ready after unknown command
+ self.runCmd("-unknown-command")
+ self.expect("\^error,msg=\"Driver\. Received command '-unknown-command'\. It was not handled\. Command 'unknown-command' not in Command Factory\"")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after -file-exec-and-symbols
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after -break-insert
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after -exec-run
+ self.runCmd("-exec-run")
+ self.expect("\*running")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after BP hit
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after -exec-continue
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect(self.child_prompt, exactly = True)
+
+ # Test that lldb-mi is ready after program exited
+ self.expect("\*stopped,reason=\"exited-normally\"")
+ self.expect(self.child_prompt, exactly = True)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/TestMiBreak.py b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/TestMiBreak.py
new file mode 100644
index 0000000..020954f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/TestMiBreak.py
@@ -0,0 +1,246 @@
+"""
+Test lldb-mi -break-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiBreakTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_break_insert_function_pending(self):
+ """Test that 'lldb-mi --interpreter' works for pending function breakpoints."""
+
+ self.spawnLldbMi(args = None)
+
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ self.runCmd("-break-insert -f printf")
+ #FIXME function name is unknown on Darwin, fullname should be ??, line is -1
+ #self.expect("\^done,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"0xffffffffffffffff\",func=\"printf\",file=\"\?\?\",fullname=\"\?\?\",line=\"-1\",pending=\[\"printf\"\],times=\"0\",original-location=\"printf\"}")
+ self.expect("\^done,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"0xffffffffffffffff\",func=\"\?\?\",file=\"\?\?\",fullname=\"\?\?/\?\?\",line=\"0\",pending=\[\"printf\"\],times=\"0\",original-location=\"printf\"}")
+ #FIXME function name is unknown on Darwin, fullname should be ??, line -1
+ #self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"0xffffffffffffffff\",func=\"printf\",file=\"\?\?\",fullname=\"\?\?\",line=\"-1\",pending=\[\"printf\"\],times=\"0\",original-location=\"printf\"}")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"0xffffffffffffffff\",func=\"\?\?\",file=\"\?\?\",fullname=\"\?\?/\?\?\",line=\"0\",pending=\[\"printf\"\],times=\"0\",original-location=\"printf\"}")
+
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\".+?\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",pending=\[\"printf\"\],times=\"0\",original-location=\"printf\"}")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_break_insert_function(self):
+ """Test that 'lldb-mi --interpreter' works for function breakpoints."""
+
+ self.spawnLldbMi(args = None)
+
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",pending=\[\"main\"\],times=\"0\",original-location=\"main\"}")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",pending=\[\"main\"\],times=\"0\",original-location=\"main\"}")
+
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",pending=\[\"main\"\],times=\"0\",original-location=\"main\"}")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -break-insert can set non-pending BP
+ self.runCmd("-break-insert printf")
+ #FIXME function name is unknown on Darwin
+ #self.expect("\^done,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"printf\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+ self.expect("\^done,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\".+?\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+ #FIXME function name is unknown on Darwin
+ #self.expect("=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"printf\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+ self.expect("=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\".+?\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+ # FIXME function name is unknown on Darwin
+ #self.expect("=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"printf\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+ self.expect("=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\".+?\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\",times=\"0\",original-location=\"printf\"}")
+
+ # Test that -break-insert fails if non-pending BP can't be resolved
+ self.runCmd("-break-insert unknown_func")
+ self.expect("\^error,msg=\"Command 'break-insert'. Breakpoint location 'unknown_func' not found\"")
+
+ # Test that non-pending BP was set correctly
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\".*bkptno=\"2\"")
+
+ # Test that we can set a BP using the file:func syntax
+ self.runCmd("-break-insert main.cpp:main")
+ self.expect("\^done,bkpt={number=\"4\"")
+ self.runCmd("-break-insert main.cpp:ns::foo1")
+ self.expect("\^done,bkpt={number=\"5\"")
+ #FIXME: quotes on filenames aren't handled correctly in lldb-mi.
+ #self.runCmd("-break-insert \"main.cpp\":main")
+ #self.expect("\^done,bkpt={number=\"6\"")
+
+ # We should hit BP #5 on 'main.cpp:ns::foo1'
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\".*bkptno=\"5\"")
+
+ #FIXME: this test is disabled due to lldb bug llvm.org/pr24271.
+ # Test that we can set a BP using the global namespace token
+ #self.runCmd("-break-insert ::main")
+ #self.expect("\^done,bkpt={number=\"7\"")
+ #self.runCmd("-break-insert main.cpp:::main")
+ #self.expect("\^done,bkpt={number=\"8\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_break_insert_file_line_pending(self):
+ """Test that 'lldb-mi --interpreter' works for pending file:line breakpoints."""
+
+ self.spawnLldbMi(args = None)
+
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Find the line number to break inside main() and set
+ # pending BP
+ line = line_number('main.cpp', '// BP_return')
+ self.runCmd("-break-insert -f main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"%d\",pending=\[\"main.cpp:%d\"\],times=\"0\",original-location=\"main.cpp:%d\"}" % (line, line, line))
+ self.expect("=breakpoint-modified,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"%d\",pending=\[\"main.cpp:%d\"\],times=\"0\",original-location=\"main.cpp:%d\"}" % (line, line, line))
+
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_break_insert_file_line(self):
+ """Test that 'lldb-mi --interpreter' works for file:line breakpoints."""
+
+ self.spawnLldbMi(args = None)
+
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -break-insert can set non-pending BP
+ line = line_number('main.cpp', '// BP_return')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"%d\",times=\"0\",original-location=\"main.cpp:%d\"}" % (line, line))
+ self.expect("=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"%d\",times=\"0\",original-location=\"main.cpp:%d\"}" % (line, line))
+
+ # Test that -break-insert fails if non-pending BP can't be resolved
+ self.runCmd("-break-insert unknown_file:1")
+ self.expect("\^error,msg=\"Command 'break-insert'. Breakpoint location 'unknown_file:1' not found\"")
+
+ # Test that non-pending BP was set correctly
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @unittest2.expectedFailure("-break-insert doesn't work for absolute path")
+ def test_lldbmi_break_insert_file_line_absolute_path(self):
+ """Test that 'lldb-mi --interpreter' works for file:line breakpoints."""
+
+ self.spawnLldbMi(args = None)
+
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ import os
+ path = os.path.join(os.getcwd(), "main.cpp")
+ line = line_number('main.cpp', '// BP_return')
+ self.runCmd("-break-insert %s:%d" % (path, line))
+ self.expect("\^done,bkpt={number=\"2\"")
+
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_break_insert_settings(self):
+ """Test that 'lldb-mi --interpreter' can set breakpoints accoridng to global options."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set target.move-to-nearest-code=off and try to set BP #1 that shouldn't be hit
+ self.runCmd("-interpreter-exec console \"settings set target.move-to-nearest-code off\"")
+ self.expect("\^done")
+ line = line_number('main.cpp', '// BP_before_main')
+ self.runCmd("-break-insert -f main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Test that non-pending BP will not be set on non-existing line if target.move-to-nearest-code=off
+ # Note: this increases the BP number by 1 even though BP #2 is invalid.
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^error,msg=\"Command 'break-insert'. Breakpoint location 'main.cpp:%d' not found\"" % line)
+
+ # Set target.move-to-nearest-code=on and target.skip-prologue=on and set BP #3
+ self.runCmd("-interpreter-exec console \"settings set target.move-to-nearest-code on\"")
+ self.runCmd("-interpreter-exec console \"settings set target.skip-prologue on\"")
+ self.expect("\^done")
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"3\"")
+
+ # Set target.skip-prologue=off and set BP #4
+ self.runCmd("-interpreter-exec console \"settings set target.skip-prologue off\"")
+ self.expect("\^done")
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"4\"")
+
+ # Test that BP #4 is located before BP #3
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"4\"")
+
+ # Test that BP #3 is hit
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"3\"")
+
+ # Test that the target.language=pascal setting works and that BP #5 is NOT set
+ self.runCmd("-interpreter-exec console \"settings set target.language c\"")
+ self.expect("\^done")
+ self.runCmd("-break-insert ns.foo1")
+ self.expect("\^error")
+
+ # Test that the target.language=c++ setting works and that BP #6 is hit
+ self.runCmd("-interpreter-exec console \"settings set target.language c++\"")
+ self.expect("\^done")
+ self.runCmd("-break-insert ns::foo1")
+ self.expect("\^done,bkpt={number=\"6\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"6\"")
+
+ # Test that BP #1 and #2 weren't set by running to program exit
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/main.cpp
new file mode 100644
index 0000000..9416a0d
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/main.cpp
@@ -0,0 +1,27 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+namespace ns
+{
+ int foo1(void) { printf("In foo1\n"); return 1; }
+ int foo2(void) { printf("In foo2\n"); return 2; }
+}
+
+// BP_before_main
+
+int x;
+int
+main(int argc, char const *argv[])
+{
+ printf("Print a formatted string so that GCC does not optimize this printf call: %s\n", argv[0]);
+ x = ns::foo1() + ns::foo2();
+ return 0; // BP_return
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/control/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/control/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/control/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py b/packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py
new file mode 100644
index 0000000..742bbc8
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py
@@ -0,0 +1,457 @@
+"""
+Test lldb-mi -exec-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiExecTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # llvm.org/pr25000: lldb-mi does not receive broadcasted notification from Core/Process about process stopped
+ def test_lldbmi_exec_run(self):
+ """Test that 'lldb-mi --interpreter' can stop at entry."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that program is stopped at entry
+ self.runCmd("-exec-run --start")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",.*?thread-id=\"1\",stopped-threads=\"all\"")
+ # Test that lldb-mi is ready to execute next commands
+ self.expect(self.child_prompt, exactly = True)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_abort(self):
+ """Test that 'lldb-mi --interpreter' works for -exec-abort."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -exec-abort fails on invalid process
+ self.runCmd("-exec-abort")
+ self.expect("\^error,msg=\"Command 'exec-abort'\. Invalid process during debug session\"")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set arguments
+ self.runCmd("-exec-arguments arg1")
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that arguments were passed
+ self.runCmd("-data-evaluate-expression argc")
+ self.expect("\^done,value=\"2\"")
+
+ # Test that program may be aborted
+ self.runCmd("-exec-abort")
+ self.expect("\^done")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ # Test that program can be run again
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that arguments were passed again
+ self.runCmd("-data-evaluate-expression argc")
+ self.expect("\^done,value=\"2\"")
+
+ # Test that program may be aborted again
+ self.runCmd("-exec-abort")
+ self.expect("\^done")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_arguments_set(self):
+ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set arguments
+ self.runCmd("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"")
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Check argc and argv to see if arg passed
+ self.runCmd("-data-evaluate-expression argc")
+ self.expect("\^done,value=\"5\"")
+ #self.runCmd("-data-evaluate-expression argv[1]")
+ #self.expect("\^done,value=\"--arg1\"")
+ self.runCmd("-interpreter-exec command \"print argv[1]\"")
+ self.expect("\"--arg1\"")
+ #self.runCmd("-data-evaluate-expression argv[2]")
+ #self.expect("\^done,value=\"2nd arg\"")
+ self.runCmd("-interpreter-exec command \"print argv[2]\"")
+ self.expect("\"2nd arg\"")
+ #self.runCmd("-data-evaluate-expression argv[3]")
+ #self.expect("\^done,value=\"third_arg\"")
+ self.runCmd("-interpreter-exec command \"print argv[3]\"")
+ self.expect("\"third_arg\"")
+ #self.runCmd("-data-evaluate-expression argv[4]")
+ #self.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"")
+ self.runCmd("-interpreter-exec command \"print argv[4]\"")
+ self.expect("\"fourth=\\\\\\\"4th arg\\\\\\\"\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_arguments_reset(self):
+ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set arguments
+ self.runCmd("-exec-arguments arg1")
+ self.expect("\^done")
+ self.runCmd("-exec-arguments")
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Check argc to see if arg passed
+ self.runCmd("-data-evaluate-expression argc")
+ self.expect("\^done,value=\"1\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_next(self):
+ """Test that 'lldb-mi --interpreter' works for stepping."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Warning: the following is sensitive to the lines in the source
+
+ # Test -exec-next
+ self.runCmd("-exec-next --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"29\"")
+
+ # Test that --thread is optional
+ self.runCmd("-exec-next --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"30\"")
+
+ # Test that --frame is optional
+ self.runCmd("-exec-next --thread 1")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"31\"")
+
+ # Test that both --thread and --frame are optional
+ self.runCmd("-exec-next")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"32\"")
+
+ # Test that an invalid --thread is handled
+ self.runCmd("-exec-next --thread 0")
+ self.expect("\^error,message=\"error: Thread index 0 is out of range")
+ self.runCmd("-exec-next --thread 10")
+ self.expect("\^error,message=\"error: Thread index 10 is out of range")
+
+ # Test that an invalid --frame is handled
+ # FIXME: no error is returned
+ self.runCmd("-exec-next --frame 10")
+ #self.expect("\^error: Frame index 10 is out of range")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailurei386 #xfail to get buildbot green, failing config: i386 binary running on ubuntu 14.04 x86_64
+ def test_lldbmi_exec_next_instruction(self):
+ """Test that 'lldb-mi --interpreter' works for instruction stepping."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Warning: the following is sensitive to the lines in the
+ # source and optimizations
+
+ # Test -exec-next-instruction
+ self.runCmd("-exec-next-instruction --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"28\"")
+
+ # Test that --thread is optional
+ self.runCmd("-exec-next-instruction --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"28\"")
+
+ # Test that --frame is optional
+ self.runCmd("-exec-next-instruction --thread 1")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"29\"")
+
+ # Test that both --thread and --frame are optional
+ self.runCmd("-exec-next-instruction")
+ self.expect("\^running")
+ # Depending on compiler, it can stop at different line
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"(29|30)\"")
+
+ # Test that an invalid --thread is handled
+ self.runCmd("-exec-next-instruction --thread 0")
+ self.expect("\^error,message=\"error: Thread index 0 is out of range")
+ self.runCmd("-exec-next-instruction --thread 10")
+ self.expect("\^error,message=\"error: Thread index 10 is out of range")
+
+ # Test that an invalid --frame is handled
+ # FIXME: no error is returned
+ self.runCmd("-exec-next-instruction --frame 10")
+ #self.expect("\^error: Frame index 10 is out of range")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_step(self):
+ """Test that 'lldb-mi --interpreter' works for stepping into."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Warning: the following is sensitive to the lines in the source
+
+ # Test that -exec-step steps into (or not) printf depending on debug info
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x[0-9a-f]+\",func=\"main\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value="0x[0-9a-f]+\"}],file=\"main.cpp\",fullname=\".+main.cpp\",line=\"\d\"},thread-id=\"1\",stopped-threads=\"all\"
+ # Linux: "*stopped,reason=\"end-stepping-range\",frame={addr="0x[0-9a-f]+\",func=\"__printf\",args=[{name=\"format\",value=\"0x[0-9a-f]+\"}],file=\"printf.c\",fullname=\".+printf.c\",line="\d+"},thread-id=\"1\",stopped-threads=\"all\"
+ self.runCmd("-exec-step --thread 1 --frame 0")
+ self.expect("\^running")
+ it = self.expect([ "\*stopped,reason=\"end-stepping-range\".+?func=\"main\"",
+ "\*stopped,reason=\"end-stepping-range\".+?func=\"(?!main).+?\"" ])
+ # Exit from printf if needed
+ if it == 1:
+ self.runCmd("-exec-finish")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
+
+ # Test that -exec-step steps into g_MyFunction and back out
+ # (and that --thread is optional)
+ self.runCmd("-exec-step --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"g_MyFunction.*?\"")
+ # Use -exec-finish here to make sure that control reaches the caller.
+ # -exec-step can keep us in the g_MyFunction for gcc
+ self.runCmd("-exec-finish --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"30\"")
+
+ # Test that -exec-step steps into s_MyFunction
+ # (and that --frame is optional)
+ self.runCmd("-exec-step --thread 1")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\".*?s_MyFunction.*?\"")
+
+ # Test that -exec-step steps into g_MyFunction from inside
+ # s_MyFunction (and that both --thread and --frame are optional)
+ self.runCmd("-exec-step")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"g_MyFunction.*?\"")
+
+ # Test that an invalid --thread is handled
+ self.runCmd("-exec-step --thread 0")
+ self.expect("\^error,message=\"error: Thread index 0 is out of range")
+ self.runCmd("-exec-step --thread 10")
+ self.expect("\^error,message=\"error: Thread index 10 is out of range")
+
+ # Test that an invalid --frame is handled
+ # FIXME: no error is returned
+ self.runCmd("-exec-step --frame 10")
+ #self.expect("\^error: Frame index 10 is out of range")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_step_instruction(self):
+ """Test that 'lldb-mi --interpreter' works for instruction stepping into."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Warning: the following is sensitive to the lines in the
+ # source and optimizations
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -exec-next steps over printf
+ self.runCmd("-exec-next --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"29\"")
+
+ # Test that -exec-step-instruction steps over non branching
+ # instruction
+ self.runCmd("-exec-step-instruction --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\"")
+
+ # Test that -exec-step-instruction steps into g_MyFunction
+ # instruction (and that --thread is optional)
+ self.runCmd("-exec-step-instruction --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"g_MyFunction.*?\"")
+
+ # Test that -exec-step-instruction steps over non branching
+ # (and that --frame is optional)
+ self.runCmd("-exec-step-instruction --thread 1")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"g_MyFunction.*?\"")
+
+ # Test that -exec-step-instruction steps into g_MyFunction
+ # (and that both --thread and --frame are optional)
+ self.runCmd("-exec-step-instruction")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"g_MyFunction.*?\"")
+
+ # Test that an invalid --thread is handled
+ self.runCmd("-exec-step-instruction --thread 0")
+ self.expect("\^error,message=\"error: Thread index 0 is out of range")
+ self.runCmd("-exec-step-instruction --thread 10")
+ self.expect("\^error,message=\"error: Thread index 10 is out of range")
+
+ # Test that an invalid --frame is handled
+ # FIXME: no error is returned
+ self.runCmd("-exec-step-instruction --frame 10")
+ #self.expect("\^error: Frame index 10 is out of range")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_exec_finish(self):
+ """Test that 'lldb-mi --interpreter' works for -exec-finish."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set BP at g_MyFunction and run to BP
+ self.runCmd("-break-insert -f g_MyFunction")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -exec-finish returns from g_MyFunction
+ self.runCmd("-exec-finish --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
+
+ # Run to BP inside s_MyFunction call
+ self.runCmd("-break-insert s_MyFunction")
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -exec-finish hits BP at g_MyFunction call inside
+ # s_MyFunction (and that --thread is optional)
+ self.runCmd("-exec-finish --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -exec-finish returns from g_MyFunction call inside
+ # s_MyFunction (and that --frame is optional)
+ self.runCmd("-exec-finish --thread 1")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\".*?s_MyFunction.*?\"")
+
+ # Test that -exec-finish returns from s_MyFunction
+ # (and that both --thread and --frame are optional)
+ self.runCmd("-exec-finish")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
+
+ # Test that an invalid --thread is handled
+ self.runCmd("-exec-finish --thread 0")
+ self.expect("\^error,message=\"error: Thread index 0 is out of range")
+ self.runCmd("-exec-finish --thread 10")
+ self.expect("\^error,message=\"error: Thread index 10 is out of range")
+
+ # Test that an invalid --frame is handled
+ # FIXME: no error is returned
+ #self.runCmd("-exec-finish --frame 10")
+ #self.expect("\^error: Frame index 10 is out of range")
+
+ # Set BP at printf and run to BP
+ self.runCmd("-break-insert -f printf")
+ self.expect("\^done,bkpt={number=\"3\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ ## Test that -exec-finish returns from printf
+ self.runCmd("-exec-finish --thread 1 --frame 0")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/control/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/control/main.cpp
new file mode 100644
index 0000000..ae0c3d9
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/control/main.cpp
@@ -0,0 +1,33 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+void
+g_MyFunction(void)
+{
+ printf("g_MyFunction");
+}
+
+static void
+s_MyFunction(void)
+{
+ g_MyFunction();
+ printf("s_MyFunction");
+}
+
+int
+main(int argc, char const *argv[])
+{
+ printf("start");
+ g_MyFunction();
+ s_MyFunction();
+ printf("exit");
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/data/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/data/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/data/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/data/TestMiData.py b/packages/Python/lldbsuite/test/tools/lldb-mi/data/TestMiData.py
new file mode 100644
index 0000000..df9f541
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/data/TestMiData.py
@@ -0,0 +1,337 @@
+"""
+Test lldb-mi -data-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiDataTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_disassemble(self):
+ """Test that 'lldb-mi --interpreter' works for -data-disassemble."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Get an address for disassembling: use main
+ self.runCmd("-data-evaluate-expression main")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \(a.out`main at main.cpp:[0-9]+\)\"")
+ addr = int(self.child.after.split("\"")[1].split(" ")[0], 16)
+
+ # Test -data-disassemble: try to disassemble some address
+ self.runCmd("-data-disassemble -s %#x -e %#x -- 0" % (addr, addr + 0x10))
+ self.expect("\^done,asm_insns=\[{address=\"0x0*%x\",func-name=\"main\",offset=\"0\",size=\"[1-9]+\",inst=\".+?\"}," % addr)
+
+ # Test -data-disassemble without "--"
+ self.runCmd("-data-disassemble -s %#x -e %#x 0" % (addr, addr + 0x10))
+ self.expect("\^done,asm_insns=\[{address=\"0x0*%x\",func-name=\"main\",offset=\"0\",size=\"[1-9]+\",inst=\".+?\"}," % addr)
+
+ # Run to hello_world
+ self.runCmd("-break-insert -f hello_world")
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Get an address for disassembling: use hello_world
+ self.runCmd("-data-evaluate-expression hello_world")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \(a.out`hello_world\(\) at main.cpp:[0-9]+\)\"")
+ addr = int(self.child.after.split("\"")[1].split(" ")[0], 16)
+
+ # Test -data-disassemble: try to disassemble some address
+ self.runCmd("-data-disassemble -s %#x -e %#x -- 0" % (addr, addr + 0x10))
+
+ # This matches a line similar to:
+ # Darwin: {address="0x0000000100000f18",func-name="hello_world()",offset="8",size="7",inst="leaq 0x65(%rip), %rdi; \"Hello, World!\\n\""},
+ # Linux: {address="0x0000000000400642",func-name="hello_world()",offset="18",size="5",inst="callq 0x4004d0; symbol stub for: printf"}
+ # To match the escaped characters in the ouptut, we must use four backslashes per matches backslash
+ # See https://docs.python.org/2/howto/regex.html#the-backslash-plague
+ self.expect([ "{address=\"0x[0-9a-f]+\",func-name=\"hello_world\(\)\",offset=\"[0-9]+\",size=\"[0-9]+\",inst=\".+?; \\\\\"Hello, World!\\\\\\\\n\\\\\"\"}",
+ "{address=\"0x[0-9a-f]+\",func-name=\"hello_world\(\)\",offset=\"[0-9]+\",size=\"[0-9]+\",inst=\".+?; symbol stub for: printf\"}" ])
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @unittest2.skip("-data-evaluate-expression doesn't work on globals") #FIXME: the global case worked before refactoring
+ def test_lldbmi_data_read_memory_bytes_global(self):
+ """Test that -data-read-memory-bytes can access global buffers."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Get address of char[] (global)
+ self.runCmd("-data-evaluate-expression &g_CharArray")
+ self.expect("\^done,value=\"0x[0-9a-f]+\"")
+ addr = int(self.child.after.split("\"")[1], 16)
+ size = 5
+
+ # Test that -data-read-memory-bytes works for char[] type (global)
+ self.runCmd("-data-read-memory-bytes %#x %d" % (addr, size))
+ self.expect("\^done,memory=\[{begin=\"0x0*%x\",offset=\"0x0+\",end=\"0x0*%x\",contents=\"1112131400\"}\]" % (addr, addr + size))
+
+ # Get address of static char[]
+ self.runCmd("-data-evaluate-expression &s_CharArray")
+ self.expect("\^done,value=\"0x[0-9a-f]+\"")
+ addr = int(self.child.after.split("\"")[1], 16)
+ size = 5
+
+ # Test that -data-read-memory-bytes works for static char[] type
+ self.runCmd("-data-read-memory-bytes %#x %d" % (addr, size))
+ self.expect("\^done,memory=\[{begin=\"0x0*%x\",offset=\"0x0+\",end=\"0x0*%x\",contents=\"1112131400\"}\]" % (addr, addr + size))
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_read_memory_bytes_local(self):
+ """Test that -data-read-memory-bytes can access local buffers."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd('-file-exec-and-symbols %s' % self.myexe)
+ self.expect(r'\^done')
+
+ # Run to BP_local_array_test_inner
+ line = line_number('main.cpp', '// BP_local_array_test_inner')
+ self.runCmd('-break-insert main.cpp:%d' % line)
+ self.expect(r'\^done,bkpt=\{number="1"')
+ self.runCmd('-exec-run')
+ self.expect(r'\^running')
+ self.expect(r'\*stopped,reason="breakpoint-hit"')
+
+ # Get address of local char[]
+ self.runCmd('-data-evaluate-expression "(void *)&array"')
+ self.expect(r'\^done,value="0x[0-9a-f]+"')
+ addr = int(self.child.after.split('"')[1], 16)
+ size = 4
+
+ # Test that an unquoted hex literal address works
+ self.runCmd('-data-read-memory-bytes %#x %d' % (addr, size))
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # Test that a double-quoted hex literal address works
+ self.runCmd('-data-read-memory-bytes "%#x" %d' % (addr, size))
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # Test that unquoted expressions work
+ self.runCmd('-data-read-memory-bytes &array %d' % size)
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # This doesn't work, and perhaps that makes sense, but it does work on GDB
+ self.runCmd('-data-read-memory-bytes array 4')
+ self.expect(r'\^error')
+ #self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ self.runCmd('-data-read-memory-bytes &array[2] 2')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="0304"\}\]' % (addr + 2, addr + size))
+
+ self.runCmd('-data-read-memory-bytes first_element_ptr %d' % size)
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # Test that double-quoted expressions work
+ self.runCmd('-data-read-memory-bytes "&array" %d' % size)
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ self.runCmd('-data-read-memory-bytes "&array[0] + 1" 3')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+ self.runCmd('-data-read-memory-bytes "first_element_ptr + 1" 3')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+ # Test the -o (offset) option
+ self.runCmd('-data-read-memory-bytes -o 1 &array 3')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+ # Test the --thread option
+ self.runCmd('-data-read-memory-bytes --thread 1 &array 4')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # Test the --thread option with an invalid value
+ self.runCmd('-data-read-memory-bytes --thread 999 &array 4')
+ self.expect(r'\^error')
+
+ # Test the --frame option (current frame)
+ self.runCmd('-data-read-memory-bytes --frame 0 &array 4')
+ self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+ # Test the --frame option (outer frame)
+ self.runCmd('-data-read-memory-bytes --frame 1 &array 4')
+ self.expect(r'\^done,memory=\[\{begin="0x[0-9a-f]+",offset="0x0+",end="0x[0-9a-f]+",contents="05060708"\}\]')
+
+ # Test the --frame option with an invalid value
+ self.runCmd('-data-read-memory-bytes --frame 999 &array 4')
+ self.expect(r'\^error')
+
+ # Test all the options at once
+ self.runCmd('-data-read-memory-bytes --thread 1 --frame 1 -o 2 &array 2')
+ self.expect(r'\^done,memory=\[\{begin="0x[0-9a-f]+",offset="0x0+",end="0x[0-9a-f]+",contents="0708"\}\]')
+
+ # Test that an expression that references undeclared variables doesn't work
+ self.runCmd('-data-read-memory-bytes "&undeclared_array1 + undeclared_array2[1]" 2')
+ self.expect(r'\^error')
+
+ # Test that the address argument is required
+ self.runCmd('-data-read-memory-bytes')
+ self.expect(r'\^error')
+
+ # Test that the count argument is required
+ self.runCmd('-data-read-memory-bytes &array')
+ self.expect(r'\^error')
+
+ # Test that the address and count arguments are required when other options are present
+ self.runCmd('-data-read-memory-bytes --thread 1')
+ self.expect(r'\^error')
+
+ self.runCmd('-data-read-memory-bytes --thread 1 --frame 0')
+ self.expect(r'\^error')
+
+ # Test that the count argument is required when other options are present
+ self.runCmd('-data-read-memory-bytes --thread 1 &array')
+ self.expect(r'\^error')
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_list_register_names(self):
+ """Test that 'lldb-mi --interpreter' works for -data-list-register-names."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -data-list-register-names: try to get all registers
+ self.runCmd("-data-list-register-names")
+ self.expect("\^done,register-names=\[\".+?\",")
+
+ # Test -data-list-register-names: try to get specified registers
+ self.runCmd("-data-list-register-names 0")
+ self.expect("\^done,register-names=\[\".+?\"\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_list_register_values(self):
+ """Test that 'lldb-mi --interpreter' works for -data-list-register-values."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -data-list-register-values: try to get all registers
+ self.runCmd("-data-list-register-values x")
+ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"")
+
+ # Test -data-list-register-values: try to get specified registers
+ self.runCmd("-data-list-register-values x 0")
+ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"}\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_info_line(self):
+ """Test that 'lldb-mi --interpreter' works for -data-info-line."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Get the address of main and its line
+ self.runCmd("-data-evaluate-expression main")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \(a.out`main at main.cpp:[0-9]+\)\"")
+ addr = int(self.child.after.split("\"")[1].split(" ")[0], 16)
+ line = line_number('main.cpp', '// FUNC_main')
+
+ # Test that -data-info-line works for address
+ self.runCmd("-data-info-line *%#x" % addr)
+ self.expect("\^done,start=\"0x0*%x\",end=\"0x[0-9a-f]+\",file=\".+?main.cpp\",line=\"%d\"" % (addr, line))
+
+ # Test that -data-info-line works for file:line
+ self.runCmd("-data-info-line main.cpp:%d" % line)
+ self.expect("\^done,start=\"0x0*%x\",end=\"0x[0-9a-f]+\",file=\".+?main.cpp\",line=\"%d\"" % (addr, line))
+
+ # Test that -data-info-line fails when invalid address is specified
+ self.runCmd("-data-info-line *0x0")
+ self.expect("\^error,msg=\"Command 'data-info-line'\. Error: The LineEntry is absent or has an unknown format\.\"")
+
+ # Test that -data-info-line fails when file is unknown
+ self.runCmd("-data-info-line unknown_file:1")
+ self.expect("\^error,msg=\"Command 'data-info-line'\. Error: The LineEntry is absent or has an unknown format\.\"")
+
+ # Test that -data-info-line fails when line has invalid format
+ self.runCmd("-data-info-line main.cpp:bad_line")
+ self.expect("\^error,msg=\"error: invalid line number string 'bad_line'")
+ self.runCmd("-data-info-line main.cpp:0")
+ self.expect("\^error,msg=\"error: zero is an invalid line number")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_data_evaluate_expression(self):
+ """Test that 'lldb-mi --interpreter' works for -data-evaluate-expression."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ line = line_number('main.cpp', '// BP_local_2d_array_test')
+ self.runCmd('-break-insert main.cpp:%d' % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Check 2d array
+ self.runCmd("-data-evaluate-expression array2d")
+ self.expect("\^done,value=\"\{\[0\] = \{\[0\] = 1, \[1\] = 2, \[2\] = 3\}, \[1\] = \{\[0\] = 4, \[1\] = 5, \[2\] = 6\}\}\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/data/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/data/main.cpp
new file mode 100644
index 0000000..8030fe8
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/data/main.cpp
@@ -0,0 +1,59 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+const char g_CharArray[] = "\x10\x11\x12\x13";
+static const char s_CharArray[] = "\x20\x21\x22\x23";
+
+void
+local_array_test_inner()
+{
+ char array[] = { 0x01, 0x02, 0x03, 0x04 };
+ char *first_element_ptr = &array[0];
+ // BP_local_array_test_inner
+ return;
+}
+
+void
+local_array_test()
+{
+ char array[] = { 0x05, 0x06, 0x07, 0x08 };
+ // BP_local_array_test
+ local_array_test_inner();
+ return;
+}
+
+void
+local_2d_array_test()
+{
+ int array2d[2][3];
+ array2d[0][0] = 1;
+ array2d[0][1] = 2;
+ array2d[0][2] = 3;
+ array2d[1][0] = 4;
+ array2d[1][1] = 5;
+ array2d[1][2] = 6;
+ return; // BP_local_2d_array_test
+}
+
+void
+hello_world()
+{
+ printf("Hello, World!\n"); // BP_hello_world
+}
+
+int
+main(int argc, char const *argv[])
+{ // FUNC_main
+ local_array_test();
+ hello_world();
+ local_2d_array_test();
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiCliSupport.py b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiCliSupport.py
new file mode 100644
index 0000000..562be91
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiCliSupport.py
@@ -0,0 +1,206 @@
+"""
+Test lldb-mi can interpret CLI commands directly.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiCliSupportTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_target_create(self):
+ """Test that 'lldb-mi --interpreter' can create target by 'target create' command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that "target create" loads executable
+ self.runCmd("target create \"%s\"" % self.myexe)
+ self.expect("\^done")
+
+ # Test that executable was loaded properly
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_breakpoint_set(self):
+ """Test that 'lldb-mi --interpreter' can set breakpoint by 'breakpoint set' command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that "breakpoint set" sets a breakpoint
+ self.runCmd("breakpoint set --name main")
+ self.expect("\^done")
+ self.expect("=breakpoint-created,bkpt={number=\"1\"")
+
+ # Test that breakpoint was set properly
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\"")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_settings_set_target_run_args_before(self):
+ """Test that 'lldb-mi --interpreter' can set target arguments by 'setting set target.run-args' command before than target was created."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that "settings set target.run-args" passes arguments to executable
+ #FIXME: --arg1 causes an error
+ self.runCmd("setting set target.run-args arg1 \"2nd arg\" third_arg fourth=\"4th arg\"")
+ self.expect("\^done")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+
+ # Test that arguments were passed properly
+ self.expect("@\"argc=5\\\\r\\\\n\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_settings_set_target_run_args_after(self):
+ """Test that 'lldb-mi --interpreter' can set target arguments by 'setting set target.run-args' command after than target was created."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that "settings set target.run-args" passes arguments to executable
+ #FIXME: --arg1 causes an error
+ self.runCmd("setting set target.run-args arg1 \"2nd arg\" third_arg fourth=\"4th arg\"")
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+
+ # Test that arguments were passed properly
+ self.expect("@\"argc=5\\\\r\\\\n\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_process_launch(self):
+ """Test that 'lldb-mi --interpreter' can launch process by "process launch" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set breakpoint
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Test that "process launch" launches executable
+ self.runCmd("process launch")
+ self.expect("\^done")
+
+ # Test that breakpoint hit
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_thread_step_in(self):
+ """Test that 'lldb-mi --interpreter' can step in by "thread step-in" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread step-in" steps into (or not) printf depending on debug info
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x[0-9a-f]+\",func=\"main\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value="0x[0-9a-f]+\"}],file=\"main.cpp\",fullname=\".+main.cpp\",line=\"\d\"},thread-id=\"1\",stopped-threads=\"all\"
+ # Linux: "*stopped,reason=\"end-stepping-range\",frame={addr="0x[0-9a-f]+\",func=\"__printf\",args=[{name=\"format\",value=\"0x[0-9a-f]+\"}],file=\"printf.c\",fullname=\".+printf.c\",line="\d+"},thread-id=\"1\",stopped-threads=\"all\"
+ self.runCmd("thread step-in")
+ self.expect("\^done")
+ it = self.expect([ "@\"argc=1\\\\r\\\\n\"",
+ "\*stopped,reason=\"end-stepping-range\".+?func=\"(?!main).+?\"" ])
+ if it == 0:
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_thread_step_over(self):
+ """Test that 'lldb-mi --interpreter' can step over by "thread step-over" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread step-over" steps over
+ self.runCmd("thread step-over")
+ self.expect("\^done")
+ self.expect("@\"argc=1\\\\r\\\\n\"")
+ self.expect("\*stopped,reason=\"end-stepping-range\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_thread_continue(self):
+ """Test that 'lldb-mi --interpreter' can continue execution by "thread continue" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread continue" continues execution
+ self.runCmd("thread continue")
+ self.expect("\^done")
+ self.expect("@\"argc=1\\\\r\\\\n")
+ self.expect("\*stopped,reason=\"exited-normally\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiInterpreterExec.py b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiInterpreterExec.py
new file mode 100644
index 0000000..93d9f25
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiInterpreterExec.py
@@ -0,0 +1,229 @@
+"""
+Test lldb-mi -interpreter-exec command.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiInterpreterExecTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_target_create(self):
+ """Test that 'lldb-mi --interpreter' can create target by 'target create' command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that "target create" loads executable
+ self.runCmd("-interpreter-exec console \"target create \\\"%s\\\"\"" % self.myexe)
+ self.expect("\^done")
+
+ # Test that executable was loaded properly
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_breakpoint_set(self):
+ """Test that 'lldb-mi --interpreter' can set breakpoint by 'breakpoint set' command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that "breakpoint set" sets a breakpoint
+ self.runCmd("-interpreter-exec console \"breakpoint set --name main\"")
+ self.expect("\^done")
+ self.expect("=breakpoint-created,bkpt={number=\"1\"")
+
+ # Test that breakpoint was set properly
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("=breakpoint-modified,bkpt={number=\"1\"")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # Failing in ~9/600 dosep runs (build 3120-3122)
+ def test_lldbmi_settings_set_target_run_args_before(self):
+ """Test that 'lldb-mi --interpreter' can set target arguments by 'setting set target.run-args' command before than target was created."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that "settings set target.run-args" passes arguments to executable
+ #FIXME: --arg1 causes an error
+ self.runCmd("-interpreter-exec console \"setting set target.run-args arg1 \\\"2nd arg\\\" third_arg fourth=\\\"4th arg\\\"\"")
+ self.expect("\^done")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+
+ # Test that arguments were passed properly
+ self.expect("@\"argc=5\\\\r\\\\n\"")
+ self.expect("@\"argv.0.=.*lldb-mi")
+ self.expect("@\"argv.1.=arg1\\\\r\\\\n\"")
+ self.expect("@\"argv.2.=2nd arg\\\\r\\\\n\"")
+ self.expect("@\"argv.3.=third_arg\\\\r\\\\n\"")
+ self.expect("@\"argv.4.=fourth=4th arg\\\\r\\\\n\"")
+
+ # Test that program exited normally
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # Failing in ~9/600 dosep runs (build 3120-3122)
+ def test_lldbmi_settings_set_target_run_args_after(self):
+ """Test that 'lldb-mi --interpreter' can set target arguments by 'setting set target.run-args' command after than target was created."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Test that "settings set target.run-args" passes arguments to executable
+ #FIXME: --arg1 causes an error
+ self.runCmd("-interpreter-exec console \"setting set target.run-args arg1 \\\"2nd arg\\\" third_arg fourth=\\\"4th arg\\\"\"")
+ self.expect("\^done")
+
+ # Run to BP_printf
+ line = line_number('main.cpp', '// BP_printf')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running");
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Run to BP_return
+ line = line_number('main.cpp', '// BP_return')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running");
+
+ # Test that arguments were passed properly
+ self.expect("@\"argc=5\\\\r\\\\n\"")
+ self.expect("@\"argv.0.=.*lldb-mi")
+ self.expect("@\"argv.1.=arg1\\\\r\\\\n\"")
+ self.expect("@\"argv.2.=2nd arg\\\\r\\\\n\"")
+ self.expect("@\"argv.3.=third_arg\\\\r\\\\n\"")
+ self.expect("@\"argv.4.=fourth=4th arg\\\\r\\\\n\"")
+
+ # Hit BP_return
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_process_launch(self):
+ """Test that 'lldb-mi --interpreter' can launch process by "process launch" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Set breakpoint
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Test that "process launch" launches executable
+ self.runCmd("-interpreter-exec console \"process launch\"")
+ self.expect("\^done")
+
+ # Test that breakpoint hit
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_thread_step_in(self):
+ """Test that 'lldb-mi --interpreter' can step in by "thread step-in" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread step-in" steps into (or not) printf depending on debug info
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x[0-9a-f]+\",func=\"main\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value="0x[0-9a-f]+\"}],file=\"main.cpp\",fullname=\".+main.cpp\",line=\"\d\"},thread-id=\"1\",stopped-threads=\"all\"
+ # Linux: "*stopped,reason=\"end-stepping-range\",frame={addr="0x[0-9a-f]+\",func=\"__printf\",args=[{name=\"format\",value=\"0x[0-9a-f]+\"}],file=\"printf.c\",fullname=\".+printf.c\",line="\d+"},thread-id=\"1\",stopped-threads=\"all\"
+ self.runCmd("-interpreter-exec console \"thread step-in\"")
+ self.expect("\^done")
+ it = self.expect([ "@\"argc=1\\\\r\\\\n\"",
+ "\*stopped,reason=\"end-stepping-range\".+?func=\"(?!main).+?\"" ])
+ if it == 0:
+ self.expect("\*stopped,reason=\"end-stepping-range\".+?func=\"main\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_thread_step_over(self):
+ """Test that 'lldb-mi --interpreter' can step over by "thread step-over" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread step-over" steps over
+ self.runCmd("-interpreter-exec console \"thread step-over\"")
+ self.expect("\^done")
+ self.expect("@\"argc=1\\\\r\\\\n\"")
+ self.expect("\*stopped,reason=\"end-stepping-range\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFlakeyLinux("llvm.org/pr25470")
+ def test_lldbmi_thread_continue(self):
+ """Test that 'lldb-mi --interpreter' can continue execution by "thread continue" command."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that "thread continue" continues execution
+ self.runCmd("-interpreter-exec console \"thread continue\"")
+ self.expect("\^done")
+ self.expect("@\"argc=1\\\\r\\\\n")
+ self.expect("\*stopped,reason=\"exited-normally\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/main.cpp
new file mode 100644
index 0000000..0c042d4
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/main.cpp
@@ -0,0 +1,19 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+int
+main(int argc, char const *argv[])
+{
+ printf("argc=%d\n", argc); // BP_printf
+ for (int i = 0; i < argc; ++i)
+ printf("argv[%d]=%s\n", i, argv[i]);
+ return 0; // BP_return
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/lldbmi_testcase.py b/packages/Python/lldbsuite/test/tools/lldb-mi/lldbmi_testcase.py
new file mode 100644
index 0000000..277ffe7
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/lldbmi_testcase.py
@@ -0,0 +1,54 @@
+"""
+Base class for lldb-mi test cases.
+"""
+
+from __future__ import print_function
+
+
+
+from lldbsuite.test.lldbtest import *
+
+class MiTestCaseBase(Base):
+
+ mydir = None
+ myexe = "a.out"
+ mylog = "child.log"
+
+ def getCategories(self):
+ return ['lldb-mi']
+
+ @classmethod
+ def classCleanup(cls):
+ TestBase.RemoveTempFile(cls.myexe)
+ TestBase.RemoveTempFile(cls.mylog)
+
+ def setUp(self):
+ Base.setUp(self)
+ self.buildDefault()
+ self.child_prompt = "(gdb)"
+
+ def tearDown(self):
+ if self.TraceOn():
+ print("\n\nContents of %s:" % self.mylog)
+ try:
+ print(open(self.mylog, "r").read())
+ except IOError:
+ pass
+ Base.tearDown(self)
+
+ def spawnLldbMi(self, args=None):
+ import pexpect
+ self.child = pexpect.spawn("%s --interpreter %s" % (
+ self.lldbMiExec, args if args else ""))
+ self.child.setecho(True)
+ self.child.logfile_read = open(self.mylog, "w")
+ # wait until lldb-mi has started up and is ready to go
+ self.expect(self.child_prompt, exactly = True)
+
+ def runCmd(self, cmd):
+ self.child.sendline(cmd)
+
+ def expect(self, pattern, exactly=False, *args, **kwargs):
+ if exactly:
+ return self.child.expect_exact(pattern, *args, **kwargs)
+ return self.child.expect(pattern, *args, **kwargs)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/main.cpp
new file mode 100644
index 0000000..6a2079f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/main.cpp
@@ -0,0 +1,19 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+int
+main(int argc, char const *argv[])
+{
+ int a = 10;
+
+ printf("argc=%d\n", argc); // BP_printf
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/signal/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/signal/TestMiSignal.py b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/TestMiSignal.py
new file mode 100644
index 0000000..11e7b8a
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/TestMiSignal.py
@@ -0,0 +1,197 @@
+"""
+Test that the lldb-mi handles signals properly.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiSignalTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Fails on FreeBSD apparently due to thread race conditions
+ def test_lldbmi_stopped_when_interrupt(self):
+ """Test that 'lldb-mi --interpreter' interrupt and resume a looping app."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Set doloop=1 and run (to loop forever)
+ self.runCmd("-data-evaluate-expression \"do_loop=1\"")
+ self.expect("\^done,value=\"1\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+
+ # Test that -exec-interrupt can interrupt an execution
+ self.runCmd("-exec-interrupt")
+ self.expect("\*stopped,reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\",.+?thread-id=\"1\",stopped-threads=\"all\"")
+
+ # Continue (to loop forever)
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+
+ # Test that Ctrl+C can interrupt an execution
+ self.child.sendintr() #FIXME: here uses self.child directly
+ self.expect("\*stopped,reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\",.*thread-id=\"1\",stopped-threads=\"all\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Fails on FreeBSD apparently due to thread race conditions
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_stopped_when_stopatentry_local(self):
+ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (local)."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run with stop-at-entry flag
+ self.runCmd("-interpreter-exec command \"process launch -s\"")
+ self.expect("\^done")
+
+ # Test that *stopped is printed
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",frame={level=\"0\",addr=\"0x[0-9a-f]+\",func=\"_dyld_start\",file=\"??\",fullname=\"??\",line=\"-1\"},thread-id=\"1\",stopped-threads=\"all\"
+ # Linux: "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x[0-9a-f]+\",func=\"??\",args=[],file=\"??\",fullname=\"??\",line=\"-1\"},thread-id=\"1\",stopped-threads=\"all\"
+ self.expect([ "\*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"_dyld_start\",file=\"\?\?\",fullname=\"\?\?\",line=\"-1\"\},thread-id=\"1\",stopped-threads=\"all\"",
+ "\*stopped,reason=\"end-stepping-range\",frame={addr=\"0x[0-9a-f]+\",func=\"\?\?\",args=\[\],file=\"\?\?\",fullname=\"\?\?\",line=\"-1\"},thread-id=\"1\",stopped-threads=\"all\"" ])
+
+ # Run to main to make sure we have not exited the application
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipUnlessDarwin
+ def test_lldbmi_stopped_when_stopatentry_remote(self):
+ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (remote)."""
+
+ # Prepare debugserver
+ import lldbgdbserverutils
+ debugserver_exe = lldbgdbserverutils.get_debugserver_exe()
+ if not debugserver_exe:
+ self.skipTest("debugserver exe not found")
+ hostname = "localhost"
+ import random
+ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port
+ import pexpect
+ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port))
+ self.addTearDownHook(lambda: debugserver_child.terminate(force = True))
+
+ self.spawnLldbMi(args = None)
+
+ # Connect to debugserver
+ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"")
+ self.expect("\^done")
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port))
+ self.expect("\^done")
+
+ # Run with stop-at-entry flag
+ self.runCmd("-interpreter-exec command \"process launch -s\"")
+ self.expect("\^done")
+
+ # Test that *stopped is printed
+ self.expect("\*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",.+?thread-id=\"1\",stopped-threads=\"all\"")
+
+ # Exit
+ self.runCmd("-gdb-exit")
+ self.expect("\^exit")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_stopped_when_segfault_local(self):
+ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (local)."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Set do_segfault=1 and run (to cause a segfault error)
+ self.runCmd("-data-evaluate-expression \"do_segfault=1\"")
+ self.expect("\^done,value=\"1\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+
+ # Test that *stopped is printed
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS (code=1, address=0x0)\",thread-id=\"1\",stopped-threads=\"all\""
+ # Linux: "*stopped,reason=\"exception-received\",exception=\"invalid address (fault address: 0x0)\",thread-id=\"1\",stopped-threads=\"all\""
+ self.expect([ "\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"",
+ "\*stopped,reason=\"exception-received\",exception=\"invalid address \(fault address: 0x0\)\",thread-id=\"1\",stopped-threads=\"all\"" ])
+
+ @skipUnlessDarwin
+ def test_lldbmi_stopped_when_segfault_remote(self):
+ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (remote)."""
+
+ # Prepare debugserver
+ import lldbgdbserverutils
+ debugserver_exe = lldbgdbserverutils.get_debugserver_exe()
+ if not debugserver_exe:
+ self.skipTest("debugserver exe not found")
+ hostname = "localhost"
+ import random
+ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port
+ import pexpect
+ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port))
+ self.addTearDownHook(lambda: debugserver_child.terminate(force = True))
+
+ self.spawnLldbMi(args = None)
+
+ # Connect to debugserver
+ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"")
+ self.expect("\^done")
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port))
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ #FIXME -exec-run doesn't work
+ self.runCmd("-interpreter-exec command \"process launch\"") #FIXME: self.runCmd("-exec-run")
+ self.expect("\^done") #FIXME: self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Set do_segfault=1 and run (to cause a segfault error)
+ self.runCmd("-data-evaluate-expression \"do_segfault=1\"")
+ self.expect("\^done,value=\"1\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+
+ # Test that *stopped is printed
+ self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"")
+
+ # Exit
+ self.runCmd("-gdb-exit")
+ self.expect("\^exit")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/signal/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/main.cpp
new file mode 100644
index 0000000..7f6eeca
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/signal/main.cpp
@@ -0,0 +1,33 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstddef>
+#include <unistd.h>
+
+int do_loop;
+int do_segfault;
+
+int
+main(int argc, char const *argv[])
+{
+ if (do_loop)
+ {
+ do
+ sleep(1);
+ while (do_loop); // BP_loop_condition
+ }
+
+ if (do_segfault)
+ {
+ int *null_ptr = NULL;
+ return *null_ptr;
+ }
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/stack/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/stack/TestMiStack.py b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/TestMiStack.py
new file mode 100644
index 0000000..14dab38
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/TestMiStack.py
@@ -0,0 +1,479 @@
+"""
+Test lldb-mi -stack-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiStackTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_list_arguments(self):
+ """Test that 'lldb-mi --interpreter' can shows arguments."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -stack-list-arguments lists empty stack arguments if range is empty
+ self.runCmd("-stack-list-arguments 0 1 0")
+ self.expect("\^done,stack-args=\[\]")
+
+ # Test that -stack-list-arguments lists stack arguments without values
+ # (and that low-frame and high-frame are optional)
+ self.runCmd("-stack-list-arguments 0")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}")
+ self.runCmd("-stack-list-arguments --no-values")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}")
+
+ # Test that -stack-list-arguments lists stack arguments with all values
+ self.runCmd("-stack-list-arguments 1 0 0")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}\]")
+ self.runCmd("-stack-list-arguments --all-values 0 0")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}\]")
+
+ # Test that -stack-list-arguments lists stack arguments with simple values
+ self.runCmd("-stack-list-arguments 2 0 1")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",type=\"int\",value=\"1\"},{name=\"argv\",type=\"const char \*\*\",value=\".*\"}\]}")
+ self.runCmd("-stack-list-arguments --simple-values 0 1")
+ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",type=\"int\",value=\"1\"},{name=\"argv\",type=\"const char \*\*\",value=\".*\"}\]}")
+
+ # Test that an invalid low-frame is handled
+ # FIXME: -1 is treated as unsigned int
+ self.runCmd("-stack-list-arguments 0 -1 0")
+ #self.expect("\^error")
+ self.runCmd("-stack-list-arguments 0 0")
+ self.expect("\^error,msg=\"Command 'stack-list-arguments'\. Thread frame range invalid\"")
+
+ # Test that an invalid high-frame is handled
+ # FIXME: -1 is treated as unsigned int
+ self.runCmd("-stack-list-arguments 0 0 -1")
+ #self.expect("\^error")
+
+ # Test that a missing low-frame or high-frame is handled
+ self.runCmd("-stack-list-arguments 0 0")
+ self.expect("\^error,msg=\"Command 'stack-list-arguments'\. Thread frame range invalid\"")
+
+ # Test that an invalid low-frame is handled
+ self.runCmd("-stack-list-arguments 0 0")
+ self.expect("\^error,msg=\"Command 'stack-list-arguments'\. Thread frame range invalid\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_list_locals(self):
+ """Test that 'lldb-mi --interpreter' can shows local variables."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test int local variables:
+ # Run to BP_local_int_test
+ line = line_number('main.cpp', '// BP_local_int_test')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-locals: use 0 or --no-values
+ self.runCmd("-stack-list-locals 0")
+ self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]")
+ self.runCmd("-stack-list-locals --no-values")
+ self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]")
+
+ # Test -stack-list-locals: use 1 or --all-values
+ self.runCmd("-stack-list-locals 1")
+ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]")
+ self.runCmd("-stack-list-locals --all-values")
+ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]")
+
+ # Test -stack-list-locals: use 2 or --simple-values
+ self.runCmd("-stack-list-locals 2")
+ self.expect("\^done,locals=\[{name=\"a\",type=\"int\",value=\"10\"},{name=\"b\",type=\"int\",value=\"20\"}\]")
+ self.runCmd("-stack-list-locals --simple-values")
+ self.expect("\^done,locals=\[{name=\"a\",type=\"int\",value=\"10\"},{name=\"b\",type=\"int\",value=\"20\"}\]")
+
+ # Test struct local variable:
+ # Run to BP_local_struct_test
+ line = line_number('main.cpp', '// BP_local_struct_test')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"3\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-locals: use 0 or --no-values
+ self.runCmd("-stack-list-locals 0")
+ self.expect("\^done,locals=\[name=\"var_c\"\]")
+ self.runCmd("-stack-list-locals --no-values")
+ self.expect("\^done,locals=\[name=\"var_c\"\]")
+
+ # Test -stack-list-locals: use 1 or --all-values
+ self.runCmd("-stack-list-locals 1")
+ self.expect("\^done,locals=\[{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]")
+ self.runCmd("-stack-list-locals --all-values")
+ self.expect("\^done,locals=\[{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]")
+
+ # Test -stack-list-locals: use 2 or --simple-values
+ self.runCmd("-stack-list-locals 2")
+ self.expect("\^done,locals=\[{name=\"var_c\",type=\"my_type\"}\]")
+ self.runCmd("-stack-list-locals --simple-values")
+ self.expect("\^done,locals=\[{name=\"var_c\",type=\"my_type\"}\]")
+
+ # Test array local variable:
+ # Run to BP_local_array_test
+ line = line_number('main.cpp', '// BP_local_array_test')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"4\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-locals: use 0 or --no-values
+ self.runCmd("-stack-list-locals 0")
+ self.expect("\^done,locals=\[name=\"array\"\]")
+ self.runCmd("-stack-list-locals --no-values")
+ self.expect("\^done,locals=\[name=\"array\"\]")
+
+ # Test -stack-list-locals: use 1 or --all-values
+ self.runCmd("-stack-list-locals 1")
+ self.expect("\^done,locals=\[{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]")
+ self.runCmd("-stack-list-locals --all-values")
+ self.expect("\^done,locals=\[{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]")
+
+ # Test -stack-list-locals: use 2 or --simple-values
+ self.runCmd("-stack-list-locals 2")
+ self.expect("\^done,locals=\[{name=\"array\",type=\"int \[3\]\"}\]")
+ self.runCmd("-stack-list-locals --simple-values")
+ self.expect("\^done,locals=\[{name=\"array\",type=\"int \[3\]\"}\]")
+
+ # Test pointers as local variable:
+ # Run to BP_local_pointer_test
+ line = line_number('main.cpp', '// BP_local_pointer_test')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"5\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-locals: use 0 or --no-values
+ self.runCmd("-stack-list-locals 0")
+ self.expect("\^done,locals=\[name=\"test_str\",name=\"var_e\",name=\"ptr\"\]")
+ self.runCmd("-stack-list-locals --no-values")
+ self.expect("\^done,locals=\[name=\"test_str\",name=\"var_e\",name=\"ptr\"\]")
+
+ # Test -stack-list-locals: use 1 or --all-values
+ self.runCmd("-stack-list-locals 1")
+ self.expect("\^done,locals=\[{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]")
+ self.runCmd("-stack-list-locals --all-values")
+ self.expect("\^done,locals=\[{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]")
+
+ # Test -stack-list-locals: use 2 or --simple-values
+ self.runCmd("-stack-list-locals 2")
+ self.expect("\^done,locals=\[{name=\"test_str\",type=\"const char \*\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",type=\"int\",value=\"24\"},{name=\"ptr\",type=\"int \*\",value=\".*?\"}\]")
+ self.runCmd("-stack-list-locals --simple-values")
+ self.expect("\^done,locals=\[{name=\"test_str\",type=\"const char \*\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",type=\"int\",value=\"24\"},{name=\"ptr\",type=\"int \*\",value=\".*?\"}\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_list_variables(self):
+ """Test that 'lldb-mi --interpreter' can shows local variables and arguments."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test int local variables:
+ # Run to BP_local_int_test
+ line = line_number('main.cpp', '// BP_local_int_test_with_args')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-variables: use 0 or --no-values
+ self.runCmd("-stack-list-variables 0")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\"},{arg=\"1\",name=\"d\"},{name=\"a\"},{name=\"b\"}\]")
+ self.runCmd("-stack-list-variables --no-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\"},{arg=\"1\",name=\"d\"},{name=\"a\"},{name=\"b\"}\]")
+
+ # Test -stack-list-variables: use 1 or --all-values
+ self.runCmd("-stack-list-variables 1")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]")
+ self.runCmd("-stack-list-variables --all-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]")
+
+ # Test -stack-list-variables: use 2 or --simple-values
+ self.runCmd("-stack-list-variables 2")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",type=\"int\",value=\"30\"},{arg=\"1\",name=\"d\",type=\"int\",value=\"40\"},{name=\"a\",type=\"int\",value=\"10\"},{name=\"b\",type=\"int\",value=\"20\"}\]")
+ self.runCmd("-stack-list-variables --simple-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",type=\"int\",value=\"30\"},{arg=\"1\",name=\"d\",type=\"int\",value=\"40\"},{name=\"a\",type=\"int\",value=\"10\"},{name=\"b\",type=\"int\",value=\"20\"}\]")
+
+ # Test struct local variable:
+ # Run to BP_local_struct_test
+ line = line_number('main.cpp', '// BP_local_struct_test_with_args')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"3\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-variables: use 0 or --no-values
+ self.runCmd("-stack-list-variables 0")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]")
+ self.runCmd("-stack-list-variables --no-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]")
+
+ # Test -stack-list-variables: use 1 or --all-values
+ self.runCmd("-stack-list-variables 1")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",value=\"{var_a = 20, var_b = 98 'b', inner_ = {var_d = 40}}\"},{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]")
+ self.runCmd("-stack-list-variables --all-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",value=\"{var_a = 20, var_b = 98 'b', inner_ = {var_d = 40}}\"},{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]")
+
+ # Test -stack-list-variables: use 2 or --simple-values
+ self.runCmd("-stack-list-variables 2")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",type=\"my_type\"},{name=\"var_c\",type=\"my_type\"}\]")
+ self.runCmd("-stack-list-variables --simple-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",type=\"my_type\"},{name=\"var_c\",type=\"my_type\"}\]")
+
+ # Test array local variable:
+ # Run to BP_local_array_test
+ line = line_number('main.cpp', '// BP_local_array_test_with_args')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"4\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-variables: use 0 or --no-values
+ self.runCmd("-stack-list-variables 0")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\"},{name=\"array\"}\]")
+ self.runCmd("-stack-list-variables --no-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\"},{name=\"array\"}\]")
+
+ # Test -stack-list-variables: use 1 or --all-values
+ self.runCmd("-stack-list-variables 1")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]")
+ self.runCmd("-stack-list-variables --all-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]")
+
+ # Test -stack-list-variables: use 2 or --simple-values
+ self.runCmd("-stack-list-variables 2")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",type=\"int \*\",value=\".*?\"},{name=\"array\",type=\"int \[3\]\"}\]")
+ self.runCmd("-stack-list-variables --simple-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",type=\"int \*\",value=\".*?\"},{name=\"array\",type=\"int \[3\]\"}\]")
+
+ # Test pointers as local variable:
+ # Run to BP_local_pointer_test
+ line = line_number('main.cpp', '// BP_local_pointer_test_with_args')
+ self.runCmd("-break-insert --file main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"5\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test -stack-list-variables: use 0 or --no-values
+ self.runCmd("-stack-list-variables 0")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\"},{arg=\"1\",name=\"arg_ptr\"},{name=\"test_str\"},{name=\"var_e\"},{name=\"ptr\"}\]")
+ self.runCmd("-stack-list-variables --no-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\"},{arg=\"1\",name=\"arg_ptr\"},{name=\"test_str\"},{name=\"var_e\"},{name=\"ptr\"}\]")
+
+ # Test -stack-list-variables: use 1 or --all-values
+ self.runCmd("-stack-list-variables 1")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]")
+ self.runCmd("-stack-list-variables --all-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]")
+
+ # Test -stack-list-variables: use 2 or --simple-values
+ self.runCmd("-stack-list-variables 2")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",type=\"const char \*\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",type=\"int \*\",value=\".*?\"},{name=\"test_str\",type=\"const char \*\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",type=\"int\",value=\"24\"},{name=\"ptr\",type=\"int \*\",value=\".*?\"}\]")
+ self.runCmd("-stack-list-variables --simple-values")
+ self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",type=\"const char \*\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",type=\"int \*\",value=\".*?\"},{name=\"test_str\",type=\"const char \*\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",type=\"int\",value=\"24\"},{name=\"ptr\",type=\"int \*\",value=\".*?\"}\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_info_depth(self):
+ """Test that 'lldb-mi --interpreter' can shows depth of the stack."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -stack-info-depth works
+ # (and that max-depth is optional)
+ self.runCmd("-stack-info-depth")
+ self.expect("\^done,depth=\"[1-9]\"")
+
+ # Test that max-depth restricts check of stack depth
+ #FIXME: max-depth argument is ignored
+ self.runCmd("-stack-info-depth 1")
+ #self.expect("\^done,depth=\"1\"")
+
+ # Test that invalid max-depth argument is handled
+ #FIXME: max-depth argument is ignored
+ self.runCmd("-stack-info-depth -1")
+ #self.expect("\^error")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipUnlessDarwin
+ def test_lldbmi_stack_info_frame(self):
+ """Test that 'lldb-mi --interpreter' can show information about current frame."""
+
+ self.spawnLldbMi(args = None)
+
+ # Test that -stack-info-frame fails when program isn't running
+ self.runCmd("-stack-info-frame")
+ self.expect("\^error,msg=\"Command 'stack-info-frame'\. Invalid process during debug session\"")
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -stack-info-frame works when program was stopped on BP
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\"\}")
+
+ # Select frame #1
+ self.runCmd("-stack-select-frame 1")
+ self.expect("\^done")
+
+ # Test that -stack-info-frame works when specified frame was selected
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"1\",addr=\"0x[0-9a-f]+\",func=\".+?\",file=\"\?\?\",fullname=\"\?\?\",line=\"-1\"\}")
+
+ # Test that -stack-info-frame fails when an argument is specified
+ #FIXME: unknown argument is ignored
+ self.runCmd("-stack-info-frame unknown_arg")
+ #self.expect("\^error")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_list_frames(self):
+ """Test that 'lldb-mi --interpreter' can lists the frames on the stack."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test stack frame: get frame #0 info
+ self.runCmd("-stack-list-frames 0 0")
+ self.expect("\^done,stack=\[frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\"\}\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_stack_select_frame(self):
+ """Test that 'lldb-mi --interpreter' can choose current frame."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that -stack-select-frame requires 1 mandatory argument
+ self.runCmd("-stack-select-frame")
+ self.expect("\^error,msg=\"Command 'stack-select-frame'\. Command Args\. Validation failed. Mandatory args not found: frame_id\"")
+
+ # Test that -stack-select-frame fails on invalid frame number
+ self.runCmd("-stack-select-frame 99")
+ self.expect("\^error,msg=\"Command 'stack-select-frame'\. Frame ID invalid\"")
+
+ # Test that current frame is #0
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\"\}")
+
+ # Test that -stack-select-frame can select the selected frame
+ self.runCmd("-stack-select-frame 0")
+ self.expect("\^done")
+
+ # Test that current frame is still #0
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\"\}")
+
+ # Test that -stack-select-frame can select frame #1 (parent frame)
+ self.runCmd("-stack-select-frame 1")
+ self.expect("\^done")
+
+ # Test that current frame is #1
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "^done,frame={level=\"1\",addr=\"0x[0-9a-f]+\",func=\"start\",file=\"??\",fullname=\"??\",line=\"-1\"}"
+ # Linux: "^done,frame={level=\"1\",addr=\"0x[0-9a-f]+\",func=\".+\",file=\".+\",fullname=\".+\",line=\"\d+\"}"
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"1\",addr=\"0x[0-9a-f]+\",func=\".+?\",file=\".+?\",fullname=\".+?\",line=\"(-1|\d+)\"\}")
+
+ # Test that -stack-select-frame can select frame #0 (child frame)
+ self.runCmd("-stack-select-frame 0")
+ self.expect("\^done")
+
+ # Test that current frame is #0 and it has the same information
+ self.runCmd("-stack-info-frame")
+ self.expect("\^done,frame=\{level=\"0\",addr=\"0x[0-9a-f]+\",func=\"main\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\"\}")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/stack/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/main.cpp
new file mode 100644
index 0000000..e11f83e
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/stack/main.cpp
@@ -0,0 +1,127 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+struct inner
+{
+ int var_d;
+};
+
+struct my_type
+{
+ int var_a;
+ char var_b;
+ struct inner inner_;
+};
+
+int
+local_int_test(void)
+{
+ int a = 10, b = 20;
+ return 0; // BP_local_int_test
+}
+
+int
+local_int_test_with_args(int c, int d)
+{
+ int a = 10, b = 20;
+ return 0; // BP_local_int_test_with_args
+}
+
+int
+local_struct_test(void)
+{
+ struct my_type var_c;
+ var_c.var_a = 10;
+ var_c.var_b = 'a';
+ var_c.inner_.var_d = 30;
+ return 0; // BP_local_struct_test
+}
+
+int local_struct_test_with_args(struct my_type var_e)
+{
+ struct my_type var_c;
+ var_c.var_a = 10;
+ var_c.var_b = 'a';
+ var_c.inner_.var_d = 30;
+ return 0; // BP_local_struct_test_with_args
+}
+
+int
+local_array_test(void)
+{
+ int array[3];
+ array[0] = 100;
+ array[1] = 200;
+ array[2] = 300;
+ return 0; // BP_local_array_test
+}
+
+int
+local_array_test_with_args(int* other_array)
+{
+ int array[3];
+ array[0] = 100;
+ array[1] = 200;
+ array[2] = 300;
+ return 0; // BP_local_array_test_with_args
+}
+
+int
+local_pointer_test(void)
+{
+ const char *test_str = "Rakaposhi";
+ int var_e = 24;
+ int *ptr = &var_e;
+ return 0; // BP_local_pointer_test
+}
+
+int
+local_pointer_test_with_args(const char *arg_str, int *arg_ptr)
+{
+ const char *test_str = "Rakaposhi";
+ int var_e = 24;
+ int *ptr = &var_e;
+ return 0; // BP_local_pointer_test_with_args
+}
+
+int do_tests_with_args()
+{
+ local_int_test_with_args(30, 40);
+
+ struct my_type var_e;
+ var_e.var_a = 20;
+ var_e.var_b = 'b';
+ var_e.inner_.var_d = 40;
+ local_struct_test_with_args(var_e);
+
+ int array[3];
+ array[0] = 400;
+ array[1] = 500;
+ array[2] = 600;
+ local_array_test_with_args(array);
+
+ const char *test_str = "String";
+ int var_z = 25;
+ int *ptr = &var_z;
+ local_pointer_test_with_args(test_str, ptr);
+
+ return 0;
+}
+
+int
+main(int argc, char const *argv[])
+{
+ local_int_test();
+ local_struct_test();
+ local_array_test();
+ local_pointer_test();
+
+ do_tests_with_args();
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py
new file mode 100644
index 0000000..8f02f1c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py
@@ -0,0 +1,290 @@
+"""
+Test lldb-mi startup options.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiStartupOptionsTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_executable_option_file(self):
+ """Test that 'lldb-mi --interpreter %s' loads executable file."""
+
+ self.spawnLldbMi(args = "%s" % self.myexe)
+
+ # Test that the executable is loaded when file was specified
+ self.expect("-file-exec-and-symbols \"%s\"" % self.myexe)
+ self.expect("\^done")
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Continue
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_executable_option_unknown_file(self):
+ """Test that 'lldb-mi --interpreter %s' fails on unknown executable file."""
+
+ # Prepare path to executable
+ path = "unknown_file"
+
+ self.spawnLldbMi(args = "%s" % path)
+
+ # Test that the executable isn't loaded when unknown file was specified
+ self.expect("-file-exec-and-symbols \"%s\"" % path)
+ self.expect("\^error,msg=\"Command 'file-exec-and-symbols'. Target binary '%s' is invalid. error: unable to find executable for '%s'\"" % (path, path))
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_executable_option_absolute_path(self):
+ """Test that 'lldb-mi --interpreter %s' loads executable which is specified via absolute path."""
+
+ # Prepare path to executable
+ import os
+ path = os.path.join(os.getcwd(), self.myexe)
+
+ self.spawnLldbMi(args = "%s" % path)
+
+ # Test that the executable is loaded when file was specified using absolute path
+ self.expect("-file-exec-and-symbols \"%s\"" % path)
+ self.expect("\^done")
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_executable_option_relative_path(self):
+ """Test that 'lldb-mi --interpreter %s' loads executable which is specified via relative path."""
+
+ # Prepare path to executable
+ path = "./%s" % self.myexe
+
+ self.spawnLldbMi(args = "%s" % path)
+
+ # Test that the executable is loaded when file was specified using relative path
+ self.expect("-file-exec-and-symbols \"%s\"" % path)
+ self.expect("\^done")
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_executable_option_unknown_path(self):
+ """Test that 'lldb-mi --interpreter %s' fails on executable file which is specified via unknown path."""
+
+ # Prepare path to executable
+ path = "unknown_dir/%s" % self.myexe
+
+ self.spawnLldbMi(args = "%s" % path)
+
+ # Test that the executable isn't loaded when file was specified using unknown path
+ self.expect("-file-exec-and-symbols \"%s\"" % path)
+ self.expect("\^error,msg=\"Command 'file-exec-and-symbols'. Target binary '%s' is invalid. error: unable to find executable for '%s'\"" % (path, path))
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_source_option_start_script(self):
+ """Test that 'lldb-mi --interpreter' can execute user's commands after initial commands were executed."""
+
+ # Prepared source file
+ sourceFile = "start_script"
+
+ self.spawnLldbMi(args = "--source %s" % sourceFile)
+
+ # After '-file-exec-and-symbols a.out'
+ self.expect("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # After '-break-insert -f main'
+ self.expect("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # After '-exec-run'
+ self.expect("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # After '-break-insert main.cpp:BP_return'
+ line = line_number('main.cpp', '//BP_return')
+ self.expect("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+
+ # After '-exec-continue'
+ self.expect("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that lldb-mi is ready after execution of --source start_script
+ self.expect(self.child_prompt, exactly = True)
+
+ # Try to evaluate 'a' expression
+ self.runCmd("-data-evaluate-expression a")
+ self.expect("\^done,value=\"10\"")
+ self.expect(self.child_prompt, exactly = True)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_source_option_start_script_exit(self):
+ """Test that 'lldb-mi --interpreter' can execute a prepared file which passed via --source option."""
+
+ # Prepared source file
+ sourceFile = "start_script_exit"
+
+ self.spawnLldbMi(args = "--source %s" % sourceFile)
+
+ # After '-file-exec-and-symbols a.out'
+ self.expect("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # After '-break-insert -f main'
+ self.expect("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # After '-exec-run'
+ self.expect("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # After '-break-insert main.cpp:BP_return'
+ line = line_number('main.cpp', '//BP_return')
+ self.expect("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+
+ # After '-exec-continue'
+ self.expect("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # After '-data-evaluate-expression a'
+ self.expect("-data-evaluate-expression a")
+ self.expect("\^done,value=\"10\"")
+
+ # After '-gdb-exit'
+ self.expect("-gdb-exit")
+ self.expect("\^exit")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_source_option_start_script_error(self):
+ """Test that 'lldb-mi --interpreter' stops execution of initial commands in case of error."""
+
+ # Prepared source file
+ sourceFile = "start_script_error"
+
+ self.spawnLldbMi(args = "--source %s" % sourceFile)
+
+ # After '-file-exec-and-symbols a.out'
+ self.expect("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # After '-break-ins -f main'
+ self.expect("-break-ins -f main")
+ self.expect("\^error")
+
+ # Test that lldb-mi is ready after execution of --source start_script
+ self.expect(self.child_prompt, exactly = True)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_log_option(self):
+ """Test that 'lldb-mi --log' creates a log file in the current directory."""
+
+ logDirectory = "."
+ self.spawnLldbMi(args = "%s --log" % self.myexe)
+
+ # Test that the executable is loaded when file was specified
+ self.expect("-file-exec-and-symbols \"%s\"" % self.myexe)
+ self.expect("\^done")
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ # Check log file is created
+ import glob,os
+ logFile = glob.glob(logDirectory + "/lldb-mi-*.log")
+
+ if not logFile:
+ self.fail("log file not found")
+
+ # Delete log
+ for f in logFile:
+ os.remove(f)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_log_directory_option(self):
+ """Test that 'lldb-mi --log --log-dir' creates a log file in the directory specified by --log-dir."""
+
+ # Create log in temp directory
+ import tempfile
+ logDirectory = tempfile.gettempdir()
+
+ self.spawnLldbMi(args = "%s --log --log-dir=%s" % (self.myexe,logDirectory))
+
+ # Test that the executable is loaded when file was specified
+ self.expect("-file-exec-and-symbols \"%s\"" % self.myexe)
+ self.expect("\^done")
+
+ # Test that lldb-mi is ready when executable was loaded
+ self.expect(self.child_prompt, exactly = True)
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ # Check log file is created
+ import glob,os
+ logFile = glob.glob(logDirectory + "/lldb-mi-*.log")
+
+ if not logFile:
+ self.fail("log file not found")
+
+ # Delete log
+ for f in logFile:
+ os.remove(f)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/main.cpp
new file mode 100644
index 0000000..7f2d524
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/main.cpp
@@ -0,0 +1,15 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int
+main(int argc, char const *argv[])
+{
+ int a = 10;
+ return 0; //BP_return
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script
new file mode 100644
index 0000000..511c022
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script
@@ -0,0 +1,5 @@
+-file-exec-and-symbols a.out
+-break-insert -f main
+-exec-run
+-break-insert main.cpp:14
+-exec-continue
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_error b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_error
new file mode 100644
index 0000000..d834e74
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_error
@@ -0,0 +1,2 @@
+-file-exec-and-symbols a.out
+-break-ins -f main
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_exit b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_exit
new file mode 100644
index 0000000..8379018
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_exit
@@ -0,0 +1,7 @@
+-file-exec-and-symbols a.out
+-break-insert -f main
+-exec-run
+-break-insert main.cpp:14
+-exec-continue
+-data-evaluate-expression a
+-gdb-exit
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile
new file mode 100644
index 0000000..dde38f4
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp symbol_list_lines_inline_test.cpp symbol_list_lines_inline_test2.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
new file mode 100644
index 0000000..3566b2f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
@@ -0,0 +1,81 @@
+"""
+Test lldb-mi -symbol-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiSymbolTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # new failure after r256863
+ def test_lldbmi_symbol_list_lines_file(self):
+ """Test that 'lldb-mi --interpreter' works for -symbol-list-lines when file exists."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Get address of main and its line
+ self.runCmd("-data-evaluate-expression main")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \(a.out`main at main.cpp:[0-9]+\)\"")
+ addr = int(self.child.after.split("\"")[1].split(" ")[0], 16)
+ line = line_number('main.cpp', '// FUNC_main')
+
+ # Test that -symbol-list-lines works on valid data
+ self.runCmd("-symbol-list-lines main.cpp")
+ self.expect("\^done,lines=\[\{pc=\"0x0*%x\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d+\"\})+\]" % (addr, line))
+
+ # Test that -symbol-list-lines doesn't include lines from other sources
+ # by checking the first and last line, and making sure the other lines
+ # are between 30 and 39.
+ sline = line_number('symbol_list_lines_inline_test2.cpp', '// FUNC_gfunc2')
+ eline = line_number('symbol_list_lines_inline_test2.cpp', '// END_gfunc2')
+ self.runCmd("-symbol-list-lines symbol_list_lines_inline_test2.cpp")
+ self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*\]" % (sline, eline))
+ ##FIXME: This doesn't work for symbol_list_lines_inline_test.cpp due to clang bug llvm.org/pr24716 (fixed in newer versions of clang)
+ ##sline = line_number('symbol_list_lines_inline_test.cpp', '// FUNC_gfunc')
+ ##eline = line_number('symbol_list_lines_inline_test.cpp', '// STRUCT_s')
+ ##self.runCmd("-symbol-list-lines symbol_list_lines_inline_test.cpp")
+ ##self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline))
+
+ # Test that -symbol-list-lines works on header files by checking the first
+ # and last line, and making sure the other lines are under 29.
+ sline = line_number('symbol_list_lines_inline_test.h', '// FUNC_ifunc')
+ eline = line_number('symbol_list_lines_inline_test.h', '// FUNC_mfunc')
+ self.runCmd("-symbol-list-lines symbol_list_lines_inline_test.h")
+ self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d\"\})*(,\{pc=\"0x[0-9a-f]+\",line=\"1\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"2\d\"\})*\]" % (sline, eline))
+
+ # Test that -symbol-list-lines fails when file doesn't exist
+ self.runCmd("-symbol-list-lines unknown_file")
+ self.expect("\^error,message=\"error: No source filenames matched 'unknown_file'\. \"")
+
+ # Test that -symbol-list-lines fails when file is specified using relative path
+ self.runCmd("-symbol-list-lines ./main.cpp")
+ self.expect("\^error,message=\"error: No source filenames matched '\./main\.cpp'\. \"")
+
+ # Test that -symbol-list-lines works when file is specified using absolute path
+ import os
+ path = os.path.join(os.getcwd(), "main.cpp")
+ self.runCmd("-symbol-list-lines \"%s\"" % path)
+ self.expect("\^done,lines=\[\{pc=\"0x0*%x\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d+\"\})+\]" % (addr, line))
+
+ # Test that -symbol-list-lines fails when file doesn't exist
+ self.runCmd("-symbol-list-lines unknown_dir/main.cpp")
+ self.expect("\^error,message=\"error: No source filenames matched 'unknown_dir/main\.cpp'\. \"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp
new file mode 100644
index 0000000..6d725a5
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp
@@ -0,0 +1,18 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern int j;
+extern int gfunc(int i);
+extern int gfunc2(int i);
+int
+main()
+{ // FUNC_main
+ int i = gfunc(j) + gfunc2(j);
+ return i == 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp
new file mode 100644
index 0000000..c432ba8
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp
@@ -0,0 +1,39 @@
+// Skip lines so we can make sure we're not seeing any lines from
+// symbol_list_lines_inline_test.h included in -symbol-list-lines
+// symbol_list_lines_inline_test.cpp, by checking that all the lines
+// are between 30 and 39.
+// line 5
+// line 6
+// line 7
+// line 8
+// line 9
+// line 10
+// line 11
+// line 12
+// line 13
+// line 14
+// line 15
+// line 16
+// line 17
+// line 18
+// line 19
+// line 20
+// line 21
+// line 22
+// line 23
+// line 24
+// line 25
+// line 26
+// line 27
+// line 28
+// line 29
+#include "symbol_list_lines_inline_test.h"
+int
+gfunc(int i)
+{ // FUNC_gfunc
+ return ns::ifunc(i);
+}
+namespace ns
+{
+S s; // STRUCT_s
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
new file mode 100644
index 0000000..4b986dc
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
@@ -0,0 +1,24 @@
+namespace ns
+{
+inline int
+ifunc(int i)
+{ // FUNC_ifunc
+ return i;
+}
+struct S
+{
+ int a;
+ int b;
+ S()
+ : a(3)
+ , b(4)
+ {
+ }
+ int
+ mfunc()
+ { // FUNC_mfunc
+ return a + b;
+ }
+};
+extern S s;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp
new file mode 100644
index 0000000..cfedf47
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp
@@ -0,0 +1,38 @@
+// Skip lines so we can make sure we're not seeing any lines from
+// symbol_list_lines_inline_test.h included in -symbol-list-lines
+// symbol_list_lines_inline_test2.cpp, by checking that all the lines
+// are between 30 and 39.
+// line 5
+// line 6
+// line 7
+// line 8
+// line 9
+// line 10
+// line 11
+// line 12
+// line 13
+// line 14
+// line 15
+// line 16
+// line 17
+// line 18
+// line 19
+// line 20
+// line 21
+// line 22
+// line 23
+// line 24
+// line 25
+// line 26
+// line 27
+// line 28
+// line 29
+#include "symbol_list_lines_inline_test.h"
+int j = 2;
+int
+gfunc2(int i)
+{ // FUNC_gfunc2
+ i += ns::s.mfunc();
+ i += ns::ifunc(i);
+ return i == 0; // END_gfunc2
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/TestMiSyntax.py b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/TestMiSyntax.py
new file mode 100644
index 0000000..f8a6743
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/TestMiSyntax.py
@@ -0,0 +1,80 @@
+"""
+Test that the lldb-mi driver understands MI command syntax.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiSyntaxTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_tokens(self):
+ """Test that 'lldb-mi --interpreter' prints command tokens."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("000-file-exec-and-symbols %s" % self.myexe)
+ self.expect("000\^done")
+
+ # Run to main
+ self.runCmd("100000001-break-insert -f main")
+ self.expect("100000001\^done,bkpt={number=\"1\"")
+ self.runCmd("2-exec-run")
+ self.expect("2\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Exit
+ self.runCmd("0000000000000000000003-exec-continue")
+ self.expect("0000000000000000000003\^running")
+ self.expect("\*stopped,reason=\"exited-normally\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_specialchars(self):
+ """Test that 'lldb-mi --interpreter' handles complicated strings."""
+
+ # Create an alias for myexe
+ complicated_myexe = "C--mpl-x file's`s @#$%^&*()_+-={}[]| name"
+ os.symlink(self.myexe, complicated_myexe)
+ self.addTearDownHook(lambda: os.unlink(complicated_myexe))
+
+ self.spawnLldbMi(args = "\"%s\"" % complicated_myexe)
+
+ # Test that the executable was loaded
+ self.expect("-file-exec-and-symbols \"%s\"" % complicated_myexe, exactly = True)
+ self.expect("\^done")
+
+ # Check that it was loaded correctly
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @expectedFailureLinux # Failing in ~6/600 dosep runs (build 3120-3122)
+ def test_lldbmi_process_output(self):
+ """Test that 'lldb-mi --interpreter' wraps process output correctly."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+
+ # Test that a process output is wrapped correctly
+ self.expect("\@\"'\\\\r\\\\n\"")
+ self.expect("\@\"` - it's \\\\\\\\n\\\\x12\\\\\"\\\\\\\\\\\\\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/main.cpp
new file mode 100644
index 0000000..d2935b0
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/syntax/main.cpp
@@ -0,0 +1,17 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+int
+main(int argc, char const *argv[])
+{
+ printf("'\n` - it's \\n\x12\"\\\"");
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/target/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/target/Makefile
new file mode 100644
index 0000000..b2550fe
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/target/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := test_attach.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/target/TestMiTarget.py b/packages/Python/lldbsuite/test/tools/lldb-mi/target/TestMiTarget.py
new file mode 100644
index 0000000..73ef913
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/target/TestMiTarget.py
@@ -0,0 +1,125 @@
+"""
+Test lldb-mi -target-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiTargetTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # cannot attach to process on linux
+ def test_lldbmi_target_attach_wait_for(self):
+ """Test that 'lldb-mi --interpreter' works for -target-attach -n <name> --waitfor."""
+
+ # Build target executable with unique name
+ exeName = self.testMethodName
+ d = {'EXE': exeName}
+ self.buildProgram("test_attach.cpp", exeName)
+ self.addTearDownCleanup(dictionary=d)
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ # FIXME: -file-exec-and-sybmols is not required for target attach, but the test will not pass without this
+ self.runCmd("-file-exec-and-symbols %s" % exeName)
+ self.expect("\^done")
+
+ # Set up attach
+ self.runCmd("-target-attach -n %s --waitfor" % exeName)
+ time.sleep(4) # Give attach time to setup
+
+ # Start target process
+ self.spawnSubprocess(os.path.join(os.path.dirname(__file__), exeName));
+ self.addTearDownHook(self.cleanupSubprocesses)
+ self.expect("\^done")
+
+ # Set breakpoint on printf
+ line = line_number('test_attach.cpp', '// BP_i++')
+ self.runCmd("-break-insert -f test_attach.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Continue to breakpoint
+ self.runCmd("-exec-continue")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Detach
+ self.runCmd("-target-detach")
+ self.expect("\^done")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # cannot attach to process on linux
+ def test_lldbmi_target_attach_name(self):
+ """Test that 'lldb-mi --interpreter' works for -target-attach -n <name>."""
+
+ # Build target executable with unique name
+ exeName = self.testMethodName
+ d = {'EXE': exeName}
+ self.buildProgram("test_attach.cpp", exeName)
+ self.addTearDownCleanup(dictionary=d)
+
+ # Start target process
+ targetProcess = self.spawnSubprocess(os.path.join(os.path.dirname(__file__), exeName));
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ self.spawnLldbMi(args = None)
+
+ # Set up atatch
+ self.runCmd("-target-attach -n %s" % exeName)
+ self.expect("\^done")
+
+ # Set breakpoint on printf
+ line = line_number('test_attach.cpp', '// BP_i++')
+ self.runCmd("-break-insert -f test_attach.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Continue to breakpoint
+ self.runCmd("-exec-continue")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Detach
+ self.runCmd("-target-detach")
+ self.expect("\^done")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # cannot attach to process on linux
+ def test_lldbmi_target_attach_pid(self):
+ """Test that 'lldb-mi --interpreter' works for -target-attach <pid>."""
+
+ # Build target executable with unique name
+ exeName = self.testMethodName
+ d = {'EXE': exeName}
+ self.buildProgram("test_attach.cpp", exeName)
+ self.addTearDownCleanup(dictionary=d)
+
+ # Start target process
+ targetProcess = self.spawnSubprocess(os.path.join(os.path.dirname(__file__), exeName));
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ self.spawnLldbMi(args = None)
+
+ # Set up atatch
+ self.runCmd("-target-attach %d" % targetProcess.pid)
+ self.expect("\^done")
+
+ # Set breakpoint on printf
+ line = line_number('test_attach.cpp', '// BP_i++')
+ self.runCmd("-break-insert -f test_attach.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+
+ # Continue to breakpoint
+ self.runCmd("-exec-continue")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Detach
+ self.runCmd("-target-detach")
+ self.expect("\^done")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/target/test_attach.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/target/test_attach.cpp
new file mode 100644
index 0000000..caaf33a
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/target/test_attach.cpp
@@ -0,0 +1,21 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+
+int
+main(int argc, char const *argv[])
+{
+ int i = 0;
+ for (;;)
+ {
+ i++; // BP_i++
+ }
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/variable/Makefile b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiGdbSetShowPrint.py b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiGdbSetShowPrint.py
new file mode 100644
index 0000000..067df64
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiGdbSetShowPrint.py
@@ -0,0 +1,227 @@
+#coding=utf8
+"""
+Test lldb-mi -gdb-set and -gdb-show commands for 'print option-name'.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiGdbSetShowTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ # evaluates array when char-array-as-string is off
+ def eval_and_check_array(self, var, typ, length):
+ self.runCmd("-var-create - * %s" % var)
+ self.expect('\^done,name="var\d+",numchild="%d",value="\[%d\]",type="%s \[%d\]",thread-id="1",has_more="0"' % (length, length, typ, length))
+
+ # evaluates any type which can be represented as string of characters
+ def eval_and_match_string(self, var, value, typ):
+ value=value.replace("\\", "\\\\").replace("\"", "\\\"")
+ self.runCmd("-var-create - * " + var)
+ self.expect('\^done,name="var\d+",numchild="[0-9]+",value="%s",type="%s",thread-id="1",has_more="0"' % (value, typ))
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_gdb_set_show_print_char_array_as_string(self):
+ """Test that 'lldb-mi --interpreter' can print array of chars as string."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_gdb_set_show_print_char_array_as_string_test
+ line = line_number('main.cpp', '// BP_gdb_set_show_print_char_array_as_string_test')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that default print char-array-as-string value is "off"
+ self.runCmd("-gdb-show print char-array-as-string")
+ self.expect("\^done,value=\"off\"")
+
+ # Test that a char* is expanded to string when print char-array-as-string is "off"
+ self.eval_and_match_string("cp", r'0x[0-9a-f]+ \"\\t\\\"hello\\\"\\n\"', r'const char \*')
+
+ # Test that a char[] isn't expanded to string when print char-array-as-string is "off"
+ self.eval_and_check_array("ca", "const char", 10);
+
+ # Test that a char16_t* is expanded to string when print char-array-as-string is "off"
+ self.eval_and_match_string("u16p", r'0x[0-9a-f]+ u\"\\t\\\"hello\\\"\\n\"', r'const char16_t \*')
+
+ # Test that a char16_t[] isn't expanded to string when print char-array-as-string is "off"
+ self.eval_and_check_array("u16a", "const char16_t", 10);
+
+ # Test that a char32_t* is expanded to string when print char-array-as-string is "off"
+ self.eval_and_match_string("u32p", r'0x[0-9a-f]+ U\"\\t\\\"hello\\\"\\n\"', r'const char32_t \*')
+
+ # Test that a char32_t[] isn't expanded to string when print char-array-as-string is "off"
+ self.eval_and_check_array("u32a", "const char32_t", 10);
+
+ # Test that -gdb-set can set print char-array-as-string flag
+ self.runCmd("-gdb-set print char-array-as-string on")
+ self.expect("\^done")
+ self.runCmd("-gdb-set print char-array-as-string 1")
+ self.expect("\^done")
+ self.runCmd("-gdb-show print char-array-as-string")
+ self.expect("\^done,value=\"on\"")
+
+ # Test that a char* with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("cp", r'0x[0-9a-f]+ \"\\t\\\"hello\\\"\\n\"', r'const char \*')
+
+ # Test that a char[] with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("ca", r'\"\\t\\\"hello\\\"\\n\"', r'const char \[10\]')
+
+ # Test that a char16_t* with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("u16p", r'0x[0-9a-f]+ u\"\\t\\\"hello\\\"\\n\"', r'const char16_t \*')
+
+ # Test that a char16_t[] with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("u16a", r'u\"\\t\\\"hello\\\"\\n\"', r'const char16_t \[10\]')
+
+ # Test that a char32_t* with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("u32p", r'0x[0-9a-f]+ U\"\\t\\\"hello\\\"\\n\"', r'const char32_t \*')
+
+ # Test that a char32_t[] with escape chars is expanded to string when print char-array-as-string is "on"
+ self.eval_and_match_string("u32a", r'U\"\\t\\\"hello\\\"\\n\"', r'const char32_t \[10\]')
+
+ # Test russian unicode strings
+ self.eval_and_match_string("u16p_rus", r'0x[0-9a-f]+ u\"\\\\Аламо-сквер\"', r'const char16_t \*')
+ self.eval_and_match_string("u16a_rus", r'u\"\\\\Бейвью\"', r'const char16_t \[8\]')
+ self.eval_and_match_string("u32p_rus", r'0x[0-9a-f]+ U\"\\\\Чайнатаун\"', r'const char32_t \*')
+ self.eval_and_match_string("u32a_rus", r'U\"\\\\Догпатч\"', r'const char32_t \[9\]')
+
+ # Test that -gdb-set print char-array-as-string fails if "on"/"off" isn't specified
+ self.runCmd("-gdb-set print char-array-as-string")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
+
+ # Test that -gdb-set print char-array-as-string fails when option is unknown
+ self.runCmd("-gdb-set print char-array-as-string unknown")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi working on Windows
+ @expectedFailureGcc("https://llvm.org/bugs/show_bug.cgi?id=23357")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_set_show_print_expand_aggregates(self):
+ """Test that 'lldb-mi --interpreter' can expand aggregates everywhere."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_gdb_set_show_print_expand_aggregates
+ line = line_number('main.cpp', '// BP_gdb_set_show_print_expand_aggregates')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that default print expand-aggregates value is "off"
+ self.runCmd("-gdb-show print expand-aggregates")
+ self.expect("\^done,value=\"off\"")
+
+ # Test that composite type isn't expanded when print expand-aggregates is "off"
+ self.runCmd("-var-create var1 * complx")
+ self.expect("\^done,name=\"var1\",numchild=\"3\",value=\"{\.\.\.}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that composite type[] isn't expanded when print expand-aggregates is "off"
+ self.eval_and_check_array("complx_array", "complex_type", 2)
+
+ # Test that a struct with a char first element is not formatted as a string
+ self.runCmd("-var-create - * &nstr")
+ self.expect("\^done,name=\"var\d+\",numchild=\"2\",value=\"0x[0-9a-f]+\",type=\"not_str \*\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that -gdb-set can set print expand-aggregates flag
+ self.runCmd("-gdb-set print expand-aggregates on")
+ self.expect("\^done")
+ self.runCmd("-gdb-set print expand-aggregates 1")
+ self.expect("\^done")
+ self.runCmd("-gdb-show print expand-aggregates")
+ self.expect("\^done,value=\"on\"")
+
+ # Test that composite type is expanded when print expand-aggregates is "on"
+ self.runCmd("-var-create var3 * complx")
+ self.expect("\^done,name=\"var3\",numchild=\"3\",value=\"{i = 3, inner = {l = 3}, complex_ptr = 0x[0-9a-f]+}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that composite type[] is expanded when print expand-aggregates is "on"
+ self.runCmd("-var-create var4 * complx_array")
+ self.expect("\^done,name=\"var4\",numchild=\"2\",value=\"{\[0\] = {i = 4, inner = {l = 4}, complex_ptr = 0x[0-9a-f]+}, \[1\] = {i = 5, inner = {l = 5}, complex_ptr = 0x[0-9a-f]+}}\",type=\"complex_type \[2\]\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that -gdb-set print expand-aggregates fails if "on"/"off" isn't specified
+ self.runCmd("-gdb-set print expand-aggregates")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
+
+ # Test that -gdb-set print expand-aggregates fails when option is unknown
+ self.runCmd("-gdb-set print expand-aggregates unknown")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi working on Windows
+ @expectedFailureGcc("https://llvm.org/bugs/show_bug.cgi?id=23357")
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_gdb_set_show_print_aggregate_field_names(self):
+ """Test that 'lldb-mi --interpreter' can expand aggregates everywhere."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_gdb_set_show_print_aggregate_field_names
+ line = line_number('main.cpp', '// BP_gdb_set_show_print_aggregate_field_names')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that default print aggregatep-field-names value is "on"
+ self.runCmd("-gdb-show print aggregate-field-names")
+ self.expect("\^done,value=\"on\"")
+
+ # Set print expand-aggregates flag to "on"
+ self.runCmd("-gdb-set print expand-aggregates on")
+ self.expect("\^done")
+
+ # Test that composite type is expanded with field name when print aggregate-field-names is "on"
+ self.runCmd("-var-create var1 * complx")
+ self.expect("\^done,name=\"var1\",numchild=\"3\",value=\"{i = 3, inner = {l = 3}, complex_ptr = 0x[0-9a-f]+}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that composite type[] is expanded with field name when print aggregate-field-names is "on"
+ self.runCmd("-var-create var2 * complx_array")
+ self.expect("\^done,name=\"var2\",numchild=\"2\",value=\"{\[0\] = {i = 4, inner = {l = 4}, complex_ptr = 0x[0-9a-f]+}, \[1\] = {i = 5, inner = {l = 5}, complex_ptr = 0x[0-9a-f]+}}\",type=\"complex_type \[2\]\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that -gdb-set can set print aggregate-field-names flag
+ self.runCmd("-gdb-set print aggregate-field-names off")
+ self.expect("\^done")
+ self.runCmd("-gdb-set print aggregate-field-names 0")
+ self.expect("\^done")
+ self.runCmd("-gdb-show print aggregate-field-names")
+ self.expect("\^done,value=\"off\"")
+
+ # Test that composite type is expanded without field name when print aggregate-field-names is "off"
+ self.runCmd("-var-create var3 * complx")
+ self.expect("\^done,name=\"var3\",numchild=\"3\",value=\"{3,\{3\},0x[0-9a-f]+}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that composite type[] is expanded without field name when print aggregate-field-names is "off"
+ self.runCmd("-var-create var4 * complx_array")
+ self.expect("\^done,name=\"var4\",numchild=\"2\",value=\"{{4,\{4\},0x[0-9a-f]+},{5,\{5\},0x[0-9a-f]+}}\",type=\"complex_type \[2\]\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that -gdb-set print aggregate-field-names fails if "on"/"off" isn't specified
+ self.runCmd("-gdb-set print aggregate-field-names")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
+
+ # Test that -gdb-set print aggregate-field-names fails when option is unknown
+ self.runCmd("-gdb-set print aggregate-field-names unknown")
+ self.expect("\^error,msg=\"The request ''print' expects option-name and \"on\" or \"off\"' failed.\"")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiVar.py b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiVar.py
new file mode 100644
index 0000000..26f3a9c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiVar.py
@@ -0,0 +1,396 @@
+"""
+Test lldb-mi -var-xxx commands.
+"""
+
+from __future__ import print_function
+
+
+
+import lldbmi_testcase
+from lldbsuite.test.lldbtest import *
+
+class MiVarTestCase(lldbmi_testcase.MiTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_eval(self):
+ """Test that 'lldb-mi --interpreter' works for evaluating."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to program return
+ line = line_number('main.cpp', '// BP_return')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Print non-existant variable
+ self.runCmd("-var-create var1 * undef")
+ self.expect("\^error,msg=\"error: error: use of undeclared identifier \'undef\'\\\\nerror: 1 errors parsing expression\\\\n\"")
+ self.runCmd("-data-evaluate-expression undef")
+ self.expect("\^error,msg=\"Could not evaluate expression\"")
+
+ # Print global "g_MyVar", modify, delete and create again
+ self.runCmd("-data-evaluate-expression g_MyVar")
+ self.expect("\^done,value=\"3\"")
+ self.runCmd("-var-create var2 * g_MyVar")
+ self.expect("\^done,name=\"var2\",numchild=\"0\",value=\"3\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-evaluate-expression var2")
+ self.expect("\^done,value=\"3\"")
+ self.runCmd("-var-show-attributes var2")
+ self.expect("\^done,status=\"editable\"")
+ self.runCmd("-var-list-children var2")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+ # Ensure -var-list-children also works with quotes
+ self.runCmd("-var-list-children \"var2\"")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+ self.runCmd("-data-evaluate-expression \"g_MyVar=30\"")
+ self.expect("\^done,value=\"30\"")
+ self.runCmd("-var-update --all-values var2")
+ #self.expect("\^done,changelist=\[\{name=\"var2\",value=\"30\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]") #FIXME -var-update doesn't work
+ self.runCmd("-var-delete var2")
+ self.expect("\^done")
+ self.runCmd("-var-create var2 * g_MyVar")
+ self.expect("\^done,name=\"var2\",numchild=\"0\",value=\"30\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+
+ # Print static "s_MyVar", modify, delete and create again
+ self.runCmd("-data-evaluate-expression s_MyVar")
+ self.expect("\^done,value=\"30\"")
+ self.runCmd("-var-create var3 * s_MyVar")
+ self.expect("\^done,name=\"var3\",numchild=\"0\",value=\"30\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-evaluate-expression var3")
+ self.expect("\^done,value=\"30\"")
+ self.runCmd("-var-show-attributes var3")
+ self.expect("\^done,status=\"editable\"")
+ self.runCmd("-var-list-children var3")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+ self.runCmd("-data-evaluate-expression \"s_MyVar=3\"")
+ self.expect("\^done,value=\"3\"")
+ self.runCmd("-var-update --all-values var3")
+ #self.expect("\^done,changelist=\[\{name=\"var3\",value=\"3\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]") #FIXME -var-update doesn't work
+ self.runCmd("-var-delete var3")
+ self.expect("\^done")
+ self.runCmd("-var-create var3 * s_MyVar")
+ self.expect("\^done,name=\"var3\",numchild=\"0\",value=\"3\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+
+ # Print local "b", modify, delete and create again
+ self.runCmd("-data-evaluate-expression b")
+ self.expect("\^done,value=\"20\"")
+ self.runCmd("-var-create var4 * b")
+ self.expect("\^done,name=\"var4\",numchild=\"0\",value=\"20\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-evaluate-expression var4")
+ self.expect("\^done,value=\"20\"")
+ self.runCmd("-var-show-attributes var4")
+ self.expect("\^done,status=\"editable\"")
+ self.runCmd("-var-list-children var4")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+ self.runCmd("-data-evaluate-expression \"b=2\"")
+ self.expect("\^done,value=\"2\"")
+ self.runCmd("-var-update --all-values var4")
+ #self.expect("\^done,changelist=\[\{name=\"var4\",value=\"2\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]") #FIXME -var-update doesn't work
+ self.runCmd("-var-delete var4")
+ self.expect("\^done")
+ self.runCmd("-var-create var4 * b")
+ self.expect("\^done,name=\"var4\",numchild=\"0\",value=\"2\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+
+ # Print temp "a + b"
+ self.runCmd("-data-evaluate-expression \"a + b\"")
+ self.expect("\^done,value=\"12\"")
+ self.runCmd("-var-create var5 * \"a + b\"")
+ self.expect("\^done,name=\"var5\",numchild=\"0\",value=\"12\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-evaluate-expression var5")
+ self.expect("\^done,value=\"12\"")
+ self.runCmd("-var-show-attributes var5")
+ self.expect("\^done,status=\"editable\"") #FIXME editable or not?
+ self.runCmd("-var-list-children var5")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+
+ # Print argument "argv[0]"
+ self.runCmd("-data-evaluate-expression \"argv[0]\"")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \\\\\\\".*?%s\\\\\\\"\"" % self.myexe)
+ self.runCmd("-var-create var6 * \"argv[0]\"")
+ self.expect("\^done,name=\"var6\",numchild=\"1\",value=\"0x[0-9a-f]+ \\\\\\\".*?%s\\\\\\\"\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"" % self.myexe)
+ self.runCmd("-var-evaluate-expression var6")
+ self.expect("\^done,value=\"0x[0-9a-f]+ \\\\\\\".*?%s\\\\\\\"\"" % self.myexe)
+ self.runCmd("-var-show-attributes var6")
+ self.expect("\^done,status=\"editable\"")
+ self.runCmd("-var-list-children --all-values var6")
+ # FIXME: The name below is not correct. It should be "var.*argv[0]".
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var6\.\*\$[0-9]+\",exp=\"\*\$[0-9]+\",numchild=\"0\",type=\"const char\",thread-id=\"4294967295\",value=\"47 '/'\",has_more=\"0\"\}\],has_more=\"0\"") #FIXME -var-list-children shows invalid thread-id
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_var_update(self):
+ """Test that 'lldb-mi --interpreter' works for -var-update."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_var_update_test_init
+ line = line_number('main.cpp', '// BP_var_update_test_init')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Setup variables
+ self.runCmd("-var-create var_l * l")
+ self.expect("\^done,name=\"var_l\",numchild=\"0\",value=\"1\",type=\"long\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-create var_complx * complx")
+ self.expect("\^done,name=\"var_complx\",numchild=\"3\",value=\"\{\.\.\.\}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-create var_complx_array * complx_array")
+ self.expect("\^done,name=\"var_complx_array\",numchild=\"2\",value=\"\[2\]\",type=\"complex_type \[2\]\",thread-id=\"1\",has_more=\"0\"")
+
+ # Go to BP_var_update_test_l
+ line = line_number('main.cpp', '// BP_var_update_test_l')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"2\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that var_l was updated
+ self.runCmd("-var-update --all-values var_l")
+ self.expect("\^done,changelist=\[\{name=\"var_l\",value=\"0\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]")
+
+ # Go to BP_var_update_test_complx
+ line = line_number('main.cpp', '// BP_var_update_test_complx')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"3\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that var_complx was updated
+ self.runCmd("-var-update --all-values var_complx")
+ self.expect("\^done,changelist=\[\{name=\"var_complx\",value=\"\{\.\.\.\}\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]")
+
+ # Go to BP_var_update_test_complx_array
+ line = line_number('main.cpp', '// BP_var_update_test_complx_array')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"4\"")
+ self.runCmd("-exec-continue")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test that var_complex_array was updated
+ self.runCmd("-var-update --all-values var_complx_array")
+ self.expect("\^done,changelist=\[\{name=\"var_complx_array\",value=\"\[2\]\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\]")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ def test_lldbmi_var_create_register(self):
+ """Test that 'lldb-mi --interpreter' works for -var-create $regname."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to main
+ self.runCmd("-break-insert -f main")
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Find name of register 0
+ self.runCmd("-data-list-register-names 0")
+ self.expect("\^done,register-names=\[\".+?\"\]")
+ register_name = self.child.after.split("\"")[1]
+
+ # Create variable for register 0
+ # Note that message is different in Darwin and Linux:
+ # Darwin: "^done,name=\"var_reg\",numchild=\"0\",value=\"0x[0-9a-f]+\",type=\"unsigned long\",thread-id=\"1\",has_more=\"0\"
+ # Linux: "^done,name=\"var_reg\",numchild=\"0\",value=\"0x[0-9a-f]+\",type=\"unsigned int\",thread-id=\"1\",has_more=\"0\"
+ self.runCmd("-var-create var_reg * $%s" % register_name)
+ self.expect("\^done,name=\"var_reg\",numchild=\"0\",value=\"0x[0-9a-f]+\",type=\"unsigned (long|int)\",thread-id=\"1\",has_more=\"0\"")
+
+ # Assign value to variable
+ self.runCmd("-var-assign var_reg \"6\"")
+ #FIXME: the output has different format for 32bit and 64bit values
+ self.expect("\^done,value=\"0x0*?6\"")
+
+ # Assert register 0 updated
+ self.runCmd("-data-list-register-values d 0")
+ self.expect("\^done,register-values=\[{number=\"0\",value=\"6\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_var_list_children(self):
+ """Test that 'lldb-mi --interpreter' works for -var-list-children."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_var_list_children_test
+ line = line_number('main.cpp', '// BP_var_list_children_test')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Create variable
+ self.runCmd("-var-create var_complx * complx")
+ self.expect("\^done,name=\"var_complx\",numchild=\"3\",value=\"\{\.\.\.\}\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-create var_complx_array * complx_array")
+ self.expect("\^done,name=\"var_complx_array\",numchild=\"2\",value=\"\[2\]\",type=\"complex_type \[2\]\",thread-id=\"1\",has_more=\"0\"")
+ self.runCmd("-var-create var_pcomplx * pcomplx")
+ self.expect("\^done,name=\"var_pcomplx\",numchild=\"2\",value=\"\{\.\.\.\}\",type=\"pcomplex_type\",thread-id=\"1\",has_more=\"0\"")
+
+ # Test that -var-evaluate-expression can evaluate the children of created varobj
+ self.runCmd("-var-list-children var_complx")
+ self.runCmd("-var-evaluate-expression var_complx.i")
+ self.expect("\^done,value=\"3\"")
+ self.runCmd("-var-list-children var_complx_array")
+ self.runCmd("-var-evaluate-expression var_complx_array.[0]")
+ self.expect("\^done,value=\"\{...\}\"")
+ self.runCmd("-var-list-children var_pcomplx")
+ self.runCmd("-var-evaluate-expression var_pcomplx.complex_type")
+ self.expect("\^done,value=\"\{...\}\"")
+
+ # Test that -var-list-children lists empty children if range is empty
+ # (and that print-values is optional)
+ self.runCmd("-var-list-children var_complx 0 0")
+ self.expect("\^done,numchild=\"0\",has_more=\"1\"")
+ self.runCmd("-var-list-children var_complx 99 0")
+ self.expect("\^done,numchild=\"0\",has_more=\"1\"")
+ self.runCmd("-var-list-children var_complx 99 3")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+
+ # Test that -var-list-children lists all children with their values
+ # (and that from and to are optional)
+ self.runCmd("-var-list-children --all-values var_complx")
+ self.expect("\^done,numchild=\"3\",children=\[child=\{name=\"var_complx\.i\",exp=\"i\",numchild=\"0\",type=\"int\",thread-id=\"1\",value=\"3\",has_more=\"0\"\},child=\{name=\"var_complx\.inner\",exp=\"inner\",numchild=\"1\",type=\"complex_type::\(anonymous struct\)\",thread-id=\"1\",value=\"\{\.\.\.\}\",has_more=\"0\"\},child=\{name=\"var_complx\.complex_ptr\",exp=\"complex_ptr\",numchild=\"3\",type=\"complex_type \*\",thread-id=\"1\",value=\"0x[0-9a-f]+\",has_more=\"0\"\}\],has_more=\"0\"")
+ self.runCmd("-var-list-children --simple-values var_complx_array")
+ self.expect("\^done,numchild=\"2\",children=\[child=\{name=\"var_complx_array\.\[0\]\",exp=\"\[0\]\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\},child=\{name=\"var_complx_array\.\[1\]\",exp=\"\[1\]\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"0\"")
+ self.runCmd("-var-list-children 0 var_pcomplx")
+ self.expect("\^done,numchild=\"2\",children=\[child=\{name=\"var_pcomplx\.complex_type\",exp=\"complex_type\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\},child={name=\"var_pcomplx\.complx\",exp=\"complx\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"0\"")
+
+ # Test that -var-list-children lists children without values
+ self.runCmd("-var-list-children 0 var_complx 0 1")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.i\",exp=\"i\",numchild=\"0\",type=\"int\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"1\"")
+ self.runCmd("-var-list-children --no-values var_complx 0 1")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.i\",exp=\"i\",numchild=\"0\",type=\"int\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"1\"")
+ self.runCmd("-var-list-children --no-values var_complx_array 0 1")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx_array\.\[0\]\",exp=\"\[0\]\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"1\"")
+ self.runCmd("-var-list-children --no-values var_pcomplx 0 1")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_pcomplx\.complex_type\",exp=\"complex_type\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"1\"")
+
+ # Test that -var-list-children lists children with all values
+ self.runCmd("-var-list-children 1 var_complx 1 2")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.inner\",exp=\"inner\",numchild=\"1\",type=\"complex_type::\(anonymous struct\)\",thread-id=\"1\",value=\"\{\.\.\.\}\",has_more=\"0\"\}\],has_more=\"1\"")
+ self.runCmd("-var-list-children --all-values var_complx 1 2")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.inner\",exp=\"inner\",numchild=\"1\",type=\"complex_type::\(anonymous struct\)\",thread-id=\"1\",value=\"\{\.\.\.\}\",has_more=\"0\"\}\],has_more=\"1\"")
+ self.runCmd("-var-list-children --all-values var_complx_array 1 2")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx_array\.\[1\]\",exp=\"\[1\]\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",value=\"\{\.\.\.\}\",has_more=\"0\"\}\],has_more=\"0\"")
+ self.runCmd("-var-list-children --all-values var_pcomplx 1 2")
+ self.expect("\^done,numchild=\"1\",children=\[child={name=\"var_pcomplx\.complx\",exp=\"complx\",numchild=\"3\",type=\"complex_type\",thread-id=\"1\",value=\"\{\.\.\.\}\",has_more=\"0\"\}\],has_more=\"0\"")
+
+ # Test that -var-list-children lists children with simple values
+ self.runCmd("-var-list-children 2 var_complx 2 4")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.complex_ptr\",exp=\"complex_ptr\",numchild=\"3\",type=\"complex_type \*\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"0\"")
+ self.runCmd("-var-list-children --simple-values var_complx 2 4")
+ self.expect("\^done,numchild=\"1\",children=\[child=\{name=\"var_complx\.complex_ptr\",exp=\"complex_ptr\",numchild=\"3\",type=\"complex_type \*\",thread-id=\"1\",has_more=\"0\"\}\],has_more=\"0\"")
+ self.runCmd("-var-list-children --simple-values var_complx_array 2 4")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+ self.runCmd("-var-list-children --simple-values var_pcomplx 2 4")
+ self.expect("\^done,numchild=\"0\",has_more=\"0\"")
+
+ # Test that an invalid from is handled
+ # FIXME: -1 is treated as unsigned int
+ self.runCmd("-var-list-children 0 var_complx -1 0")
+ #self.expect("\^error,msg=\"Command 'var-list-children'\. Variable children range invalid\"")
+
+ # Test that an invalid to is handled
+ # FIXME: -1 is treated as unsigned int
+ self.runCmd("-var-list-children 0 var_complx 0 -1")
+ #self.expect("\^error,msg=\"Command 'var-list-children'\. Variable children range invalid\"")
+
+ # Test that a missing low-frame or high-frame is handled
+ self.runCmd("-var-list-children 0 var_complx 0")
+ self.expect("\^error,msg=\"Command 'var-list-children'. Variable children range invalid\"")
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_var_create_for_stl_types(self):
+ """Test that 'lldb-mi --interpreter' print summary for STL types."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to BP_gdb_set_show_print_char_array_as_string_test
+ line = line_number('main.cpp', '// BP_cpp_stl_types_test')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Test for std::string
+ self.runCmd("-var-create - * std_string")
+ self.expect('\^done,name="var\d+",numchild="[0-9]+",value="\\\\"hello\\\\"",type="std::[\S]*?string",thread-id="1",has_more="0"')
+
+ @skipIfWindows #llvm.org/pr24452: Get lldb-mi working on Windows
+ @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+ @skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
+ def test_lldbmi_var_create_for_unnamed_objects(self):
+ """Test that 'lldb-mi --interpreter' can expand unnamed structures and unions."""
+
+ self.spawnLldbMi(args = None)
+
+ # Load executable
+ self.runCmd("-file-exec-and-symbols %s" % self.myexe)
+ self.expect("\^done")
+
+ # Run to breakpoint
+ line = line_number('main.cpp', '// BP_unnamed_objects_test')
+ self.runCmd("-break-insert main.cpp:%d" % line)
+ self.expect("\^done,bkpt={number=\"1\"")
+ self.runCmd("-exec-run")
+ self.expect("\^running")
+ self.expect("\*stopped,reason=\"breakpoint-hit\"")
+
+ # Evaluate struct_with_unions type and its children
+ self.runCmd("-var-create v0 * swu")
+ self.expect('\^done,name="v0",numchild="2",value="\{\.\.\.\}",type="struct_with_unions",thread-id="1",has_more="0"')
+
+ self.runCmd("-var-list-children v0")
+
+ # inspect the first unnamed union
+ self.runCmd("-var-list-children v0.$0")
+ self.runCmd("-var-evaluate-expression v0.$0.u_i")
+ self.expect('\^done,value="1"')
+
+ # inspect the second unnamed union
+ self.runCmd("-var-list-children v0.$1")
+ self.runCmd("-var-evaluate-expression v0.$1.u1")
+ self.expect('\^done,value="-1"')
+ # inspect unnamed structure
+ self.runCmd("-var-list-children v0.$1.$1")
+ self.runCmd("-var-evaluate-expression v0.$1.$1.s1")
+ self.expect('\^done,value="-1"')
+
diff --git a/packages/Python/lldbsuite/test/tools/lldb-mi/variable/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/main.cpp
new file mode 100644
index 0000000..8c79539
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-mi/variable/main.cpp
@@ -0,0 +1,152 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdint>
+#include <string>
+
+struct complex_type
+{
+ int i;
+ struct { long l; } inner;
+ complex_type *complex_ptr;
+};
+
+struct pcomplex_type : complex_type
+{
+ pcomplex_type(const complex_type &complx_base, const complex_type &complx_member)
+ : complex_type(complx_base), complx(complx_member) { }
+ complex_type complx;
+ static int si;
+};
+
+int pcomplex_type::si;
+
+struct struct_with_unions
+{
+ struct_with_unions(): u_i(1), u1(-1) {}
+ union
+ {
+ int u_i;
+ int u_j;
+ };
+ union
+ {
+ int u1;
+ struct
+ {
+ short s1;
+ short s2;
+ };
+ };
+};
+
+void
+var_update_test(void)
+{
+ long l = 1;
+ complex_type complx = { 3, { 3L }, &complx };
+ complex_type complx_array[2] = { { 4, { 4L }, &complx_array[1] }, { 5, { 5 }, &complx_array[0] } };
+ // BP_var_update_test_init
+
+ l = 0;
+ // BP_var_update_test_l
+
+ complx.inner.l = 2;
+ // BP_var_update_test_complx
+
+ complx_array[1].inner.l = 4;
+ // BP_var_update_test_complx_array
+}
+
+void
+var_list_children_test(void)
+{
+ complex_type complx = { 3, { 3L }, &complx };
+ complex_type complx_array[2] = { { 4, { 4L }, &complx_array[1] }, { 5, { 5 }, &complx_array[0] } };
+ pcomplex_type pcomplx({ 6, { 6L }, &pcomplx}, { 7, { 7L }, &pcomplx});
+
+ // BP_var_list_children_test
+}
+
+void
+gdb_set_show_print_char_array_as_string_test(void)
+{
+ const char *cp = "\t\"hello\"\n";
+ const char ca[] = "\t\"hello\"\n";
+ const char16_t *u16p = u"\t\"hello\"\n";
+ const char16_t u16a[] = u"\t\"hello\"\n";
+ const char32_t *u32p = U"\t\"hello\"\n";
+ const char32_t u32a[] = U"\t\"hello\"\n";
+
+ const char16_t* u16p_rus = u"\\Аламо-сквер";
+ const char16_t u16a_rus[] = u"\\Бейвью";
+ const char32_t* u32p_rus = U"\\Чайнатаун";
+ const char32_t u32a_rus[] = U"\\Догпатч";
+
+ // BP_gdb_set_show_print_char_array_as_string_test
+}
+
+void
+cpp_stl_types_test(void)
+{
+ std::string std_string = "hello";
+ // BP_cpp_stl_types_test
+}
+
+void
+unnamed_objects_test(void)
+{
+ struct_with_unions swu;
+ // BP_unnamed_objects_test
+}
+
+struct not_str
+{
+ not_str(char _c, int _f)
+ : c(_c), f(_f) { }
+ char c;
+ int f;
+};
+
+void
+gdb_set_show_print_expand_aggregates(void)
+{
+ complex_type complx = { 3, { 3L }, &complx };
+ complex_type complx_array[2] = { { 4, { 4L }, &complx_array[1] }, { 5, { 5 }, &complx_array[0] } };
+ not_str nstr('a', 0);
+
+ // BP_gdb_set_show_print_expand_aggregates
+}
+
+void
+gdb_set_show_print_aggregate_field_names(void)
+{
+ complex_type complx = { 3, { 3L }, &complx };
+ complex_type complx_array[2] = { { 4, { 4L }, &complx_array[1] }, { 5, { 5 }, &complx_array[0] } };
+
+ // BP_gdb_set_show_print_aggregate_field_names
+}
+
+int g_MyVar = 3;
+static int s_MyVar = 4;
+
+int
+main(int argc, char const *argv[])
+{
+ int a = 10, b = 20;
+ s_MyVar = a + b;
+ var_update_test();
+ var_list_children_test();
+ gdb_set_show_print_char_array_as_string_test();
+ cpp_stl_types_test();
+ unnamed_objects_test();
+ gdb_set_show_print_expand_aggregates();
+ gdb_set_show_print_aggregate_field_names();
+ return 0; // BP_return
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/Makefile b/packages/Python/lldbsuite/test/tools/lldb-server/Makefile
new file mode 100644
index 0000000..6ae4e66
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/Makefile
@@ -0,0 +1,8 @@
+LEVEL = ../../make
+
+CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
+ENABLE_THREADS := YES
+CXX_SOURCES := main.cpp
+MAKE_DSYM :=NO
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGDBRemoteMemoryRead.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGDBRemoteMemoryRead.py
new file mode 100644
index 0000000..7b974e5
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGDBRemoteMemoryRead.py
@@ -0,0 +1,41 @@
+"""
+Tests the binary ($x) and hex ($m) memory read packets of the remote stub
+"""
+
+from __future__ import print_function
+
+
+
+import os
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+import binascii
+
+
+class MemoryReadTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipUnlessPlatform(getDarwinOSTriples()+["linux"])
+ def test_memory_read(self):
+ self.build()
+ exe = os.path.join (os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ lldbutil.run_break_set_by_symbol(self, "main")
+
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+ self.assertTrue(process, PROCESS_IS_VALID)
+ self.assertEqual(process.GetState(), lldb.eStateStopped, "Process is stopped")
+
+ pc = process.GetSelectedThread().GetSelectedFrame().GetPC()
+ for size in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]:
+ error = lldb.SBError()
+ memory = process.ReadMemory(pc, size, error)
+ self.assertTrue(error.Success())
+ self.match("process plugin packet send x%x,%x" % (pc, size), ["response:", memory])
+ self.match("process plugin packet send m%x,%x" % (pc, size), ["response:", binascii.hexlify(memory)])
+
+ process.Continue()
+ self.assertEqual(process.GetState(), lldb.eStateExited, "Process exited")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAttach.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAttach.py
new file mode 100644
index 0000000..ca96a9a8
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAttach.py
@@ -0,0 +1,60 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import lldbgdbserverutils
+
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteAttach(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def attach_with_vAttach(self):
+ # Start the inferior, start the debug monitor, nothing is attached yet.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:60"])
+ self.assertIsNotNone(procs)
+
+ # Make sure the target process has been launched.
+ inferior = procs.get("inferior")
+ self.assertIsNotNone(inferior)
+ self.assertTrue(inferior.pid > 0)
+ self.assertTrue(lldbgdbserverutils.process_is_running(inferior.pid, True))
+
+ # Add attach packets.
+ self.test_sequence.add_log_lines([
+ # Do the attach.
+ "read packet: $vAttach;{:x}#00".format(inferior.pid),
+ # Expect a stop notification from the attach.
+ { "direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$", "capture":{1:"stop_signal_hex"} },
+ ], True)
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the process id matches what we expected.
+ pid_text = process_info.get('pid', None)
+ self.assertIsNotNone(pid_text)
+ reported_pid = int(pid_text, base=16)
+ self.assertEqual(reported_pid, inferior.pid)
+
+ @debugserver_test
+ def test_attach_with_vAttach_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach_manually()
+ self.attach_with_vAttach()
+
+ @llgs_test
+ def test_attach_with_vAttach_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach_manually()
+ self.attach_with_vAttach()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAuxvSupport.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAuxvSupport.py
new file mode 100644
index 0000000..1ce5779
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAuxvSupport.py
@@ -0,0 +1,201 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read"
+
+ def has_auxv_support(self):
+ inferior_args = ["message:main entered", "sleep:5"]
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+ # Don't do anything until we match the launched inferior main entry output.
+ # Then immediately interrupt the process.
+ # This prevents auxv data being asked for before it's ready and leaves
+ # us in a stopped state.
+ self.test_sequence.add_log_lines([
+ # Start the inferior...
+ "read packet: $c#63",
+ # ... match output....
+ { "type":"output_match", "regex":r"^message:main entered\r\n$" },
+ ], True)
+ # ... then interrupt.
+ self.add_interrupt_packets()
+ self.add_qSupported_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ features = self.parse_qSupported_response(context)
+ return self.AUXV_SUPPORT_FEATURE_NAME in features and features[self.AUXV_SUPPORT_FEATURE_NAME] == "+"
+
+ def get_raw_auxv_data(self):
+ # Start up llgs and inferior, and check for auxv support.
+ if not self.has_auxv_support():
+ self.skipTest("auxv data not supported")
+
+ # Grab pointer size for target. We'll assume that is equivalent to an unsigned long on the target.
+ # Auxv is specified in terms of pairs of unsigned longs.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ proc_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(proc_info)
+ self.assertTrue("ptrsize" in proc_info)
+ word_size = int(proc_info["ptrsize"])
+
+ OFFSET = 0
+ LENGTH = 0x400
+
+ # Grab the auxv data.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: $qXfer:auxv:read::{:x},{:x}:#00".format(OFFSET, LENGTH),
+ {"direction":"send", "regex":re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE|re.DOTALL), "capture":{1:"response_type", 2:"content_raw"} }
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure we end up with all auxv data in one packet.
+ # FIXME don't assume it all comes back in one packet.
+ self.assertEqual(context.get("response_type"), "l")
+
+ # Decode binary data.
+ content_raw = context.get("content_raw")
+ self.assertIsNotNone(content_raw)
+ return (word_size, self.decode_gdbremote_binary(content_raw))
+
+ def supports_auxv(self):
+ # When non-auxv platforms support llgs, skip the test on platforms
+ # that don't support auxv.
+ self.assertTrue(self.has_auxv_support())
+
+ #
+ # We skip the "supports_auxv" test on debugserver. The rest of the tests
+ # appropriately skip the auxv tests if the support flag is not present
+ # in the qSupported response, so the debugserver test bits are still there
+ # in case debugserver code one day does have auxv support and thus those
+ # tests don't get skipped.
+ #
+
+ @llgs_test
+ def test_supports_auxv_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.supports_auxv()
+
+ def auxv_data_is_correct_size(self):
+ (word_size, auxv_data) = self.get_raw_auxv_data()
+ self.assertIsNotNone(auxv_data)
+
+ # Ensure auxv data is a multiple of 2*word_size (there should be two unsigned long fields per auxv entry).
+ self.assertEqual(len(auxv_data) % (2*word_size), 0)
+ # print("auxv contains {} entries".format(len(auxv_data) / (2*word_size)))
+
+ @debugserver_test
+ def test_auxv_data_is_correct_size_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_data_is_correct_size()
+
+ @llgs_test
+ def test_auxv_data_is_correct_size_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_data_is_correct_size()
+
+ def auxv_keys_look_valid(self):
+ (word_size, auxv_data) = self.get_raw_auxv_data()
+ self.assertIsNotNone(auxv_data)
+
+ # Grab endian.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
+ self.assertIsNotNone(auxv_dict)
+
+ # Verify keys look reasonable.
+ for auxv_key in auxv_dict:
+ self.assertTrue(auxv_key >= 1)
+ self.assertTrue(auxv_key <= 1000)
+ # print("auxv dict: {}".format(auxv_dict))
+
+ @debugserver_test
+ def test_auxv_keys_look_valid_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_keys_look_valid()
+
+ @llgs_test
+ def test_auxv_keys_look_valid_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_keys_look_valid()
+
+ def auxv_chunked_reads_work(self):
+ # Verify that multiple smaller offset,length reads of auxv data
+ # return the same data as a single larger read.
+
+ # Grab the auxv data with a single large read here.
+ (word_size, auxv_data) = self.get_raw_auxv_data()
+ self.assertIsNotNone(auxv_data)
+
+ # Grab endian.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
+ self.assertIsNotNone(auxv_dict)
+
+ iterated_auxv_data = self.read_binary_data_in_chunks("qXfer:auxv:read::", 2*word_size)
+ self.assertIsNotNone(iterated_auxv_data)
+
+ auxv_dict_iterated = self.build_auxv_dict(endian, word_size, iterated_auxv_data)
+ self.assertIsNotNone(auxv_dict_iterated)
+
+ # Verify both types of data collection returned same content.
+ self.assertEqual(auxv_dict_iterated, auxv_dict)
+
+ @debugserver_test
+ def test_auxv_chunked_reads_work_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_chunked_reads_work()
+
+ @llgs_test
+ def test_auxv_chunked_reads_work_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.auxv_chunked_reads_work()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteExpeditedRegisters.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteExpeditedRegisters.py
new file mode 100644
index 0000000..6535ce4
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteExpeditedRegisters.py
@@ -0,0 +1,144 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteExpeditedRegisters(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def gather_expedited_registers(self):
+ # Setup the stub and set the gdb remote command stream.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
+ self.test_sequence.add_log_lines([
+ # Start up the inferior.
+ "read packet: $c#63",
+ # Immediately tell it to stop. We want to see what it reports.
+ "read packet: {}".format(chr(3)),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} },
+ ], True)
+
+ # Run the gdb remote command stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Pull out expedited registers.
+ key_vals_text = context.get("key_vals_text")
+ self.assertIsNotNone(key_vals_text)
+
+ expedited_registers = self.extract_registers_from_stop_notification(key_vals_text)
+ self.assertIsNotNone(expedited_registers)
+
+ return expedited_registers
+
+ def stop_notification_contains_generic_register(self, generic_register_name):
+ # Generate a stop reply, parse out expedited registers from stop notification.
+ expedited_registers = self.gather_expedited_registers()
+ self.assertIsNotNone(expedited_registers)
+ self.assertTrue(len(expedited_registers) > 0)
+
+ # Gather target register infos.
+ reg_infos = self.gather_register_infos()
+
+ # Find the generic register.
+ reg_info = self.find_generic_register_with_name(reg_infos, generic_register_name)
+ self.assertIsNotNone(reg_info)
+
+ # Ensure the expedited registers contained it.
+ self.assertTrue(reg_info["lldb_register_index"] in expedited_registers)
+ # print("{} reg_info:{}".format(generic_register_name, reg_info))
+
+ def stop_notification_contains_any_registers(self):
+ # Generate a stop reply, parse out expedited registers from stop notification.
+ expedited_registers = self.gather_expedited_registers()
+ # Verify we have at least one expedited register.
+ self.assertTrue(len(expedited_registers) > 0)
+
+ @debugserver_test
+ def test_stop_notification_contains_any_registers_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_any_registers()
+
+ @llgs_test
+ def test_stop_notification_contains_any_registers_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_any_registers()
+
+ def stop_notification_contains_no_duplicate_registers(self):
+ # Generate a stop reply, parse out expedited registers from stop notification.
+ expedited_registers = self.gather_expedited_registers()
+ # Verify no expedited register was specified multiple times.
+ for (reg_num, value) in list(expedited_registers.items()):
+ if (type(value) == list) and (len(value) > 0):
+ self.fail("expedited register number {} specified more than once ({} times)".format(reg_num, len(value)))
+
+ @debugserver_test
+ def test_stop_notification_contains_no_duplicate_registers_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_no_duplicate_registers()
+
+ @llgs_test
+ def test_stop_notification_contains_no_duplicate_registers_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_no_duplicate_registers()
+
+ def stop_notification_contains_pc_register(self):
+ self.stop_notification_contains_generic_register("pc")
+
+ @debugserver_test
+ def test_stop_notification_contains_pc_register_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_pc_register()
+
+ @llgs_test
+ def test_stop_notification_contains_pc_register_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_pc_register()
+
+ def stop_notification_contains_fp_register(self):
+ self.stop_notification_contains_generic_register("fp")
+
+ @debugserver_test
+ def test_stop_notification_contains_fp_register_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_fp_register()
+
+ @llgs_test
+ def test_stop_notification_contains_fp_register_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_fp_register()
+
+ def stop_notification_contains_sp_register(self):
+ self.stop_notification_contains_generic_register("sp")
+
+ @debugserver_test
+ def test_stop_notification_contains_sp_register_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_sp_register()
+
+ @llgs_test
+ def test_stop_notification_contains_sp_register_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_notification_contains_sp_register()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteKill.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteKill.py
new file mode 100644
index 0000000..b253254
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteKill.py
@@ -0,0 +1,53 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import lldbgdbserverutils
+
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteKill(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def attach_commandline_kill_after_initial_stop(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines([
+ "read packet: $k#6b",
+ {"direction":"send", "regex":r"^\$X[0-9a-fA-F]+([^#]*)#[0-9A-Fa-f]{2}" },
+ ], True)
+
+ if self.stub_sends_two_stop_notifications_on_kill:
+ # Add an expectation for a second X result for stubs that send two of these.
+ self.test_sequence.add_log_lines([
+ {"direction":"send", "regex":r"^\$X[0-9a-fA-F]+([^#]*)#[0-9A-Fa-f]{2}" },
+ ], True)
+
+ self.expect_gdbremote_sequence()
+
+ # Wait a moment for completed and now-detached inferior process to clear.
+ time.sleep(1)
+
+ if not lldb.remote_platform:
+ # Process should be dead now. Reap results.
+ poll_result = procs["inferior"].poll()
+ self.assertIsNotNone(poll_result)
+
+ # Where possible, verify at the system level that the process is not running.
+ self.assertFalse(lldbgdbserverutils.process_is_running(procs["inferior"].pid, False))
+
+ @debugserver_test
+ def test_attach_commandline_kill_after_initial_stop_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_kill_after_initial_stop()
+
+ @llgs_test
+ def test_attach_commandline_kill_after_initial_stop_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_kill_after_initial_stop()
+
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py
new file mode 100644
index 0000000..a11167b
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py
@@ -0,0 +1,179 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import lldbgdbserverutils
+import sys
+
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteProcessInfo(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def qProcessInfo_returns_running_process(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the process id looks reasonable.
+ pid_text = process_info.get("pid")
+ self.assertIsNotNone(pid_text)
+ pid = int(pid_text, base=16)
+ self.assertNotEqual(0, pid)
+
+ # If possible, verify that the process is running.
+ self.assertTrue(lldbgdbserverutils.process_is_running(pid, True))
+
+ @debugserver_test
+ def test_qProcessInfo_returns_running_process_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qProcessInfo_returns_running_process()
+
+ @llgs_test
+ def test_qProcessInfo_returns_running_process_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qProcessInfo_returns_running_process()
+
+ def attach_commandline_qProcessInfo_reports_correct_pid(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.assertIsNotNone(procs)
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the process id matches what we expected.
+ pid_text = process_info.get('pid', None)
+ self.assertIsNotNone(pid_text)
+ reported_pid = int(pid_text, base=16)
+ self.assertEqual(reported_pid, procs["inferior"].pid)
+
+ @debugserver_test
+ def test_attach_commandline_qProcessInfo_reports_correct_pid_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_qProcessInfo_reports_correct_pid()
+
+ @llgs_test
+ def test_attach_commandline_qProcessInfo_reports_correct_pid_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_qProcessInfo_reports_correct_pid()
+
+ def qProcessInfo_reports_valid_endian(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the process id looks reasonable.
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+ self.assertTrue(endian in ["little", "big", "pdp"])
+
+ @debugserver_test
+ def test_qProcessInfo_reports_valid_endian_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qProcessInfo_reports_valid_endian()
+
+ @llgs_test
+ def test_qProcessInfo_reports_valid_endian_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qProcessInfo_reports_valid_endian()
+
+ def qProcessInfo_contains_keys(self, expected_key_set):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the expected keys are present and non-None within the process info.
+ missing_key_set = set()
+ for expected_key in expected_key_set:
+ if expected_key not in process_info:
+ missing_key_set.add(expected_key)
+
+ self.assertEqual(missing_key_set, set(), "the listed keys are missing in the qProcessInfo result")
+
+ def qProcessInfo_does_not_contain_keys(self, absent_key_set):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_process_info_collection_packets()
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info response
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+
+ # Ensure the unexpected keys are not present
+ unexpected_key_set = set()
+ for unexpected_key in absent_key_set:
+ if unexpected_key in process_info:
+ unexpected_key_set.add(unexpected_key)
+
+ self.assertEqual(unexpected_key_set, set(), "the listed keys were present but unexpected in qProcessInfo result")
+
+ @skipUnlessDarwin
+ @debugserver_test
+ def test_qProcessInfo_contains_cputype_cpusubtype_debugserver_darwin(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qProcessInfo_contains_keys(set(['cputype', 'cpusubtype']))
+
+ @skipUnlessPlatform(["linux"])
+ @llgs_test
+ def test_qProcessInfo_contains_triple_llgs_linux(self):
+ self.init_llgs_test()
+ self.build()
+ self.qProcessInfo_contains_keys(set(['triple']))
+
+ @skipUnlessDarwin
+ @debugserver_test
+ def test_qProcessInfo_does_not_contain_triple_debugserver_darwin(self):
+ self.init_debugserver_test()
+ self.build()
+ # We don't expect to see triple on darwin. If we do, we'll prefer triple
+ # to cputype/cpusubtype and skip some darwin-based ProcessGDBRemote ArchSpec setup
+ # for the remote Host and Process.
+ self.qProcessInfo_does_not_contain_keys(set(['triple']))
+
+ @skipUnlessPlatform(["linux"])
+ @llgs_test
+ def test_qProcessInfo_does_not_contain_cputype_cpusubtype_llgs_linux(self):
+ self.init_llgs_test()
+ self.build()
+ self.qProcessInfo_does_not_contain_keys(set(['cputype', 'cpusubtype']))
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteRegisterState.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteRegisterState.py
new file mode 100644
index 0000000..a36b4ae
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteRegisterState.py
@@ -0,0 +1,126 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteRegisterState(gdbremote_testcase.GdbRemoteTestCaseBase):
+ """Test QSaveRegisterState/QRestoreRegisterState support."""
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def grp_register_save_restore_works(self, with_suffix):
+ # Start up the process, use thread suffix, grab main thread id.
+ inferior_args = ["message:main entered", "sleep:5"]
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+ self.add_process_info_collection_packets()
+ self.add_register_info_collection_packets()
+ if with_suffix:
+ self.add_thread_suffix_request_packets()
+ self.add_threadinfo_collection_packets()
+ self.test_sequence.add_log_lines([
+ # Start the inferior...
+ "read packet: $c#63",
+ # ... match output....
+ { "type":"output_match", "regex":r"^message:main entered\r\n$" },
+ ], True)
+ # ... then interrupt.
+ self.add_interrupt_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Gather register info.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ # Pull out the register infos that we think we can bit flip successfully.
+ gpr_reg_infos = [reg_info for reg_info in reg_infos if self.is_bit_flippable_register(reg_info)]
+ self.assertTrue(len(gpr_reg_infos) > 0)
+
+ # Gather thread info.
+ if with_suffix:
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+ thread_id = threads[0]
+ self.assertIsNotNone(thread_id)
+ # print("Running on thread: 0x{:x}".format(thread_id))
+ else:
+ thread_id = None
+
+ # Save register state.
+ self.reset_test_sequence()
+ self.add_QSaveRegisterState_packets(thread_id)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ (success, state_id) = self.parse_QSaveRegisterState_response(context)
+ self.assertTrue(success)
+ self.assertIsNotNone(state_id)
+ # print("saved register state id: {}".format(state_id))
+
+ # Remember initial register values.
+ initial_reg_values = self.read_register_values(gpr_reg_infos, endian, thread_id=thread_id)
+ # print("initial_reg_values: {}".format(initial_reg_values))
+
+ # Flip gpr register values.
+ (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(gpr_reg_infos, endian, thread_id=thread_id)
+ # print("successful writes: {}, failed writes: {}".format(successful_writes, failed_writes))
+ self.assertTrue(successful_writes > 0)
+
+ flipped_reg_values = self.read_register_values(gpr_reg_infos, endian, thread_id=thread_id)
+ # print("flipped_reg_values: {}".format(flipped_reg_values))
+
+ # Restore register values.
+ self.reset_test_sequence()
+ self.add_QRestoreRegisterState_packets(state_id, thread_id)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify registers match initial register values.
+ final_reg_values = self.read_register_values(gpr_reg_infos, endian, thread_id=thread_id)
+ # print("final_reg_values: {}".format(final_reg_values))
+ self.assertIsNotNone(final_reg_values)
+ self.assertEqual(final_reg_values, initial_reg_values)
+
+ @debugserver_test
+ def test_grp_register_save_restore_works_with_suffix_debugserver(self):
+ USE_THREAD_SUFFIX = True
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
+
+ @llgs_test
+ def test_grp_register_save_restore_works_with_suffix_llgs(self):
+ USE_THREAD_SUFFIX = True
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
+
+ @debugserver_test
+ def test_grp_register_save_restore_works_no_suffix_debugserver(self):
+ USE_THREAD_SUFFIX = False
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
+
+ @llgs_test
+ def test_grp_register_save_restore_works_no_suffix_llgs(self):
+ USE_THREAD_SUFFIX = False
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py
new file mode 100644
index 0000000..3b00824
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py
@@ -0,0 +1,25 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteSingleStep(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @debugserver_test
+ def test_single_step_only_steps_one_instruction_with_s_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="s")
+
+ @llgs_test
+ @expectedFailureAndroid(bugnumber="llvm.com/pr24739", archs=["arm", "aarch64"])
+ def test_single_step_only_steps_one_instruction_with_s_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="s")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
new file mode 100644
index 0000000..a793879
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py
@@ -0,0 +1,164 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteThreadsInStopReply(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ ENABLE_THREADS_IN_STOP_REPLY_ENTRIES = [
+ "read packet: $QListThreadsInStopReply#21",
+ "send packet: $OK#00",
+ ]
+
+ def gather_stop_reply_threads(self, post_startup_log_lines, thread_count):
+ # Set up the inferior args.
+ inferior_args=[]
+ for i in range(thread_count - 1):
+ inferior_args.append("thread:new")
+ inferior_args.append("sleep:10")
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+ # Assumes test_sequence has anything added needed to setup the initial state.
+ # (Like optionally enabling QThreadsInStopReply.)
+ if post_startup_log_lines:
+ self.test_sequence.add_log_lines(post_startup_log_lines, True)
+ self.test_sequence.add_log_lines([
+ "read packet: $c#63"
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Give threads time to start up, then break.
+ time.sleep(1)
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: {}".format(chr(3)),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Wait until all threads have started.
+ threads = self.wait_for_thread_count(thread_count, timeout_seconds=3)
+ self.assertIsNotNone(threads)
+ self.assertEqual(len(threads), thread_count)
+
+ # Run, then stop the process, grab the stop reply content.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: $c#63",
+ "read packet: {}".format(chr(3)),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Parse the stop reply contents.
+ key_vals_text = context.get("key_vals_text")
+ self.assertIsNotNone(key_vals_text)
+ kv_dict = self.parse_key_val_dict(key_vals_text)
+ self.assertIsNotNone(kv_dict)
+
+ # Pull out threads from stop response.
+ stop_reply_threads_text = kv_dict.get("threads")
+ if stop_reply_threads_text:
+ return [int(thread_id, 16) for thread_id in stop_reply_threads_text.split(",")]
+ else:
+ return []
+
+ def QListThreadsInStopReply_supported(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines(self.ENABLE_THREADS_IN_STOP_REPLY_ENTRIES, True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ @debugserver_test
+ def test_QListThreadsInStopReply_supported_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.QListThreadsInStopReply_supported()
+
+ @llgs_test
+ def test_QListThreadsInStopReply_supported_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.QListThreadsInStopReply_supported()
+
+ def stop_reply_reports_multiple_threads(self, thread_count):
+ # Gather threads from stop notification when QThreadsInStopReply is enabled.
+ stop_reply_threads = self.gather_stop_reply_threads(self.ENABLE_THREADS_IN_STOP_REPLY_ENTRIES, thread_count)
+ self.assertEqual(len(stop_reply_threads), thread_count)
+
+ @debugserver_test
+ def test_stop_reply_reports_multiple_threads_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_reply_reports_multiple_threads(5)
+
+ @llgs_test
+ def test_stop_reply_reports_multiple_threads_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_reply_reports_multiple_threads(5)
+
+ def no_QListThreadsInStopReply_supplies_no_threads(self, thread_count):
+ # Gather threads from stop notification when QThreadsInStopReply is not enabled.
+ stop_reply_threads = self.gather_stop_reply_threads(None, thread_count)
+ self.assertEqual(len(stop_reply_threads), 0)
+
+ @debugserver_test
+ def test_no_QListThreadsInStopReply_supplies_no_threads_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.no_QListThreadsInStopReply_supplies_no_threads(5)
+
+ @llgs_test
+ def test_no_QListThreadsInStopReply_supplies_no_threads_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.no_QListThreadsInStopReply_supplies_no_threads(5)
+
+ def stop_reply_reports_correct_threads(self, thread_count):
+ # Gather threads from stop notification when QThreadsInStopReply is enabled.
+ stop_reply_threads = self.gather_stop_reply_threads(self.ENABLE_THREADS_IN_STOP_REPLY_ENTRIES, thread_count)
+ self.assertEqual(len(stop_reply_threads), thread_count)
+
+ # Gather threads from q{f,s}ThreadInfo.
+ self.reset_test_sequence()
+ self.add_threadinfo_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+ self.assertEqual(len(threads), thread_count)
+
+ # Ensure each thread in q{f,s}ThreadInfo appears in stop reply threads
+ for tid in threads:
+ self.assertTrue(tid in stop_reply_threads)
+
+ @debugserver_test
+ def test_stop_reply_reports_correct_threads_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_reply_reports_correct_threads(5)
+
+ @llgs_test
+ def test_stop_reply_reports_correct_threads_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.stop_reply_reports_correct_threads(5)
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_qThreadStopInfo.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_qThreadStopInfo.py
new file mode 100644
index 0000000..cce4844
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_qThreadStopInfo.py
@@ -0,0 +1,150 @@
+from __future__ import print_function
+
+
+
+import sys
+
+import unittest2
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemote_qThreadStopInfo(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ THREAD_COUNT = 5
+
+ def gather_stop_replies_via_qThreadStopInfo(self, thread_count):
+ # Set up the inferior args.
+ inferior_args=[]
+ for i in range(thread_count - 1):
+ inferior_args.append("thread:new")
+ inferior_args.append("sleep:10")
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+ # Assumes test_sequence has anything added needed to setup the initial state.
+ # (Like optionally enabling QThreadsInStopReply.)
+ self.test_sequence.add_log_lines([
+ "read packet: $c#63"
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Give threads time to start up, then break.
+ time.sleep(1)
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: {}".format(chr(3)),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Wait until all threads have started.
+ threads = self.wait_for_thread_count(thread_count, timeout_seconds=3)
+ self.assertIsNotNone(threads)
+ self.assertEqual(len(threads), thread_count)
+
+ # Grab stop reply for each thread via qThreadStopInfo{tid:hex}.
+ stop_replies = {}
+ thread_dicts = {}
+ for thread in threads:
+ # Run the qThreadStopInfo command.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: $qThreadStopInfo{:x}#00".format(thread),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result", 2:"key_vals_text"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Parse stop reply contents.
+ key_vals_text = context.get("key_vals_text")
+ self.assertIsNotNone(key_vals_text)
+ kv_dict = self.parse_key_val_dict(key_vals_text)
+ self.assertIsNotNone(kv_dict)
+
+ # Verify there is a thread and that it matches the expected thread id.
+ kv_thread = kv_dict.get("thread")
+ self.assertIsNotNone(kv_thread)
+ kv_thread_id = int(kv_thread, 16)
+ self.assertEqual(kv_thread_id, thread)
+
+ # Grab the stop id reported.
+ stop_result_text = context.get("stop_result")
+ self.assertIsNotNone(stop_result_text)
+ stop_replies[kv_thread_id] = int(stop_result_text, 16)
+
+ # Hang on to the key-val dictionary for the thread.
+ thread_dicts[kv_thread_id] = kv_dict
+
+ return (stop_replies, thread_dicts)
+
+ def qThreadStopInfo_works_for_multiple_threads(self, thread_count):
+ (stop_replies, _) = self.gather_stop_replies_via_qThreadStopInfo(thread_count)
+ self.assertEqual(len(stop_replies), thread_count)
+
+ @debugserver_test
+ def test_qThreadStopInfo_works_for_multiple_threads_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_works_for_multiple_threads(self.THREAD_COUNT)
+
+ @llgs_test
+ def test_qThreadStopInfo_works_for_multiple_threads_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_works_for_multiple_threads(self.THREAD_COUNT)
+
+ def qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt(self, thread_count):
+ (stop_replies, _) = self.gather_stop_replies_via_qThreadStopInfo(thread_count)
+ self.assertIsNotNone(stop_replies)
+
+ no_stop_reason_count = sum(1 for stop_reason in list(stop_replies.values()) if stop_reason == 0)
+ with_stop_reason_count = sum(1 for stop_reason in list(stop_replies.values()) if stop_reason != 0)
+
+ # All but one thread should report no stop reason.
+ self.assertEqual(no_stop_reason_count, thread_count - 1)
+
+ # Only one thread should should indicate a stop reason.
+ self.assertEqual(with_stop_reason_count, 1)
+
+ @debugserver_test
+ def test_qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt(self.THREAD_COUNT)
+
+ @llgs_test
+ def test_qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt(self.THREAD_COUNT)
+
+ def qThreadStopInfo_has_valid_thread_names(self, thread_count, expected_thread_name):
+ (_, thread_dicts) = self.gather_stop_replies_via_qThreadStopInfo(thread_count)
+ self.assertIsNotNone(thread_dicts)
+
+ for thread_dict in list(thread_dicts.values()):
+ name = thread_dict.get("name")
+ self.assertIsNotNone(name)
+ self.assertEqual(name, expected_thread_name)
+
+ @unittest2.skip("MacOSX doesn't have a default thread name")
+ @debugserver_test
+ def test_qThreadStopInfo_has_valid_thread_names_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_has_valid_thread_names(self.THREAD_COUNT, "a.out")
+
+ @skipUnlessPlatform(["linux"]) # test requires OS with set, equal thread names by default.
+ @llgs_test
+ def test_qThreadStopInfo_has_valid_thread_names_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadStopInfo_has_valid_thread_names(self.THREAD_COUNT, "a.out")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py
new file mode 100644
index 0000000..579e99d
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py
@@ -0,0 +1,116 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemote_vCont(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def vCont_supports_mode(self, mode, inferior_args=None):
+ # Setup the stub and set the gdb remote command stream.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+ self.add_vCont_query_packets()
+
+ # Run the gdb remote command stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Pull out supported modes.
+ supported_vCont_modes = self.parse_vCont_query_response(context)
+ self.assertIsNotNone(supported_vCont_modes)
+
+ # Verify we support the given mode.
+ self.assertTrue(mode in supported_vCont_modes)
+
+ def vCont_supports_c(self):
+ self.vCont_supports_mode("c")
+
+ def vCont_supports_C(self):
+ self.vCont_supports_mode("C")
+
+ def vCont_supports_s(self):
+ self.vCont_supports_mode("s")
+
+ def vCont_supports_S(self):
+ self.vCont_supports_mode("S")
+
+ @debugserver_test
+ def test_vCont_supports_c_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.vCont_supports_c()
+
+ @llgs_test
+ def test_vCont_supports_c_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.vCont_supports_c()
+
+ @debugserver_test
+ def test_vCont_supports_C_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.vCont_supports_C()
+
+ @llgs_test
+ def test_vCont_supports_C_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.vCont_supports_C()
+
+ @debugserver_test
+ def test_vCont_supports_s_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.vCont_supports_s()
+
+ @llgs_test
+ def test_vCont_supports_s_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.vCont_supports_s()
+
+ @debugserver_test
+ def test_vCont_supports_S_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.vCont_supports_S()
+
+ @llgs_test
+ def test_vCont_supports_S_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.vCont_supports_S()
+
+ @debugserver_test
+ def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="vCont;s")
+
+ @llgs_test
+ @expectedFailureAndroid(bugnumber="llvm.com/pr24739", archs=["arm", "aarch64"])
+ def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="vCont;s")
+
+ @debugserver_test
+ def test_single_step_only_steps_one_instruction_with_vCont_s_thread_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}")
+
+ @llgs_test
+ @expectedFailureAndroid(bugnumber="llvm.com/pr24739", archs=["arm", "aarch64"])
+ def test_single_step_only_steps_one_instruction_with_vCont_s_thread_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
new file mode 100644
index 0000000..aec040c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
@@ -0,0 +1,1473 @@
+"""
+Test case for testing the gdbremote protocol.
+
+Tests run against debugserver and lldb-server (llgs).
+lldb-server tests run where the lldb-server exe is
+available.
+
+This class will be broken into smaller test case classes by
+gdb remote packet functional areas. For now it contains
+the initial set of tests implemented.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import gdbremote_testcase
+import lldbgdbserverutils
+import platform
+import signal
+from lldbsuite.test.lldbtest import *
+
+class LldbGdbServerTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @debugserver_test
+ def test_exe_starts_debugserver(self):
+ self.init_debugserver_test()
+ server = self.connect_to_debug_monitor()
+
+ @llgs_test
+ def test_exe_starts_llgs(self):
+ self.init_llgs_test()
+ server = self.connect_to_debug_monitor()
+
+ def start_no_ack_mode(self):
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_start_no_ack_mode_debugserver(self):
+ self.init_debugserver_test()
+ self.start_no_ack_mode()
+
+ @llgs_test
+ def test_start_no_ack_mode_llgs(self):
+ self.init_llgs_test()
+ self.start_no_ack_mode()
+
+ def thread_suffix_supported(self):
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.test_sequence.add_log_lines(
+ ["lldb-server < 26> read packet: $QThreadSuffixSupported#e4",
+ "lldb-server < 6> send packet: $OK#9a"],
+ True)
+
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_thread_suffix_supported_debugserver(self):
+ self.init_debugserver_test()
+ self.thread_suffix_supported()
+
+ @llgs_test
+ def test_thread_suffix_supported_llgs(self):
+ self.init_llgs_test()
+ self.thread_suffix_supported()
+
+ def list_threads_in_stop_reply_supported(self):
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.test_sequence.add_log_lines(
+ ["lldb-server < 27> read packet: $QListThreadsInStopReply#21",
+ "lldb-server < 6> send packet: $OK#9a"],
+ True)
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_list_threads_in_stop_reply_supported_debugserver(self):
+ self.init_debugserver_test()
+ self.list_threads_in_stop_reply_supported()
+
+ @llgs_test
+ def test_list_threads_in_stop_reply_supported_llgs(self):
+ self.init_llgs_test()
+ self.list_threads_in_stop_reply_supported()
+
+ def install_and_create_launch_args(self):
+ exe_path = os.path.abspath('a.out')
+ if not lldb.remote_platform:
+ return [exe_path]
+ remote_path = lldbutil.append_to_process_working_directory(os.path.basename(exe_path))
+ remote_file_spec = lldb.SBFileSpec(remote_path, False)
+ err = lldb.remote_platform.Install(lldb.SBFileSpec(exe_path, True), remote_file_spec)
+ if err.Fail():
+ raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (exe_path, remote_path, err))
+ return [remote_path]
+
+ def start_inferior(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.test_sequence.add_log_lines(
+ ["read packet: %s" % lldbgdbserverutils.build_gdbremote_A_packet(launch_args),
+ "send packet: $OK#9a"],
+ True)
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_start_inferior_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.start_inferior()
+
+ @llgs_test
+ def test_start_inferior_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.start_inferior()
+
+ def inferior_exit_0(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $vCont;c#a8",
+ "send packet: $W00#00"],
+ True)
+
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_inferior_exit_0_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.inferior_exit_0()
+
+ @llgs_test
+ def test_inferior_exit_0_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.inferior_exit_0()
+
+ def inferior_exit_42(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ RETVAL = 42
+
+ # build launch args
+ launch_args += ["retval:%d" % RETVAL]
+
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $vCont;c#a8",
+ "send packet: $W{0:02x}#00".format(RETVAL)],
+ True)
+
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_inferior_exit_42_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.inferior_exit_42()
+
+ @llgs_test
+ def test_inferior_exit_42_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.inferior_exit_42()
+
+ def c_packet_works(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $c#63",
+ "send packet: $W00#00"],
+ True)
+
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_c_packet_works_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.c_packet_works()
+
+ @llgs_test
+ def test_c_packet_works_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.c_packet_works()
+
+ def inferior_print_exit(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # build launch args
+ launch_args += ["hello, world"]
+
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $vCont;c#a8",
+ {"type":"output_match", "regex":r"^hello, world\r\n$" },
+ "send packet: $W00#00"],
+ True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ @debugserver_test
+ def test_inferior_print_exit_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.inferior_print_exit()
+
+ @llgs_test
+ def test_inferior_print_exit_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.inferior_print_exit()
+
+ def first_launch_stop_reply_thread_matches_first_qC(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # build launch args
+ launch_args += ["hello, world"]
+
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $qC#00",
+ { "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} },
+ "read packet: $?#00",
+ { "direction":"send", "regex":r"^\$T[0-9a-fA-F]{2}thread:([0-9a-fA-F]+)", "expect_captures":{1:"thread_id"} }],
+ True)
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_first_launch_stop_reply_thread_matches_first_qC_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.first_launch_stop_reply_thread_matches_first_qC()
+
+ @llgs_test
+ def test_first_launch_stop_reply_thread_matches_first_qC_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.first_launch_stop_reply_thread_matches_first_qC()
+
+ def attach_commandline_continue_app_exits(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines(
+ ["read packet: $vCont;c#a8",
+ "send packet: $W00#00"],
+ True)
+ self.expect_gdbremote_sequence()
+
+ # Wait a moment for completed and now-detached inferior process to clear.
+ time.sleep(1)
+
+ if not lldb.remote_platform:
+ # Process should be dead now. Reap results.
+ poll_result = procs["inferior"].poll()
+ self.assertIsNotNone(poll_result)
+
+ # Where possible, verify at the system level that the process is not running.
+ self.assertFalse(lldbgdbserverutils.process_is_running(procs["inferior"].pid, False))
+
+ @debugserver_test
+ def test_attach_commandline_continue_app_exits_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_continue_app_exits()
+
+ @llgs_test
+ def test_attach_commandline_continue_app_exits_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.attach_commandline_continue_app_exits()
+
+ def qRegisterInfo_returns_one_valid_result(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.test_sequence.add_log_lines(
+ ["read packet: $qRegisterInfo0#00",
+ { "direction":"send", "regex":r"^\$(.+);#[0-9A-Fa-f]{2}", "capture":{1:"reginfo_0"} }],
+ True)
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ reg_info_packet = context.get("reginfo_0")
+ self.assertIsNotNone(reg_info_packet)
+ self.assert_valid_reg_info(lldbgdbserverutils.parse_reg_info_response(reg_info_packet))
+
+ @debugserver_test
+ @expectedFailureDarwin("llvm.org/pr25486")
+ def test_qRegisterInfo_returns_one_valid_result_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qRegisterInfo_returns_one_valid_result()
+
+ @llgs_test
+ def test_qRegisterInfo_returns_one_valid_result_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qRegisterInfo_returns_one_valid_result()
+
+ def qRegisterInfo_returns_all_valid_results(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream.
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.add_register_info_collection_packets()
+
+ # Run the stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Validate that each register info returned validates.
+ for reg_info in self.parse_register_info_packets(context):
+ self.assert_valid_reg_info(reg_info)
+
+ @debugserver_test
+ @expectedFailureDarwin("llvm.org/pr25486")
+ def test_qRegisterInfo_returns_all_valid_results_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qRegisterInfo_returns_all_valid_results()
+
+ @llgs_test
+ def test_qRegisterInfo_returns_all_valid_results_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qRegisterInfo_returns_all_valid_results()
+
+ def qRegisterInfo_contains_required_generics(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all generic registers found.
+ generic_regs = { reg_info['generic']:1 for reg_info in reg_infos if 'generic' in reg_info }
+
+ # Ensure we have a program counter register.
+ self.assertTrue('pc' in generic_regs)
+
+ # Ensure we have a frame pointer register.
+ self.assertTrue('fp' in generic_regs)
+
+ # Ensure we have a stack pointer register.
+ self.assertTrue('sp' in generic_regs)
+
+ # Ensure we have a flags register.
+ self.assertTrue('flags' in generic_regs)
+
+ @debugserver_test
+ def test_qRegisterInfo_contains_required_generics_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qRegisterInfo_contains_required_generics()
+
+ @llgs_test
+ def test_qRegisterInfo_contains_required_generics_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qRegisterInfo_contains_required_generics()
+
+ def qRegisterInfo_contains_at_least_one_register_set(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all register sets found.
+ register_sets = { reg_info['set']:1 for reg_info in reg_infos if 'set' in reg_info }
+ self.assertTrue(len(register_sets) >= 1)
+
+ @debugserver_test
+ def test_qRegisterInfo_contains_at_least_one_register_set_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.qRegisterInfo_contains_at_least_one_register_set()
+
+ @llgs_test
+ def test_qRegisterInfo_contains_at_least_one_register_set_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qRegisterInfo_contains_at_least_one_register_set()
+
+ def targetHasAVX(self):
+ triple = self.dbg.GetSelectedPlatform().GetTriple()
+
+ # TODO other platforms, please implement this function
+ if not re.match(".*-.*-linux", triple):
+ return True
+
+ # Need to do something different for non-Linux/Android targets
+ if lldb.remote_platform:
+ self.runCmd('platform get-file "/proc/cpuinfo" "cpuinfo"')
+ cpuinfo_path = "cpuinfo"
+ self.addTearDownHook(lambda: os.unlink("cpuinfo"))
+ else:
+ cpuinfo_path = "/proc/cpuinfo"
+
+ f = open(cpuinfo_path, 'r')
+ cpuinfo = f.read()
+ f.close()
+ return " avx " in cpuinfo
+
+ def qRegisterInfo_contains_avx_registers(self):
+ launch_args = self.install_and_create_launch_args()
+
+ server = self.connect_to_debug_monitor()
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream
+ self.add_no_ack_remote_stream()
+ self.add_verified_launch_packets(launch_args)
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all generics found.
+ register_sets = { reg_info['set']:1 for reg_info in reg_infos if 'set' in reg_info }
+ self.assertEqual(self.targetHasAVX(), "Advanced Vector Extensions" in register_sets)
+
+ @llgs_test
+ def test_qRegisterInfo_contains_avx_registers_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.qRegisterInfo_contains_avx_registers()
+
+ def qThreadInfo_contains_thread(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_threadinfo_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather threadinfo entries.
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+
+ # We should have exactly one thread.
+ self.assertEqual(len(threads), 1)
+
+ @debugserver_test
+ def test_qThreadInfo_contains_thread_launch_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadInfo_contains_thread()
+
+ @llgs_test
+ def test_qThreadInfo_contains_thread_launch_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadInfo_contains_thread()
+
+ @debugserver_test
+ def test_qThreadInfo_contains_thread_attach_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.qThreadInfo_contains_thread()
+
+ @llgs_test
+ def test_qThreadInfo_contains_thread_attach_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.qThreadInfo_contains_thread()
+
+ def qThreadInfo_matches_qC(self):
+ procs = self.prep_debug_monitor_and_inferior()
+
+ self.add_threadinfo_collection_packets()
+ self.test_sequence.add_log_lines(
+ ["read packet: $qC#00",
+ { "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }
+ ], True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather threadinfo entries.
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+
+ # We should have exactly one thread from threadinfo.
+ self.assertEqual(len(threads), 1)
+
+ # We should have a valid thread_id from $QC.
+ QC_thread_id_hex = context.get("thread_id")
+ self.assertIsNotNone(QC_thread_id_hex)
+ QC_thread_id = int(QC_thread_id_hex, 16)
+
+ # Those two should be the same.
+ self.assertEqual(threads[0], QC_thread_id)
+
+ @debugserver_test
+ def test_qThreadInfo_matches_qC_launch_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadInfo_matches_qC()
+
+ @llgs_test
+ def test_qThreadInfo_matches_qC_launch_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qThreadInfo_matches_qC()
+
+ @debugserver_test
+ def test_qThreadInfo_matches_qC_attach_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.qThreadInfo_matches_qC()
+
+ @llgs_test
+ def test_qThreadInfo_matches_qC_attach_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.qThreadInfo_matches_qC()
+
+ def p_returns_correct_data_size_for_each_qRegisterInfo(self):
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.assertTrue(len(reg_infos) > 0)
+
+ # Read value for each register.
+ reg_index = 0
+ for reg_info in reg_infos:
+ # Skip registers that don't have a register set. For x86, these are
+ # the DRx registers, which have no LLDB-kind register number and thus
+ # cannot be read via normal NativeRegisterContext::ReadRegister(reg_info,...) calls.
+ if not "set" in reg_info:
+ continue
+
+ # Clear existing packet expectations.
+ self.reset_test_sequence()
+
+ # Run the register query
+ self.test_sequence.add_log_lines(
+ ["read packet: $p{0:x}#00".format(reg_index),
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} }],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the response length.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ self.assertEqual(len(p_response), 2 * int(reg_info["bitsize"]) / 8)
+
+ # Increment loop
+ reg_index += 1
+
+ @debugserver_test
+ def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.p_returns_correct_data_size_for_each_qRegisterInfo()
+
+ @llgs_test
+ def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.p_returns_correct_data_size_for_each_qRegisterInfo()
+
+ @debugserver_test
+ def test_p_returns_correct_data_size_for_each_qRegisterInfo_attach_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.p_returns_correct_data_size_for_each_qRegisterInfo()
+
+ @llgs_test
+ def test_p_returns_correct_data_size_for_each_qRegisterInfo_attach_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.p_returns_correct_data_size_for_each_qRegisterInfo()
+
+ def Hg_switches_to_3_threads(self):
+ # Startup the inferior with three threads (main + 2 new ones).
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["thread:new", "thread:new"])
+
+ # Let the inferior process have a few moments to start up the thread when launched. (The launch scenario has no time to run, so threads won't be there yet.)
+ self.run_process_then_stop(run_seconds=1)
+
+ # Wait at most x seconds for 3 threads to be present.
+ threads = self.wait_for_thread_count(3, timeout_seconds=5)
+ self.assertEqual(len(threads), 3)
+
+ # verify we can $H to each thead, and $qC matches the thread we set.
+ for thread in threads:
+ # Change to each thread, verify current thread id.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $Hg{0:x}#00".format(thread), # Set current thread.
+ "send packet: $OK#00",
+ "read packet: $qC#00",
+ { "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }],
+ True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the thread id.
+ self.assertIsNotNone(context.get("thread_id"))
+ self.assertEqual(int(context.get("thread_id"), 16), thread)
+
+ @debugserver_test
+ def test_Hg_switches_to_3_threads_launch_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.Hg_switches_to_3_threads()
+
+ @llgs_test
+ def test_Hg_switches_to_3_threads_launch_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.Hg_switches_to_3_threads()
+
+ @debugserver_test
+ def test_Hg_switches_to_3_threads_attach_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.Hg_switches_to_3_threads()
+
+ @llgs_test
+ def test_Hg_switches_to_3_threads_attach_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_attach()
+ self.Hg_switches_to_3_threads()
+
+ def Hc_then_Csignal_signals_correct_thread(self, segfault_signo):
+ # NOTE only run this one in inferior-launched mode: we can't grab inferior stdout when running attached,
+ # and the test requires getting stdout from the exe.
+
+ NUM_THREADS = 3
+
+ # Startup the inferior with three threads (main + NUM_THREADS-1 worker threads).
+ # inferior_args=["thread:print-ids"]
+ inferior_args=["thread:segfault"]
+ for i in range(NUM_THREADS - 1):
+ # if i > 0:
+ # Give time between thread creation/segfaulting for the handler to work.
+ # inferior_args.append("sleep:1")
+ inferior_args.append("thread:new")
+ inferior_args.append("sleep:10")
+
+ # Launch/attach. (In our case, this should only ever be launched since we need inferior stdout/stderr).
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+ self.test_sequence.add_log_lines(["read packet: $c#63"], True)
+ context = self.expect_gdbremote_sequence()
+
+ # Let the inferior process have a few moments to start up the thread when launched.
+ # context = self.run_process_then_stop(run_seconds=1)
+
+ # Wait at most x seconds for all threads to be present.
+ # threads = self.wait_for_thread_count(NUM_THREADS, timeout_seconds=5)
+ # self.assertEquals(len(threads), NUM_THREADS)
+
+ signaled_tids = {}
+ print_thread_ids = {}
+
+ # Switch to each thread, deliver a signal, and verify signal delivery
+ for i in range(NUM_THREADS - 1):
+ # Run until SIGSEGV comes in.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [{"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"signo", 2:"thread_id"} }
+ ], True)
+
+ context = self.expect_gdbremote_sequence(timeout_seconds=10)
+ self.assertIsNotNone(context)
+ signo = context.get("signo")
+ self.assertEqual(int(signo, 16), segfault_signo)
+
+ # Ensure we haven't seen this tid yet.
+ thread_id = int(context.get("thread_id"), 16)
+ self.assertFalse(thread_id in signaled_tids)
+ signaled_tids[thread_id] = 1
+
+ # Send SIGUSR1 to the thread that signaled the SIGSEGV.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Set the continue thread.
+ "read packet: $Hc{0:x}#00".format(thread_id), # Set current thread.
+ "send packet: $OK#00",
+
+ # Continue sending the signal number to the continue thread.
+ # The commented out packet is a way to do this same operation without using
+ # a $Hc (but this test is testing $Hc, so we'll stick with the former).
+ "read packet: $C{0:x}#00".format(lldbutil.get_signal_number('SIGUSR1')),
+ # "read packet: $vCont;C{0:x}:{1:x};c#00".format(lldbutil.get_signal_number('SIGUSR1'), thread_id),
+
+ # FIXME: Linux does not report the thread stop on the delivered signal (SIGUSR1 here). MacOSX debugserver does.
+ # But MacOSX debugserver isn't guaranteeing the thread the signal handler runs on, so currently its an XFAIL.
+ # Need to rectify behavior here. The linux behavior is more intuitive to me since we're essentially swapping out
+ # an about-to-be-delivered signal (for which we already sent a stop packet) to a different signal.
+ # {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+ # "read packet: $c#63",
+ { "type":"output_match", "regex":r"^received SIGUSR1 on thread id: ([0-9a-fA-F]+)\r\nthread ([0-9a-fA-F]+): past SIGSEGV\r\n", "capture":{ 1:"print_thread_id", 2:"post_handle_thread_id" } },
+ ],
+ True)
+
+ # Run the sequence.
+ context = self.expect_gdbremote_sequence(timeout_seconds=10)
+ self.assertIsNotNone(context)
+
+ # Ensure the stop signal is the signal we delivered.
+ # stop_signo = context.get("stop_signo")
+ # self.assertIsNotNone(stop_signo)
+ # self.assertEquals(int(stop_signo,16), lldbutil.get_signal_number('SIGUSR1'))
+
+ # Ensure the stop thread is the thread to which we delivered the signal.
+ # stop_thread_id = context.get("stop_thread_id")
+ # self.assertIsNotNone(stop_thread_id)
+ # self.assertEquals(int(stop_thread_id,16), thread_id)
+
+ # Ensure we haven't seen this thread id yet. The inferior's self-obtained thread ids are not guaranteed to match the stub tids (at least on MacOSX).
+ print_thread_id = context.get("print_thread_id")
+ self.assertIsNotNone(print_thread_id)
+ print_thread_id = int(print_thread_id, 16)
+ self.assertFalse(print_thread_id in print_thread_ids)
+
+ # Now remember this print (i.e. inferior-reflected) thread id and ensure we don't hit it again.
+ print_thread_ids[print_thread_id] = 1
+
+ # Ensure post signal-handle thread id matches the thread that initially raised the SIGSEGV.
+ post_handle_thread_id = context.get("post_handle_thread_id")
+ self.assertIsNotNone(post_handle_thread_id)
+ post_handle_thread_id = int(post_handle_thread_id, 16)
+ self.assertEqual(post_handle_thread_id, print_thread_id)
+
+ @unittest2.expectedFailure()
+ @debugserver_test
+ def test_Hc_then_Csignal_signals_correct_thread_launch_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ # Darwin debugserver translates some signals like SIGSEGV into some gdb expectations about fixed signal numbers.
+ self.Hc_then_Csignal_signals_correct_thread(self.TARGET_EXC_BAD_ACCESS)
+
+ @llgs_test
+ def test_Hc_then_Csignal_signals_correct_thread_launch_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.Hc_then_Csignal_signals_correct_thread(lldbutil.get_signal_number('SIGSEGV'))
+
+ def m_packet_reads_memory(self):
+ # This is the memory we will write into the inferior and then ensure we can read back with $m.
+ MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-data-address-hex:g_message", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^data address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"message_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Grab contents from the inferior.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $m{0:x},{1:x}#00".format(message_address, len(MEMORY_CONTENTS)),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"read_contents"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ self.assertIsNotNone(context.get("read_contents"))
+ read_contents = context.get("read_contents").decode("hex")
+ self.assertEqual(read_contents, MEMORY_CONTENTS)
+
+ @debugserver_test
+ def test_m_packet_reads_memory_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.m_packet_reads_memory()
+
+ @llgs_test
+ def test_m_packet_reads_memory_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.m_packet_reads_memory()
+
+ def qMemoryRegionInfo_is_supported(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+
+ # Ask if it supports $qMemoryRegionInfo.
+ self.test_sequence.add_log_lines(
+ ["read packet: $qMemoryRegionInfo#00",
+ "send packet: $OK#00"
+ ], True)
+ self.expect_gdbremote_sequence()
+
+ @debugserver_test
+ def test_qMemoryRegionInfo_is_supported_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_is_supported()
+
+ @llgs_test
+ def test_qMemoryRegionInfo_is_supported_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_is_supported()
+
+ def qMemoryRegionInfo_reports_code_address_as_executable(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"code_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the code address.
+ self.assertIsNotNone(context.get("code_address"))
+ code_address = int(context.get("code_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(code_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertFalse("error" in mem_region_dict)
+
+ # Ensure code address is readable and executable.
+ self.assertTrue("permissions" in mem_region_dict)
+ self.assertTrue("r" in mem_region_dict["permissions"])
+ self.assertTrue("x" in mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(code_address, mem_region_dict)
+
+ @debugserver_test
+ def test_qMemoryRegionInfo_reports_code_address_as_executable_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_code_address_as_executable()
+
+ @llgs_test
+ def test_qMemoryRegionInfo_reports_code_address_as_executable_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_code_address_as_executable()
+
+ def qMemoryRegionInfo_reports_stack_address_as_readable_writeable(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-stack-address-hex:", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^stack address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"stack_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("stack_address"))
+ stack_address = int(context.get("stack_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(stack_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertFalse("error" in mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertTrue("permissions" in mem_region_dict)
+ self.assertTrue("r" in mem_region_dict["permissions"])
+ self.assertTrue("w" in mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(stack_address, mem_region_dict)
+
+ @debugserver_test
+ def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_stack_address_as_readable_writeable()
+
+ @llgs_test
+ def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_stack_address_as_readable_writeable()
+
+ def qMemoryRegionInfo_reports_heap_address_as_readable_writeable(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-heap-address-hex:", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^heap address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"heap_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("heap_address"))
+ heap_address = int(context.get("heap_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(heap_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertFalse("error" in mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertTrue("permissions" in mem_region_dict)
+ self.assertTrue("r" in mem_region_dict["permissions"])
+ self.assertTrue("w" in mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(heap_address, mem_region_dict)
+
+
+ @debugserver_test
+ def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
+
+ @llgs_test
+ def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
+
+ def software_breakpoint_set_and_remove_work(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:1", "call-function:hello"])
+
+ # Run the process
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ [# Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"function_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info - we need endian of target to handle register value conversions.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+ (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
+ self.assertIsNotNone(pc_lldb_reg_index)
+ self.assertIsNotNone(pc_reg_info)
+
+ # Grab the function address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Set the breakpoint.
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ BREAKPOINT_KIND = 4
+ else:
+ BREAKPOINT_KIND = 1
+ self.reset_test_sequence()
+ self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the stop signal reported was the breakpoint signal number.
+ stop_signo = context.get("stop_signo")
+ self.assertIsNotNone(stop_signo)
+ self.assertEqual(int(stop_signo,16), lldbutil.get_signal_number('SIGTRAP'))
+
+ # Ensure we did not receive any output. If the breakpoint was not set, we would
+ # see output (from a launched process with captured stdio) printing a hello, world message.
+ # That would indicate the breakpoint didn't take.
+ self.assertEqual(len(context["O_content"]), 0)
+
+ # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
+ # This acts as a another validation on the register reading code.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Print the PC. This should match the breakpoint address.
+ "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
+ # Capture $p results.
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the PC is where we expect. Note response is in endianness of the inferior.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+
+ # Convert from target endian to int.
+ returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(endian, p_response)
+ self.assertEqual(returned_pc, function_address)
+
+ # Verify that a breakpoint remove and continue gets us the expected output.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Remove the breakpoint.
+ "read packet: $z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
+ # Verify the stub could unset it.
+ "send packet: $OK#00",
+ # Continue running.
+ "read packet: $c#63",
+ # We should now receive the output from the call.
+ { "type":"output_match", "regex":r"^hello, world\r\n$" },
+ # And wait for program completion.
+ {"direction":"send", "regex":r"^\$W00(.*)#[0-9a-fA-F]{2}$" },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ @debugserver_test
+ def test_software_breakpoint_set_and_remove_work_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.software_breakpoint_set_and_remove_work()
+
+ @llgs_test
+ def test_software_breakpoint_set_and_remove_work_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.software_breakpoint_set_and_remove_work()
+
+ def qSupported_returns_known_stub_features(self):
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_qSupported_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Retrieve the qSupported features.
+ supported_dict = self.parse_qSupported_response(context)
+ self.assertIsNotNone(supported_dict)
+ self.assertTrue(len(supported_dict) > 0)
+
+ @debugserver_test
+ def test_qSupported_returns_known_stub_features_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qSupported_returns_known_stub_features()
+
+ @llgs_test
+ def test_qSupported_returns_known_stub_features_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.qSupported_returns_known_stub_features()
+
+ def written_M_content_reads_back_correctly(self):
+ TEST_MESSAGE = "Hello, memory"
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["set-message:xxxxxxxxxxxxxX", "get-data-address-hex:g_message", "sleep:1", "print-message:"])
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^data address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"message_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Hex-encode the test message, adding null termination.
+ hex_encoded_message = TEST_MESSAGE.encode("hex")
+
+ # Write the message to the inferior.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $M{0:x},{1:x}:{2}#00".format(message_address, len(hex_encoded_message)/2, hex_encoded_message),
+ "send packet: $OK#00",
+ "read packet: $c#63",
+ { "type":"output_match", "regex":r"^message: (.+)\r\n$", "capture":{ 1:"printed_message"} },
+ "send packet: $W00#00",
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ printed_message = context.get("printed_message")
+ self.assertIsNotNone(printed_message)
+ self.assertEqual(printed_message, TEST_MESSAGE + "X")
+
+ @debugserver_test
+ def test_written_M_content_reads_back_correctly_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.written_M_content_reads_back_correctly()
+
+ @llgs_test
+ def test_written_M_content_reads_back_correctly_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.written_M_content_reads_back_correctly()
+
+ def P_writes_all_gpr_registers(self):
+ # Start inferior debug session, grab all register info.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Process register infos.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ # Process endian.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Pull out the register infos that we think we can bit flip successfully,.
+ gpr_reg_infos = [reg_info for reg_info in reg_infos if self.is_bit_flippable_register(reg_info)]
+ self.assertTrue(len(gpr_reg_infos) > 0)
+
+ # Write flipped bit pattern of existing value to each register.
+ (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(gpr_reg_infos, endian)
+ # print("successful writes: {}, failed writes: {}".format(successful_writes, failed_writes))
+ self.assertTrue(successful_writes > 0)
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ # Come back to this. I have the test rigged to verify that at least some of the bit-flip writes work.
+ @debugserver_test
+ def test_P_writes_all_gpr_registers_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.P_writes_all_gpr_registers()
+
+ @llgs_test
+ def test_P_writes_all_gpr_registers_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.P_writes_all_gpr_registers()
+
+ def P_and_p_thread_suffix_work(self):
+ # Startup the inferior with three threads.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["thread:new", "thread:new"])
+ self.add_thread_suffix_request_packets()
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ reg_index = self.select_modifiable_register(reg_infos)
+ self.assertIsNotNone(reg_index)
+ reg_byte_size = int(reg_infos[reg_index]["bitsize"]) / 8
+ self.assertTrue(reg_byte_size > 0)
+
+ # Run the process a bit so threads can start up, and collect register info.
+ context = self.run_process_then_stop(run_seconds=1)
+ self.assertIsNotNone(context)
+
+ # Wait for 3 threads to be present.
+ threads = self.wait_for_thread_count(3, timeout_seconds=5)
+ self.assertEqual(len(threads), 3)
+
+ expected_reg_values = []
+ register_increment = 1
+ next_value = None
+
+ # Set the same register in each of 3 threads to a different value.
+ # Verify each one has the unique value.
+ for thread in threads:
+ # If we don't have a next value yet, start it with the initial read value + 1
+ if not next_value:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Set the next value to use for writing as the increment plus current value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ next_value = lldbgdbserverutils.unpack_register_hex_unsigned(endian, p_response)
+
+ # Set new value using P and thread suffix.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $P{0:x}={1};thread:{2:x}#00".format(reg_index, lldbgdbserverutils.pack_register_hex(endian, next_value, byte_size=reg_byte_size), thread),
+ "send packet: $OK#00",
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Save the value we set.
+ expected_reg_values.append(next_value)
+
+ # Increment value for next thread to use (we want them all different so we can verify they wrote to each thread correctly next.)
+ next_value += register_increment
+
+ # Revisit each thread and verify they have the expected value set for the register we wrote.
+ thread_index = 0
+ for thread in threads:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Get the register value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ read_value = lldbgdbserverutils.unpack_register_hex_unsigned(endian, p_response)
+
+ # Make sure we read back what we wrote.
+ self.assertEqual(read_value, expected_reg_values[thread_index])
+ thread_index += 1
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ @debugserver_test
+ def test_P_and_p_thread_suffix_work_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.P_and_p_thread_suffix_work()
+
+ @llgs_test
+ def test_P_and_p_thread_suffix_work_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.P_and_p_thread_suffix_work()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubReverseConnect.py b/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubReverseConnect.py
new file mode 100644
index 0000000..9035237
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubReverseConnect.py
@@ -0,0 +1,87 @@
+from __future__ import print_function
+
+import gdbremote_testcase
+import lldbgdbserverutils
+import re
+import select
+import socket
+import time
+from lldbsuite.test.lldbtest import *
+
+class TestStubReverseConnect(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ _DEFAULT_TIMEOUT = 20
+
+ def setUp(self):
+ # Set up the test.
+ gdbremote_testcase.GdbRemoteTestCaseBase.setUp(self)
+
+ # Create a listener on a local port.
+ self.listener_socket = self.create_listener_socket()
+ self.assertIsNotNone(self.listener_socket)
+ self.listener_port = self.listener_socket.getsockname()[1]
+
+ def create_listener_socket(self, timeout_seconds=_DEFAULT_TIMEOUT):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.assertIsNotNone(sock)
+
+ sock.settimeout(timeout_seconds)
+ sock.bind(("127.0.0.1",0))
+ sock.listen(1)
+
+ def tear_down_listener():
+ try:
+ sock.shutdown(socket.SHUT_RDWR)
+ except:
+ # ignore
+ None
+
+ self.addTearDownHook(tear_down_listener)
+ return sock
+
+ def reverse_connect_works(self):
+ # Indicate stub startup should do a reverse connect.
+ appended_stub_args = ["--reverse-connect"]
+ if self.debug_monitor_extra_args:
+ self.debug_monitor_extra_args += appended_stub_args
+ else:
+ self.debug_monitor_extra_args = appended_stub_args
+
+ self.stub_hostname = "127.0.0.1"
+ self.port = self.listener_port
+
+ triple = self.dbg.GetSelectedPlatform().GetTriple()
+ if re.match(".*-.*-.*-android", triple):
+ self.forward_adb_port(self.port, self.port, "reverse", self.stub_device)
+
+ # Start the stub.
+ server = self.launch_debug_monitor(logfile=sys.stdout)
+ self.assertIsNotNone(server)
+ self.assertTrue(lldbgdbserverutils.process_is_running(server.pid, True))
+
+ # Listen for the stub's connection to us.
+ (stub_socket, address) = self.listener_socket.accept()
+ self.assertIsNotNone(stub_socket)
+ self.assertIsNotNone(address)
+ print("connected to stub {} on {}".format(address, stub_socket.getsockname()))
+
+ # Verify we can do the handshake. If that works, we'll call it good.
+ self.do_handshake(stub_socket, timeout_seconds=self._DEFAULT_TIMEOUT)
+
+ # Clean up.
+ stub_socket.shutdown(socket.SHUT_RDWR)
+
+ @debugserver_test
+ def test_reverse_connect_works_debugserver(self):
+ self.init_debugserver_test(use_named_pipe=False)
+ self.set_inferior_startup_launch()
+ self.reverse_connect_works()
+
+ @llgs_test
+ @skipIfRemote # reverse connect is not a supported use case for now
+ def test_reverse_connect_works_llgs(self):
+ self.init_llgs_test(use_named_pipe=False)
+ self.set_inferior_startup_launch()
+ self.reverse_connect_works()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubSetSID.py b/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubSetSID.py
new file mode 100644
index 0000000..2b2b0e8
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubSetSID.py
@@ -0,0 +1,82 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import lldbgdbserverutils
+import os
+import select
+import tempfile
+import time
+from lldbsuite.test.lldbtest import *
+
+class TestStubSetSIDTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def get_stub_sid(self, extra_stub_args=None):
+ # Launch debugserver
+ if extra_stub_args:
+ self.debug_monitor_extra_args += extra_stub_args
+
+ server = self.launch_debug_monitor()
+ self.assertIsNotNone(server)
+ self.assertTrue(lldbgdbserverutils.process_is_running(server.pid, True))
+
+ # Get the process id for the stub.
+ return os.getsid(server.pid)
+
+ def sid_is_same_without_setsid(self):
+ stub_sid = self.get_stub_sid()
+ self.assertEqual(stub_sid, os.getsid(0))
+
+ def sid_is_different_with_setsid(self):
+ stub_sid = self.get_stub_sid(["--setsid"])
+ self.assertNotEqual(stub_sid, os.getsid(0))
+
+ def sid_is_different_with_S(self):
+ stub_sid = self.get_stub_sid(["-S"])
+ self.assertNotEqual(stub_sid, os.getsid(0))
+
+ @debugserver_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ def test_sid_is_same_without_setsid_debugserver(self):
+ self.init_debugserver_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_same_without_setsid()
+
+ @llgs_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ @expectedFailureFreeBSD()
+ def test_sid_is_same_without_setsid_llgs(self):
+ self.init_llgs_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_same_without_setsid()
+
+ @debugserver_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ def test_sid_is_different_with_setsid_debugserver(self):
+ self.init_debugserver_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_different_with_setsid()
+
+ @llgs_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ def test_sid_is_different_with_setsid_llgs(self):
+ self.init_llgs_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_different_with_setsid()
+
+ @debugserver_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ def test_sid_is_different_with_S_debugserver(self):
+ self.init_debugserver_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_different_with_S()
+
+ @llgs_test
+ @skipIfRemote # --setsid not used on remote platform and currently it is also impossible to get the sid of lldb-platform running on a remote target
+ def test_sid_is_different_with_S_llgs(self):
+ self.init_llgs_test()
+ self.set_inferior_startup_launch()
+ self.sid_is_different_with_S()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
new file mode 100644
index 0000000..113e01e
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -0,0 +1,1299 @@
+"""
+Base class for gdb-remote test cases.
+"""
+
+from __future__ import print_function
+
+
+
+import errno
+import os
+import os.path
+import platform
+import random
+import re
+import select
+import signal
+import socket
+import subprocess
+import sys
+import tempfile
+import time
+from lldbsuite.test import configuration
+from lldbsuite.test.lldbtest import *
+from lldbgdbserverutils import *
+import logging
+
+class GdbRemoteTestCaseBase(TestBase):
+
+ _TIMEOUT_SECONDS = 5
+
+ _GDBREMOTE_KILL_PACKET = "$k#6b"
+
+ _LOGGING_LEVEL = logging.WARNING
+ # _LOGGING_LEVEL = logging.DEBUG
+
+ # Start the inferior separately, attach to the inferior on the stub command line.
+ _STARTUP_ATTACH = "attach"
+ # Start the inferior separately, start the stub without attaching, allow the test to attach to the inferior however it wants (e.g. $vAttach;pid).
+ _STARTUP_ATTACH_MANUALLY = "attach_manually"
+ # Start the stub, and launch the inferior with an $A packet via the initial packet stream.
+ _STARTUP_LAUNCH = "launch"
+
+ # GDB Signal numbers that are not target-specific used for common exceptions
+ TARGET_EXC_BAD_ACCESS = 0x91
+ TARGET_EXC_BAD_INSTRUCTION = 0x92
+ TARGET_EXC_ARITHMETIC = 0x93
+ TARGET_EXC_EMULATION = 0x94
+ TARGET_EXC_SOFTWARE = 0x95
+ TARGET_EXC_BREAKPOINT = 0x96
+
+ def setUp(self):
+ TestBase.setUp(self)
+ FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'
+ logging.basicConfig(format=FORMAT)
+ self.logger = logging.getLogger(__name__)
+ self.logger.setLevel(self._LOGGING_LEVEL)
+ self.test_sequence = GdbRemoteTestSequence(self.logger)
+ self.set_inferior_startup_launch()
+ self.port = self.get_next_port()
+ self.named_pipe_path = None
+ self.named_pipe = None
+ self.named_pipe_fd = None
+ self.stub_sends_two_stop_notifications_on_kill = False
+ if configuration.lldb_platform_url:
+ if configuration.lldb_platform_url.startswith('unix-'):
+ url_pattern = '(.+)://\[?(.+?)\]?/.*'
+ else:
+ url_pattern = '(.+)://(.+):\d+'
+ scheme, host = re.match(url_pattern, configuration.lldb_platform_url).groups()
+ if configuration.lldb_platform_name == 'remote-android' and host != 'localhost':
+ self.stub_device = host
+ self.stub_hostname = 'localhost'
+ else:
+ self.stub_device = None
+ self.stub_hostname = host
+ else:
+ self.stub_hostname = "localhost"
+
+ def get_next_port(self):
+ return 12000 + random.randint(0,3999)
+
+ def reset_test_sequence(self):
+ self.test_sequence = GdbRemoteTestSequence(self.logger)
+
+ def create_named_pipe(self):
+ # Create a temp dir and name for a pipe.
+ temp_dir = tempfile.mkdtemp()
+ named_pipe_path = os.path.join(temp_dir, "stub_port_number")
+
+ # Create the named pipe.
+ os.mkfifo(named_pipe_path)
+
+ # Open the read side of the pipe in non-blocking mode. This will return right away, ready or not.
+ named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
+
+ # Create the file for the named pipe. Note this will follow semantics of
+ # a non-blocking read side of a named pipe, which has different semantics
+ # than a named pipe opened for read in non-blocking mode.
+ named_pipe = os.fdopen(named_pipe_fd, "r")
+ self.assertIsNotNone(named_pipe)
+
+ def shutdown_named_pipe():
+ # Close the pipe.
+ try:
+ named_pipe.close()
+ except:
+ print("failed to close named pipe")
+ None
+
+ # Delete the pipe.
+ try:
+ os.remove(named_pipe_path)
+ except:
+ print("failed to delete named pipe: {}".format(named_pipe_path))
+ None
+
+ # Delete the temp directory.
+ try:
+ os.rmdir(temp_dir)
+ except:
+ print("failed to delete temp dir: {}, directory contents: '{}'".format(temp_dir, os.listdir(temp_dir)))
+ None
+
+ # Add the shutdown hook to clean up the named pipe.
+ self.addTearDownHook(shutdown_named_pipe)
+
+ # Clear the port so the stub selects a port number.
+ self.port = 0
+
+ return (named_pipe_path, named_pipe, named_pipe_fd)
+
+ def get_stub_port_from_named_socket(self, read_timeout_seconds=5):
+ # Wait for something to read with a max timeout.
+ (ready_readers, _, _) = select.select([self.named_pipe_fd], [], [], read_timeout_seconds)
+ self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
+ self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
+
+ # Read the port from the named pipe.
+ stub_port_raw = self.named_pipe.read()
+ self.assertIsNotNone(stub_port_raw)
+ self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
+
+ # Trim null byte, convert to int.
+ stub_port_raw = stub_port_raw[:-1]
+ stub_port = int(stub_port_raw)
+ self.assertTrue(stub_port > 0)
+
+ return stub_port
+
+ def run_shell_cmd(self, cmd):
+ platform = self.dbg.GetSelectedPlatform()
+ shell_cmd = lldb.SBPlatformShellCommand(cmd)
+ err = platform.Run(shell_cmd)
+ if err.Fail() or shell_cmd.GetStatus():
+ m = "remote_platform.RunShellCommand('%s') failed:\n" % cmd
+ m += ">>> return code: %d\n" % shell_cmd.GetStatus()
+ if err.Fail():
+ m += ">>> %s\n" % str(err).strip()
+ m += ">>> %s\n" % (shell_cmd.GetOutput() or
+ "Command generated no output.")
+ raise Exception(m)
+ return shell_cmd.GetOutput().strip()
+
+ def init_llgs_test(self, use_named_pipe=True):
+ if lldb.remote_platform:
+ # Remote platforms don't support named pipe based port negotiation
+ use_named_pipe = False
+
+ # Grab the ppid from /proc/[shell pid]/stat
+ shell_stat = self.run_shell_cmd("cat /proc/$$/stat")
+ # [pid] ([executable]) [state] [*ppid*]
+ pid = re.match(r"^\d+ \(.+\) . (\d+)", shell_stat).group(1)
+ ls_output = self.run_shell_cmd("ls -l /proc/%s/exe" % pid)
+ exe = ls_output.split()[-1]
+
+ # If the binary has been deleted, the link name has " (deleted)" appended.
+ # Remove if it's there.
+ self.debug_monitor_exe = re.sub(r' \(deleted\)$', '', exe)
+ else:
+ self.debug_monitor_exe = get_lldb_server_exe()
+ if not self.debug_monitor_exe:
+ self.skipTest("lldb-server exe not found")
+
+ self.debug_monitor_extra_args = ["gdbserver"]
+
+ if len(lldbtest_config.channels) > 0:
+ self.debug_monitor_extra_args.append("--log-file={}-server.log".format(self.log_basename))
+ self.debug_monitor_extra_args.append("--log-channels={}".format(":".join(lldbtest_config.channels)))
+
+ if use_named_pipe:
+ (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
+
+ def init_debugserver_test(self, use_named_pipe=True):
+ self.debug_monitor_exe = get_debugserver_exe()
+ if not self.debug_monitor_exe:
+ self.skipTest("debugserver exe not found")
+ self.debug_monitor_extra_args = ["--log-file={}-server.log".format(self.log_basename), "--log-flags=0x800000"]
+ if use_named_pipe:
+ (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
+ # The debugserver stub has a race on handling the 'k' command, so it sends an X09 right away, then sends the real X notification
+ # when the process truly dies.
+ self.stub_sends_two_stop_notifications_on_kill = True
+
+ def forward_adb_port(self, source, target, direction, device):
+ adb = [ 'adb' ] + ([ '-s', device ] if device else []) + [ direction ]
+ def remove_port_forward():
+ subprocess.call(adb + [ "--remove", "tcp:%d" % source])
+
+ subprocess.call(adb + [ "tcp:%d" % source, "tcp:%d" % target])
+ self.addTearDownHook(remove_port_forward)
+
+ def create_socket(self):
+ sock = socket.socket()
+ logger = self.logger
+
+ triple = self.dbg.GetSelectedPlatform().GetTriple()
+ if re.match(".*-.*-.*-android", triple):
+ self.forward_adb_port(self.port, self.port, "forward", self.stub_device)
+
+ connect_info = (self.stub_hostname, self.port)
+ sock.connect(connect_info)
+
+ def shutdown_socket():
+ if sock:
+ try:
+ # send the kill packet so lldb-server shuts down gracefully
+ sock.sendall(GdbRemoteTestCaseBase._GDBREMOTE_KILL_PACKET)
+ except:
+ logger.warning("failed to send kill packet to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+
+ try:
+ sock.close()
+ except:
+ logger.warning("failed to close socket to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+
+ self.addTearDownHook(shutdown_socket)
+
+ return sock
+
+ def set_inferior_startup_launch(self):
+ self._inferior_startup = self._STARTUP_LAUNCH
+
+ def set_inferior_startup_attach(self):
+ self._inferior_startup = self._STARTUP_ATTACH
+
+ def set_inferior_startup_attach_manually(self):
+ self._inferior_startup = self._STARTUP_ATTACH_MANUALLY
+
+ def get_debug_monitor_command_line_args(self, attach_pid=None):
+ if lldb.remote_platform:
+ commandline_args = self.debug_monitor_extra_args + ["*:{}".format(self.port)]
+ else:
+ commandline_args = self.debug_monitor_extra_args + ["localhost:{}".format(self.port)]
+
+ if attach_pid:
+ commandline_args += ["--attach=%d" % attach_pid]
+ if self.named_pipe_path:
+ commandline_args += ["--named-pipe", self.named_pipe_path]
+ return commandline_args
+
+ def run_platform_command(self, cmd):
+ platform = self.dbg.GetSelectedPlatform()
+ shell_command = lldb.SBPlatformShellCommand(cmd)
+ err = platform.Run(shell_command)
+ return (err, shell_command.GetOutput())
+
+ def launch_debug_monitor(self, attach_pid=None, logfile=None):
+ # Create the command line.
+ commandline_args = self.get_debug_monitor_command_line_args(attach_pid=attach_pid)
+
+ # Start the server.
+ server = self.spawnSubprocess(self.debug_monitor_exe, commandline_args, install_remote=False)
+ self.addTearDownHook(self.cleanupSubprocesses)
+ self.assertIsNotNone(server)
+
+ # If we're receiving the stub's listening port from the named pipe, do that here.
+ if self.named_pipe:
+ self.port = self.get_stub_port_from_named_socket()
+
+ return server
+
+ def connect_to_debug_monitor(self, attach_pid=None):
+ if self.named_pipe:
+ # Create the stub.
+ server = self.launch_debug_monitor(attach_pid=attach_pid)
+ self.assertIsNotNone(server)
+
+ def shutdown_debug_monitor():
+ try:
+ server.terminate()
+ except:
+ logger.warning("failed to terminate server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+ self.addTearDownHook(shutdown_debug_monitor)
+
+ # Schedule debug monitor to be shut down during teardown.
+ logger = self.logger
+
+ # Attach to the stub and return a socket opened to it.
+ self.sock = self.create_socket()
+ return server
+
+ # We're using a random port algorithm to try not to collide with other ports,
+ # and retry a max # times.
+ attempts = 0
+ MAX_ATTEMPTS = 20
+
+ while attempts < MAX_ATTEMPTS:
+ server = self.launch_debug_monitor(attach_pid=attach_pid)
+
+ # Schedule debug monitor to be shut down during teardown.
+ logger = self.logger
+ def shutdown_debug_monitor():
+ try:
+ server.terminate()
+ except:
+ logger.warning("failed to terminate server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+ self.addTearDownHook(shutdown_debug_monitor)
+
+ connect_attemps = 0
+ MAX_CONNECT_ATTEMPTS = 10
+
+ while connect_attemps < MAX_CONNECT_ATTEMPTS:
+ # Create a socket to talk to the server
+ try:
+ self.sock = self.create_socket()
+ return server
+ except socket.error as serr:
+ # We're only trying to handle connection refused.
+ if serr.errno != errno.ECONNREFUSED:
+ raise serr
+ time.sleep(0.5)
+ connect_attemps += 1
+
+ # We should close the server here to be safe.
+ server.terminate()
+
+ # Increment attempts.
+ print("connect to debug monitor on port %d failed, attempt #%d of %d" % (self.port, attempts + 1, MAX_ATTEMPTS))
+ attempts += 1
+
+ # And wait a random length of time before next attempt, to avoid collisions.
+ time.sleep(random.randint(1,5))
+
+ # Now grab a new port number.
+ self.port = self.get_next_port()
+
+ raise Exception("failed to create a socket to the launched debug monitor after %d tries" % attempts)
+
+ def launch_process_for_attach(self, inferior_args=None, sleep_seconds=3, exe_path=None):
+ # We're going to start a child process that the debug monitor stub can later attach to.
+ # This process needs to be started so that it just hangs around for a while. We'll
+ # have it sleep.
+ if not exe_path:
+ exe_path = os.path.abspath("a.out")
+
+ args = []
+ if inferior_args:
+ args.extend(inferior_args)
+ if sleep_seconds:
+ args.append("sleep:%d" % sleep_seconds)
+
+ inferior = self.spawnSubprocess(exe_path, args)
+ def shutdown_process_for_attach():
+ try:
+ inferior.terminate()
+ except:
+ logger.warning("failed to terminate inferior process for attach: {}; ignoring".format(sys.exc_info()[0]))
+ self.addTearDownHook(shutdown_process_for_attach)
+ return inferior
+
+ def prep_debug_monitor_and_inferior(self, inferior_args=None, inferior_sleep_seconds=3, inferior_exe_path=None):
+ """Prep the debug monitor, the inferior, and the expected packet stream.
+
+ Handle the separate cases of using the debug monitor in attach-to-inferior mode
+ and in launch-inferior mode.
+
+ For attach-to-inferior mode, the inferior process is first started, then
+ the debug monitor is started in attach to pid mode (using --attach on the
+ stub command line), and the no-ack-mode setup is appended to the packet
+ stream. The packet stream is not yet executed, ready to have more expected
+ packet entries added to it.
+
+ For launch-inferior mode, the stub is first started, then no ack mode is
+ setup on the expected packet stream, then the verified launch packets are added
+ to the expected socket stream. The packet stream is not yet executed, ready
+ to have more expected packet entries added to it.
+
+ The return value is:
+ {inferior:<inferior>, server:<server>}
+ """
+ inferior = None
+ attach_pid = None
+
+ if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY:
+ # Launch the process that we'll use as the inferior.
+ inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds, exe_path=inferior_exe_path)
+ self.assertIsNotNone(inferior)
+ self.assertTrue(inferior.pid > 0)
+ if self._inferior_startup == self._STARTUP_ATTACH:
+ # In this case, we want the stub to attach via the command line, so set the command line attach pid here.
+ attach_pid = inferior.pid
+
+ if self._inferior_startup == self._STARTUP_LAUNCH:
+ # Build launch args
+ if not inferior_exe_path:
+ inferior_exe_path = os.path.abspath("a.out")
+
+ if lldb.remote_platform:
+ remote_path = lldbutil.append_to_process_working_directory(os.path.basename(inferior_exe_path))
+ remote_file_spec = lldb.SBFileSpec(remote_path, False)
+ err = lldb.remote_platform.Install(lldb.SBFileSpec(inferior_exe_path, True), remote_file_spec)
+ if err.Fail():
+ raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (inferior_exe_path, remote_path, err))
+ inferior_exe_path = remote_path
+
+ launch_args = [inferior_exe_path]
+ if inferior_args:
+ launch_args.extend(inferior_args)
+
+ # Launch the debug monitor stub, attaching to the inferior.
+ server = self.connect_to_debug_monitor(attach_pid=attach_pid)
+ self.assertIsNotNone(server)
+
+ # Build the expected protocol stream
+ self.add_no_ack_remote_stream()
+ if self._inferior_startup == self._STARTUP_LAUNCH:
+ self.add_verified_launch_packets(launch_args)
+
+ return {"inferior":inferior, "server":server}
+
+ def expect_socket_recv(self, sock, expected_content_regex, timeout_seconds):
+ response = ""
+ timeout_time = time.time() + timeout_seconds
+
+ while not expected_content_regex.match(response) and time.time() < timeout_time:
+ can_read, _, _ = select.select([sock], [], [], timeout_seconds)
+ if can_read and sock in can_read:
+ recv_bytes = sock.recv(4096)
+ if recv_bytes:
+ response += recv_bytes
+
+ self.assertTrue(expected_content_regex.match(response))
+
+ def expect_socket_send(self, sock, content, timeout_seconds):
+ request_bytes_remaining = content
+ timeout_time = time.time() + timeout_seconds
+
+ while len(request_bytes_remaining) > 0 and time.time() < timeout_time:
+ _, can_write, _ = select.select([], [sock], [], timeout_seconds)
+ if can_write and sock in can_write:
+ written_byte_count = sock.send(request_bytes_remaining)
+ request_bytes_remaining = request_bytes_remaining[written_byte_count:]
+ self.assertEqual(len(request_bytes_remaining), 0)
+
+ def do_handshake(self, stub_socket, timeout_seconds=5):
+ # Write the ack.
+ self.expect_socket_send(stub_socket, "+", timeout_seconds)
+
+ # Send the start no ack mode packet.
+ NO_ACK_MODE_REQUEST = "$QStartNoAckMode#b0"
+ bytes_sent = stub_socket.send(NO_ACK_MODE_REQUEST)
+ self.assertEqual(bytes_sent, len(NO_ACK_MODE_REQUEST))
+
+ # Receive the ack and "OK"
+ self.expect_socket_recv(stub_socket, re.compile(r"^\+\$OK#[0-9a-fA-F]{2}$"), timeout_seconds)
+
+ # Send the final ack.
+ self.expect_socket_send(stub_socket, "+", timeout_seconds)
+
+ def add_no_ack_remote_stream(self):
+ self.test_sequence.add_log_lines(
+ ["read packet: +",
+ "read packet: $QStartNoAckMode#b0",
+ "send packet: +",
+ "send packet: $OK#9a",
+ "read packet: +"],
+ True)
+
+ def add_verified_launch_packets(self, launch_args):
+ self.test_sequence.add_log_lines(
+ ["read packet: %s" % build_gdbremote_A_packet(launch_args),
+ "send packet: $OK#00",
+ "read packet: $qLaunchSuccess#a5",
+ "send packet: $OK#00"],
+ True)
+
+ def add_thread_suffix_request_packets(self):
+ self.test_sequence.add_log_lines(
+ ["read packet: $QThreadSuffixSupported#e4",
+ "send packet: $OK#00",
+ ], True)
+
+ def add_process_info_collection_packets(self):
+ self.test_sequence.add_log_lines(
+ ["read packet: $qProcessInfo#dc",
+ { "direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"process_info_raw"} }],
+ True)
+
+ _KNOWN_PROCESS_INFO_KEYS = [
+ "pid",
+ "parent-pid",
+ "real-uid",
+ "real-gid",
+ "effective-uid",
+ "effective-gid",
+ "cputype",
+ "cpusubtype",
+ "ostype",
+ "triple",
+ "vendor",
+ "endian",
+ "ptrsize"
+ ]
+
+ def parse_process_info_response(self, context):
+ # Ensure we have a process info response.
+ self.assertIsNotNone(context)
+ process_info_raw = context.get("process_info_raw")
+ self.assertIsNotNone(process_info_raw)
+
+ # Pull out key:value; pairs.
+ process_info_dict = { match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) }
+
+ # Validate keys are known.
+ for (key, val) in list(process_info_dict.items()):
+ self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS)
+ self.assertIsNotNone(val)
+
+ return process_info_dict
+
+ def add_register_info_collection_packets(self):
+ self.test_sequence.add_log_lines(
+ [ { "type":"multi_response", "query":"qRegisterInfo", "append_iteration_suffix":True,
+ "end_regex":re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"),
+ "save_key":"reg_info_responses" } ],
+ True)
+
+ def parse_register_info_packets(self, context):
+ """Return an array of register info dictionaries, one per register info."""
+ reg_info_responses = context.get("reg_info_responses")
+ self.assertIsNotNone(reg_info_responses)
+
+ # Parse register infos.
+ return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses]
+
+ def expect_gdbremote_sequence(self, timeout_seconds=None):
+ if not timeout_seconds:
+ timeout_seconds = self._TIMEOUT_SECONDS
+ return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger)
+
+ _KNOWN_REGINFO_KEYS = [
+ "name",
+ "alt-name",
+ "bitsize",
+ "offset",
+ "encoding",
+ "format",
+ "set",
+ "ehframe",
+ "dwarf",
+ "generic",
+ "container-regs",
+ "invalidate-regs"
+ ]
+
+ def assert_valid_reg_info(self, reg_info):
+ # Assert we know about all the reginfo keys parsed.
+ for key in reg_info:
+ self.assertTrue(key in self._KNOWN_REGINFO_KEYS)
+
+ # Check the bare-minimum expected set of register info keys.
+ self.assertTrue("name" in reg_info)
+ self.assertTrue("bitsize" in reg_info)
+ self.assertTrue("offset" in reg_info)
+ self.assertTrue("encoding" in reg_info)
+ self.assertTrue("format" in reg_info)
+
+ def find_pc_reg_info(self, reg_infos):
+ lldb_reg_index = 0
+ for reg_info in reg_infos:
+ if ("generic" in reg_info) and (reg_info["generic"] == "pc"):
+ return (lldb_reg_index, reg_info)
+ lldb_reg_index += 1
+
+ return (None, None)
+
+ def add_lldb_register_index(self, reg_infos):
+ """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
+
+ We'll use this when we want to call packets like P/p with a register index but do so
+ on only a subset of the full register info set.
+ """
+ self.assertIsNotNone(reg_infos)
+
+ reg_index = 0
+ for reg_info in reg_infos:
+ reg_info["lldb_register_index"] = reg_index
+ reg_index += 1
+
+ def add_query_memory_region_packets(self, address):
+ self.test_sequence.add_log_lines(
+ ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
+ True)
+
+ def parse_key_val_dict(self, key_val_text, allow_dupes=True):
+ self.assertIsNotNone(key_val_text)
+ kv_dict = {}
+ for match in re.finditer(r";?([^:]+):([^;]+)", key_val_text):
+ key = match.group(1)
+ val = match.group(2)
+ if key in kv_dict:
+ if allow_dupes:
+ if type(kv_dict[key]) == list:
+ kv_dict[key].append(val)
+ else:
+ # Promote to list
+ kv_dict[key] = [kv_dict[key], val]
+ else:
+ self.fail("key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format(key, val, key_val_text, kv_dict))
+ else:
+ kv_dict[key] = val
+ return kv_dict
+
+ def parse_memory_region_packet(self, context):
+ # Ensure we have a context.
+ self.assertIsNotNone(context.get("memory_region_response"))
+
+ # Pull out key:value; pairs.
+ mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response"))
+
+ # Validate keys are known.
+ for (key, val) in list(mem_region_dict.items()):
+ self.assertTrue(key in ["start", "size", "permissions", "error"])
+ self.assertIsNotNone(val)
+
+ # Return the dictionary of key-value pairs for the memory region.
+ return mem_region_dict
+
+ def assert_address_within_memory_region(self, test_address, mem_region_dict):
+ self.assertIsNotNone(mem_region_dict)
+ self.assertTrue("start" in mem_region_dict)
+ self.assertTrue("size" in mem_region_dict)
+
+ range_start = int(mem_region_dict["start"], 16)
+ range_size = int(mem_region_dict["size"], 16)
+ range_end = range_start + range_size
+
+ if test_address < range_start:
+ self.fail("address 0x{0:x} comes before range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
+ elif test_address >= range_end:
+ self.fail("address 0x{0:x} comes after range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
+
+ def add_threadinfo_collection_packets(self):
+ self.test_sequence.add_log_lines(
+ [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
+ "append_iteration_suffix":False, "end_regex":re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"),
+ "save_key":"threadinfo_responses" } ],
+ True)
+
+ def parse_threadinfo_packets(self, context):
+ """Return an array of thread ids (decimal ints), one per thread."""
+ threadinfo_responses = context.get("threadinfo_responses")
+ self.assertIsNotNone(threadinfo_responses)
+
+ thread_ids = []
+ for threadinfo_response in threadinfo_responses:
+ new_thread_infos = parse_threadinfo_response(threadinfo_response)
+ thread_ids.extend(new_thread_infos)
+ return thread_ids
+
+ def wait_for_thread_count(self, thread_count, timeout_seconds=3):
+ start_time = time.time()
+ timeout_time = start_time + timeout_seconds
+
+ actual_thread_count = 0
+ while actual_thread_count < thread_count:
+ self.reset_test_sequence()
+ self.add_threadinfo_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+
+ actual_thread_count = len(threads)
+
+ if time.time() > timeout_time:
+ raise Exception(
+ 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format(
+ timeout_seconds, thread_count, actual_thread_count))
+
+ return threads
+
+ def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
+ self.test_sequence.add_log_lines(
+ [# Set the breakpoint.
+ "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
+ # Verify the stub could set it.
+ "send packet: $OK#00",
+ ], True)
+
+ if (do_continue):
+ self.test_sequence.add_log_lines(
+ [# Continue the inferior.
+ "read packet: $c#63",
+ # Expect a breakpoint stop report.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+ ], True)
+
+ def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
+ self.test_sequence.add_log_lines(
+ [# Remove the breakpoint.
+ "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
+ # Verify the stub could unset it.
+ "send packet: $OK#00",
+ ], True)
+
+ def add_qSupported_packets(self):
+ self.test_sequence.add_log_lines(
+ ["read packet: $qSupported#00",
+ {"direction":"send", "regex":r"^\$(.*)#[0-9a-fA-F]{2}", "capture":{1: "qSupported_response"}},
+ ], True)
+
+ _KNOWN_QSUPPORTED_STUB_FEATURES = [
+ "augmented-libraries-svr4-read",
+ "PacketSize",
+ "QStartNoAckMode",
+ "QThreadSuffixSupported",
+ "QListThreadsInStopReply",
+ "qXfer:auxv:read",
+ "qXfer:libraries:read",
+ "qXfer:libraries-svr4:read",
+ "qXfer:features:read",
+ "qEcho"
+ ]
+
+ def parse_qSupported_response(self, context):
+ self.assertIsNotNone(context)
+
+ raw_response = context.get("qSupported_response")
+ self.assertIsNotNone(raw_response)
+
+ # For values with key=val, the dict key and vals are set as expected. For feature+, feature- and feature?, the
+ # +,-,? is stripped from the key and set as the value.
+ supported_dict = {}
+ for match in re.finditer(r";?([^=;]+)(=([^;]+))?", raw_response):
+ key = match.group(1)
+ val = match.group(3)
+
+ # key=val: store as is
+ if val and len(val) > 0:
+ supported_dict[key] = val
+ else:
+ if len(key) < 2:
+ raise Exception("singular stub feature is too short: must be stub_feature{+,-,?}")
+ supported_type = key[-1]
+ key = key[:-1]
+ if not supported_type in ["+", "-", "?"]:
+ raise Exception("malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type))
+ supported_dict[key] = supported_type
+ # Ensure we know the supported element
+ if not key in self._KNOWN_QSUPPORTED_STUB_FEATURES:
+ raise Exception("unknown qSupported stub feature reported: %s" % key)
+
+ return supported_dict
+
+ def run_process_then_stop(self, run_seconds=1):
+ # Tell the stub to continue.
+ self.test_sequence.add_log_lines(
+ ["read packet: $vCont;c#a8"],
+ True)
+ context = self.expect_gdbremote_sequence()
+
+ # Wait for run_seconds.
+ time.sleep(run_seconds)
+
+ # Send an interrupt, capture a T response.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: {}".format(chr(3)),
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result"} }],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ self.assertIsNotNone(context.get("stop_result"))
+
+ return context
+
+ def select_modifiable_register(self, reg_infos):
+ """Find a register that can be read/written freely."""
+ PREFERRED_REGISTER_NAMES = set(["rax",])
+
+ # First check for the first register from the preferred register name set.
+ alternative_register_index = None
+
+ self.assertIsNotNone(reg_infos)
+ for reg_info in reg_infos:
+ if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES):
+ # We found a preferred register. Use it.
+ return reg_info["lldb_register_index"]
+ if ("generic" in reg_info) and (reg_info["generic"] == "fp"):
+ # A frame pointer register will do as a register to modify temporarily.
+ alternative_register_index = reg_info["lldb_register_index"]
+
+ # We didn't find a preferred register. Return whatever alternative register
+ # we found, if any.
+ return alternative_register_index
+
+ def extract_registers_from_stop_notification(self, stop_key_vals_text):
+ self.assertIsNotNone(stop_key_vals_text)
+ kv_dict = self.parse_key_val_dict(stop_key_vals_text)
+
+ registers = {}
+ for (key, val) in list(kv_dict.items()):
+ if re.match(r"^[0-9a-fA-F]+$", key):
+ registers[int(key, 16)] = val
+ return registers
+
+ def gather_register_infos(self):
+ self.reset_test_sequence()
+ self.add_register_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ return reg_infos
+
+ def find_generic_register_with_name(self, reg_infos, generic_name):
+ self.assertIsNotNone(reg_infos)
+ for reg_info in reg_infos:
+ if ("generic" in reg_info) and (reg_info["generic"] == generic_name):
+ return reg_info
+ return None
+
+ def decode_gdbremote_binary(self, encoded_bytes):
+ decoded_bytes = ""
+ i = 0
+ while i < len(encoded_bytes):
+ if encoded_bytes[i] == "}":
+ # Handle escaped char.
+ self.assertTrue(i + 1 < len(encoded_bytes))
+ decoded_bytes += chr(ord(encoded_bytes[i+1]) ^ 0x20)
+ i +=2
+ elif encoded_bytes[i] == "*":
+ # Handle run length encoding.
+ self.assertTrue(len(decoded_bytes) > 0)
+ self.assertTrue(i + 1 < len(encoded_bytes))
+ repeat_count = ord(encoded_bytes[i+1]) - 29
+ decoded_bytes += decoded_bytes[-1] * repeat_count
+ i += 2
+ else:
+ decoded_bytes += encoded_bytes[i]
+ i += 1
+ return decoded_bytes
+
+ def build_auxv_dict(self, endian, word_size, auxv_data):
+ self.assertIsNotNone(endian)
+ self.assertIsNotNone(word_size)
+ self.assertIsNotNone(auxv_data)
+
+ auxv_dict = {}
+
+ while len(auxv_data) > 0:
+ # Chop off key.
+ raw_key = auxv_data[:word_size]
+ auxv_data = auxv_data[word_size:]
+
+ # Chop of value.
+ raw_value = auxv_data[:word_size]
+ auxv_data = auxv_data[word_size:]
+
+ # Convert raw text from target endian.
+ key = unpack_endian_binary_string(endian, raw_key)
+ value = unpack_endian_binary_string(endian, raw_value)
+
+ # Handle ending entry.
+ if key == 0:
+ self.assertEqual(value, 0)
+ return auxv_dict
+
+ # The key should not already be present.
+ self.assertFalse(key in auxv_dict)
+ auxv_dict[key] = value
+
+ self.fail("should not reach here - implies required double zero entry not found")
+ return auxv_dict
+
+ def read_binary_data_in_chunks(self, command_prefix, chunk_length):
+ """Collect command_prefix{offset:x},{chunk_length:x} until a single 'l' or 'l' with data is returned."""
+ offset = 0
+ done = False
+ decoded_data = ""
+
+ while not done:
+ # Grab the next iteration of data.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
+ {"direction":"send", "regex":re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE|re.DOTALL), "capture":{1:"response_type", 2:"content_raw"} }
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ response_type = context.get("response_type")
+ self.assertIsNotNone(response_type)
+ self.assertTrue(response_type in ["l", "m"])
+
+ # Move offset along.
+ offset += chunk_length
+
+ # Figure out if we're done. We're done if the response type is l.
+ done = response_type == "l"
+
+ # Decode binary data.
+ content_raw = context.get("content_raw")
+ if content_raw and len(content_raw) > 0:
+ self.assertIsNotNone(content_raw)
+ decoded_data += self.decode_gdbremote_binary(content_raw)
+ return decoded_data
+
+ def add_interrupt_packets(self):
+ self.test_sequence.add_log_lines([
+ # Send the intterupt.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
+ ], True)
+
+ def parse_interrupt_packets(self, context):
+ self.assertIsNotNone(context.get("stop_signo"))
+ self.assertIsNotNone(context.get("stop_key_val_text"))
+ return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
+
+ def add_QSaveRegisterState_packets(self, thread_id):
+ if thread_id:
+ # Use the thread suffix form.
+ request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
+ else:
+ request = "read packet: $QSaveRegisterState#00"
+
+ self.test_sequence.add_log_lines([
+ request,
+ {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
+ ], True)
+
+ def parse_QSaveRegisterState_response(self, context):
+ self.assertIsNotNone(context)
+
+ save_response = context.get("save_response")
+ self.assertIsNotNone(save_response)
+
+ if len(save_response) < 1 or save_response[0] == "E":
+ # error received
+ return (False, None)
+ else:
+ return (True, int(save_response))
+
+ def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
+ if thread_id:
+ # Use the thread suffix form.
+ request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
+ else:
+ request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
+
+ self.test_sequence.add_log_lines([
+ request,
+ "send packet: $OK#00"
+ ], True)
+
+ def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
+ self.assertIsNotNone(reg_infos)
+
+ successful_writes = 0
+ failed_writes = 0
+
+ for reg_info in reg_infos:
+ # Use the lldb register index added to the reg info. We're not necessarily
+ # working off a full set of register infos, so an inferred register index could be wrong.
+ reg_index = reg_info["lldb_register_index"]
+ self.assertIsNotNone(reg_index)
+
+ reg_byte_size = int(reg_info["bitsize"])/8
+ self.assertTrue(reg_byte_size > 0)
+
+ # Handle thread suffix.
+ if thread_id:
+ p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
+ else:
+ p_request = "read packet: $p{:x}#00".format(reg_index)
+
+ # Read the existing value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ p_request,
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the response length.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
+
+ # Flip the value by xoring with all 1s
+ all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
+ flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
+ # print("reg (index={}, name={}): val={}, flipped bits (int={}, hex={:x})".format(reg_index, reg_info["name"], initial_reg_value, flipped_bits_int, flipped_bits_int))
+
+ # Handle thread suffix for P.
+ if thread_id:
+ P_request = "read packet: $P{:x}={};thread:{:x}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size), thread_id)
+ else:
+ P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
+
+ # Write the flipped value to the register.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ P_request,
+ { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Determine if the write succeeded. There are a handful of registers that can fail, or partially fail
+ # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
+ # all flipping perfectly.
+ P_response = context.get("P_response")
+ self.assertIsNotNone(P_response)
+ if P_response == "OK":
+ successful_writes += 1
+ else:
+ failed_writes += 1
+ # print("reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response))
+
+ # Read back the register value, ensure it matches the flipped value.
+ if P_response == "OK":
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ p_request,
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ verify_p_response_raw = context.get("p_response")
+ self.assertIsNotNone(verify_p_response_raw)
+ verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
+
+ if verify_bits != flipped_bits_int:
+ # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts.
+ # print("reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits))
+ successful_writes -= 1
+ failed_writes +=1
+
+ return (successful_writes, failed_writes)
+
+ def is_bit_flippable_register(self, reg_info):
+ if not reg_info:
+ return False
+ if not "set" in reg_info:
+ return False
+ if reg_info["set"] != "General Purpose Registers":
+ return False
+ if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
+ # Don't try to bit flip registers contained in another register.
+ return False
+ if re.match("^.s$", reg_info["name"]):
+ # This is a 2-letter register name that ends in "s", like a segment register.
+ # Don't try to bit flip these.
+ return False
+ if re.match("^(c|)psr$", reg_info["name"]):
+ # This is an ARM program status register; don't flip it.
+ return False
+ # Okay, this looks fine-enough.
+ return True
+
+ def read_register_values(self, reg_infos, endian, thread_id=None):
+ self.assertIsNotNone(reg_infos)
+ values = {}
+
+ for reg_info in reg_infos:
+ # We append a register index when load reg infos so we can work with subsets.
+ reg_index = reg_info.get("lldb_register_index")
+ self.assertIsNotNone(reg_index)
+
+ # Handle thread suffix.
+ if thread_id:
+ p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
+ else:
+ p_request = "read packet: $p{:x}#00".format(reg_index)
+
+ # Read it with p.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ p_request,
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Convert value from target endian to integral.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ self.assertTrue(len(p_response) > 0)
+ self.assertFalse(p_response[0] == "E")
+
+ values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
+
+ return values
+
+ def add_vCont_query_packets(self):
+ self.test_sequence.add_log_lines([
+ "read packet: $vCont?#49",
+ {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } },
+ ], True)
+
+ def parse_vCont_query_response(self, context):
+ self.assertIsNotNone(context)
+ vCont_query_response = context.get("vCont_query_response")
+
+ # Handle case of no vCont support at all - in which case the capture group will be none or zero length.
+ if not vCont_query_response or len(vCont_query_response) == 0:
+ return {}
+
+ return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0}
+
+ def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"):
+ """Used by single step test that appears in a few different contexts."""
+ single_step_count = 0
+
+ while single_step_count < max_step_count:
+ self.assertIsNotNone(thread_id)
+
+ # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id.
+ step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction))
+ # print("\nstep_packet created: {}\n".format(step_packet))
+
+ # Single step.
+ self.reset_test_sequence()
+ if use_Hc_packet:
+ self.test_sequence.add_log_lines(
+ [# Set the continue thread.
+ "read packet: $Hc{0:x}#00".format(thread_id),
+ "send packet: $OK#00",
+ ], True)
+ self.test_sequence.add_log_lines([
+ # Single step.
+ step_packet,
+ # "read packet: $vCont;s:{0:x}#00".format(thread_id),
+ # Expect a breakpoint stop report.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ self.assertIsNotNone(context.get("stop_signo"))
+ self.assertEqual(int(context.get("stop_signo"), 16),
+ lldbutil.get_signal_number('SIGTRAP'))
+
+ single_step_count += 1
+
+ # See if the predicate is true. If so, we're done.
+ if predicate(args):
+ return (True, single_step_count)
+
+ # The predicate didn't return true within the runaway step count.
+ return (False, single_step_count)
+
+ def g_c1_c2_contents_are(self, args):
+ """Used by single step test that appears in a few different contexts."""
+ g_c1_address = args["g_c1_address"]
+ g_c2_address = args["g_c2_address"]
+ expected_g_c1 = args["expected_g_c1"]
+ expected_g_c2 = args["expected_g_c2"]
+
+ # Read g_c1 and g_c2 contents.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
+ "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Check if what we read from inferior memory is what we are expecting.
+ self.assertIsNotNone(context.get("g_c1_contents"))
+ self.assertIsNotNone(context.get("g_c2_contents"))
+
+ return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
+
+ def single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"):
+ """Used by single step test that appears in a few different contexts."""
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:swap_chars", "get-data-address-hex:g_c1", "get-data-address-hex:g_c2", "sleep:1", "call-function:swap_chars", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [# Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$",
+ "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the main thread id.
+ self.assertIsNotNone(context.get("stop_thread_id"))
+ main_thread_id = int(context.get("stop_thread_id"), 16)
+
+ # Grab the function address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Grab the data addresses.
+ self.assertIsNotNone(context.get("g_c1_address"))
+ g_c1_address = int(context.get("g_c1_address"), 16)
+
+ self.assertIsNotNone(context.get("g_c2_address"))
+ g_c2_address = int(context.get("g_c2_address"), 16)
+
+ # Set a breakpoint at the given address.
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ BREAKPOINT_KIND = 4
+ else:
+ BREAKPOINT_KIND = 1
+ self.reset_test_sequence()
+ self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Remove the breakpoint.
+ self.reset_test_sequence()
+ self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify g_c1 and g_c2 match expected initial state.
+ args = {}
+ args["g_c1_address"] = g_c1_address
+ args["g_c2_address"] = g_c2_address
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "1"
+
+ self.assertTrue(self.g_c1_c2_contents_are(args))
+
+ # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
+ args["expected_g_c1"] = "1"
+ args["expected_g_c2"] = "1"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=25, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
+ self.assertTrue(state_reached)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "1"
+ args["expected_g_c2"] = "0"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
+ self.assertTrue(state_reached)
+ expected_step_count = 1
+ arch = self.getArchitecture()
+
+ #MIPS required "3" (ADDIU, SB, LD) machine instructions for updation of variable value
+ if re.match("mips",arch):
+ expected_step_count = 3
+ self.assertEqual(step_count, expected_step_count)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "0"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
+ self.assertTrue(state_reached)
+ self.assertEqual(step_count, expected_step_count)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "1"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
+ self.assertTrue(state_reached)
+ self.assertEqual(step_count, expected_step_count)
+
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/Makefile b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/Makefile
new file mode 100644
index 0000000..a47e279
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/Makefile
@@ -0,0 +1,8 @@
+LEVEL = ../../../make
+
+CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS -std=c++11
+# LD_EXTRAS := -lpthread
+CXX_SOURCES := main.cpp
+MAKE_DSYM :=NO
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteAbort.py b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteAbort.py
new file mode 100644
index 0000000..d134332
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteAbort.py
@@ -0,0 +1,42 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import signal
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteAbort(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ def inferior_abort_received(self):
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["abort"])
+ self.assertIsNotNone(procs)
+
+ self.test_sequence.add_log_lines([
+ "read packet: $vCont;c#a8",
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture":{ 1:"hex_exit_code"} },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ hex_exit_code = context.get("hex_exit_code")
+ self.assertIsNotNone(hex_exit_code)
+ self.assertEqual(int(hex_exit_code, 16),
+ lldbutil.get_signal_number('SIGABRT'))
+
+ @debugserver_test
+ def test_inferior_abort_received_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.inferior_abort_received()
+
+ @llgs_test
+ # std::abort() on <= API 16 raises SIGSEGV - b.android.com/179836
+ @expectedFailureAndroid(api_levels=list(range(16 + 1)))
+ def test_inferior_abort_received_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.inferior_abort_received()
+
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteSegFault.py b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteSegFault.py
new file mode 100644
index 0000000..6618d8f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteSegFault.py
@@ -0,0 +1,40 @@
+from __future__ import print_function
+
+
+
+import gdbremote_testcase
+import signal
+from lldbsuite.test.lldbtest import *
+
+class TestGdbRemoteSegFault(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ GDB_REMOTE_STOP_CODE_BAD_ACCESS = 0x91
+
+ def inferior_seg_fault_received(self, expected_signo):
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["segfault"])
+ self.assertIsNotNone(procs)
+
+ self.test_sequence.add_log_lines([
+ "read packet: $vCont;c#a8",
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture":{ 1:"hex_exit_code"} },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ hex_exit_code = context.get("hex_exit_code")
+ self.assertIsNotNone(hex_exit_code)
+ self.assertEqual(int(hex_exit_code, 16), expected_signo)
+
+ @debugserver_test
+ def test_inferior_seg_fault_received_debugserver(self):
+ self.init_debugserver_test()
+ self.build()
+ self.inferior_seg_fault_received(self.GDB_REMOTE_STOP_CODE_BAD_ACCESS)
+
+ @llgs_test
+ def test_inferior_seg_fault_received_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.inferior_seg_fault_received(lldbutil.get_signal_number('SIGSEGV'))
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/main.cpp
new file mode 100644
index 0000000..69d6007
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/main.cpp
@@ -0,0 +1,39 @@
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+namespace
+{
+ const char *const SEGFAULT_COMMAND = "segfault";
+ const char *const ABORT_COMMAND = "abort";
+}
+
+int main (int argc, char **argv)
+{
+ if (argc < 2)
+ {
+ std::cout << "expected at least one command provided on the command line" << std::endl;
+ }
+
+ // Process command line args.
+ for (int i = 1; i < argc; ++i)
+ {
+ const char *const command = argv[i];
+ if (std::strstr (command, SEGFAULT_COMMAND))
+ {
+ // Perform a null pointer access.
+ int *const null_int_ptr = nullptr;
+ *null_int_ptr = 0xDEAD;
+ }
+ else if (std::strstr (command, ABORT_COMMAND))
+ {
+ std::abort();
+ }
+ else
+ {
+ std::cout << "Unsupported command: " << command << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py b/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
new file mode 100644
index 0000000..c0ea841
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
@@ -0,0 +1,843 @@
+"""Module for supporting unit testing of the lldb-server debug monitor exe.
+"""
+
+from __future__ import print_function
+
+
+
+import os
+import os.path
+import platform
+import re
+import six
+import socket_packet_pump
+import subprocess
+import time
+from lldbsuite.test.lldbtest import *
+
+from six.moves import queue
+
+def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename):
+ """Return the debug monitor exe path given the lldb exe path.
+
+ This method attempts to construct a valid debug monitor exe name
+ from a given lldb exe name. It will return None if the synthesized
+ debug monitor name is not found to exist.
+
+ The debug monitor exe path is synthesized by taking the directory
+ of the lldb exe, and replacing the portion of the base name that
+ matches "lldb" (case insensitive) and replacing with the value of
+ debug_monitor_basename.
+
+ Args:
+ lldb_exe: the path to an lldb executable.
+
+ debug_monitor_basename: the base name portion of the debug monitor
+ that will replace 'lldb'.
+
+ Returns:
+ A path to the debug monitor exe if it is found to exist; otherwise,
+ returns None.
+
+ """
+ if not lldb_exe:
+ return None
+
+ exe_dir = os.path.dirname(lldb_exe)
+ exe_base = os.path.basename(lldb_exe)
+
+ # we'll rebuild the filename by replacing lldb with
+ # the debug monitor basename, keeping any prefix or suffix in place.
+ regex = re.compile(r"lldb", re.IGNORECASE)
+ new_base = regex.sub(debug_monitor_basename, exe_base)
+
+ debug_monitor_exe = os.path.join(exe_dir, new_base)
+ if os.path.exists(debug_monitor_exe):
+ return debug_monitor_exe
+
+ new_base = regex.sub( 'LLDB.framework/Versions/A/Resources/' + debug_monitor_basename, exe_base)
+ debug_monitor_exe = os.path.join(exe_dir, new_base)
+ if os.path.exists(debug_monitor_exe):
+ return debug_monitor_exe
+
+ return None
+
+
+def get_lldb_server_exe():
+ """Return the lldb-server exe path.
+
+ Returns:
+ A path to the lldb-server exe if it is found to exist; otherwise,
+ returns None.
+ """
+ if "LLDB_DEBUGSERVER_PATH" in os.environ:
+ return os.environ["LLDB_DEBUGSERVER_PATH"]
+
+ return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "lldb-server")
+
+def get_debugserver_exe():
+ """Return the debugserver exe path.
+
+ Returns:
+ A path to the debugserver exe if it is found to exist; otherwise,
+ returns None.
+ """
+ if "LLDB_DEBUGSERVER_PATH" in os.environ:
+ return os.environ["LLDB_DEBUGSERVER_PATH"]
+
+ return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "debugserver")
+
+_LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' +
+ '\s+(read|send)\s+packet:\s+(.+)$')
+
+
+def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read):
+ """Return whether a given packet is input for lldb-gdbserver.
+
+ Args:
+ packet_type: a string indicating 'send' or 'receive', from a
+ gdbremote packet protocol log.
+
+ llgs_input_is_read: true if lldb-gdbserver input (content sent to
+ lldb-gdbserver) is listed as 'read' or 'send' in the packet
+ log entry.
+
+ Returns:
+ True if the packet should be considered input for lldb-gdbserver; False
+ otherwise.
+ """
+ if packet_type == 'read':
+ # when llgs is the read side, then a read packet is meant for
+ # input to llgs (when captured from the llgs/debugserver exe).
+ return llgs_input_is_read
+ elif packet_type == 'send':
+ # when llgs is the send side, then a send packet is meant to
+ # be input to llgs (when captured from the lldb exe).
+ return not llgs_input_is_read
+ else:
+ # don't understand what type of packet this is
+ raise "Unknown packet type: {}".format(packet_type)
+
+
+def handle_O_packet(context, packet_contents, logger):
+ """Handle O packets."""
+ if (not packet_contents) or (len(packet_contents) < 1):
+ return False
+ elif packet_contents[0] != "O":
+ return False
+ elif packet_contents == "OK":
+ return False
+
+ new_text = gdbremote_hex_decode_string(packet_contents[1:])
+ context["O_content"] += new_text
+ context["O_count"] += 1
+
+ if logger:
+ logger.debug("text: new \"{}\", cumulative: \"{}\"".format(new_text, context["O_content"]))
+
+ return True
+
+_STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$')
+_STRIP_COMMAND_PREFIX_REGEX = re.compile(r"^\$")
+_STRIP_COMMAND_PREFIX_M_REGEX = re.compile(r"^\$m")
+
+
+def assert_packets_equal(asserter, actual_packet, expected_packet):
+ # strip off the checksum digits of the packet. When we're in
+ # no-ack mode, the # checksum is ignored, and should not be cause
+ # for a mismatched packet.
+ actual_stripped = _STRIP_CHECKSUM_REGEX.sub('', actual_packet)
+ expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet)
+ asserter.assertEqual(actual_stripped, expected_stripped)
+
+def expect_lldb_gdbserver_replay(
+ asserter,
+ sock,
+ test_sequence,
+ timeout_seconds,
+ logger=None):
+ """Replay socket communication with lldb-gdbserver and verify responses.
+
+ Args:
+ asserter: the object providing assertEqual(first, second, msg=None), e.g. TestCase instance.
+
+ sock: the TCP socket connected to the lldb-gdbserver exe.
+
+ test_sequence: a GdbRemoteTestSequence instance that describes
+ the messages sent to the gdb remote and the responses
+ expected from it.
+
+ timeout_seconds: any response taking more than this number of
+ seconds will cause an exception to be raised.
+
+ logger: a Python logger instance.
+
+ Returns:
+ The context dictionary from running the given gdbremote
+ protocol sequence. This will contain any of the capture
+ elements specified to any GdbRemoteEntry instances in
+ test_sequence.
+
+ The context will also contain an entry, context["O_content"]
+ which contains the text from the inferior received via $O
+ packets. $O packets should not attempt to be matched
+ directly since they are not entirely deterministic as to
+ how many arrive and how much text is in each one.
+
+ context["O_count"] will contain an integer of the number of
+ O packets received.
+ """
+
+ # Ensure we have some work to do.
+ if len(test_sequence.entries) < 1:
+ return {}
+
+ context = {"O_count":0, "O_content":""}
+ with socket_packet_pump.SocketPacketPump(sock, logger) as pump:
+ # Grab the first sequence entry.
+ sequence_entry = test_sequence.entries.pop(0)
+
+ # While we have an active sequence entry, send messages
+ # destined for the stub and collect/match/process responses
+ # expected from the stub.
+ while sequence_entry:
+ if sequence_entry.is_send_to_remote():
+ # This is an entry to send to the remote debug monitor.
+ send_packet = sequence_entry.get_send_packet()
+ if logger:
+ if len(send_packet) == 1 and send_packet[0] == chr(3):
+ packet_desc = "^C"
+ else:
+ packet_desc = send_packet
+ logger.info("sending packet to remote: {}".format(packet_desc))
+ sock.sendall(send_packet)
+ else:
+ # This is an entry expecting to receive content from the remote debug monitor.
+
+ # We'll pull from (and wait on) the queue appropriate for the type of matcher.
+ # We keep separate queues for process output (coming from non-deterministic
+ # $O packet division) and for all other packets.
+ if sequence_entry.is_output_matcher():
+ try:
+ # Grab next entry from the output queue.
+ content = pump.output_queue().get(True, timeout_seconds)
+ except queue.Empty:
+ if logger:
+ logger.warning("timeout waiting for stub output (accumulated output:{})".format(pump.get_accumulated_output()))
+ raise Exception("timed out while waiting for output match (accumulated output: {})".format(pump.get_accumulated_output()))
+ else:
+ try:
+ content = pump.packet_queue().get(True, timeout_seconds)
+ except queue.Empty:
+ if logger:
+ logger.warning("timeout waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer()))
+ raise Exception("timed out while waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer()))
+
+ # Give the sequence entry the opportunity to match the content.
+ # Output matchers might match or pass after more output accumulates.
+ # Other packet types generally must match.
+ asserter.assertIsNotNone(content)
+ context = sequence_entry.assert_match(asserter, content, context=context)
+
+ # Move on to next sequence entry as needed. Some sequence entries support executing multiple
+ # times in different states (for looping over query/response packets).
+ if sequence_entry.is_consumed():
+ if len(test_sequence.entries) > 0:
+ sequence_entry = test_sequence.entries.pop(0)
+ else:
+ sequence_entry = None
+
+ # Fill in the O_content entries.
+ context["O_count"] = 1
+ context["O_content"] = pump.get_accumulated_output()
+
+ return context
+
+def gdbremote_hex_encode_string(str):
+ output = ''
+ for c in str:
+ output += '{0:02x}'.format(ord(c))
+ return output
+
+def gdbremote_hex_decode_string(str):
+ return str.decode("hex")
+
+def gdbremote_packet_encode_string(str):
+ checksum = 0
+ for c in str:
+ checksum += ord(c)
+ return '$' + str + '#{0:02x}'.format(checksum % 256)
+
+def build_gdbremote_A_packet(args_list):
+ """Given a list of args, create a properly-formed $A packet containing each arg.
+ """
+ payload = "A"
+
+ # build the arg content
+ arg_index = 0
+ for arg in args_list:
+ # Comma-separate the args.
+ if arg_index > 0:
+ payload += ','
+
+ # Hex-encode the arg.
+ hex_arg = gdbremote_hex_encode_string(arg)
+
+ # Build the A entry.
+ payload += "{},{},{}".format(len(hex_arg), arg_index, hex_arg)
+
+ # Next arg index, please.
+ arg_index += 1
+
+ # return the packetized payload
+ return gdbremote_packet_encode_string(payload)
+
+
+def parse_reg_info_response(response_packet):
+ if not response_packet:
+ raise Exception("response_packet cannot be None")
+
+ # Strip off prefix $ and suffix #xx if present.
+ response_packet = _STRIP_COMMAND_PREFIX_REGEX.sub("", response_packet)
+ response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)
+
+ # Build keyval pairs
+ values = {}
+ for kv in response_packet.split(";"):
+ if len(kv) < 1:
+ continue
+ (key, val) = kv.split(':')
+ values[key] = val
+
+ return values
+
+
+def parse_threadinfo_response(response_packet):
+ if not response_packet:
+ raise Exception("response_packet cannot be None")
+
+ # Strip off prefix $ and suffix #xx if present.
+ response_packet = _STRIP_COMMAND_PREFIX_M_REGEX.sub("", response_packet)
+ response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)
+
+ # Return list of thread ids
+ return [int(thread_id_hex,16) for thread_id_hex in response_packet.split(",") if len(thread_id_hex) > 0]
+
+def unpack_endian_binary_string(endian, value_string):
+ """Unpack a gdb-remote binary (post-unescaped, i.e. not escaped) response to an unsigned int given endianness of the inferior."""
+ if not endian:
+ raise Exception("endian cannot be None")
+ if not value_string or len(value_string) < 1:
+ raise Exception("value_string cannot be None or empty")
+
+ if endian == 'little':
+ value = 0
+ i = 0
+ while len(value_string) > 0:
+ value += (ord(value_string[0]) << i)
+ value_string = value_string[1:]
+ i += 8
+ return value
+ elif endian == 'big':
+ value = 0
+ while len(value_string) > 0:
+ value = (value << 8) + ord(value_string[0])
+ value_string = value_string[1:]
+ return value
+ else:
+ # pdp is valid but need to add parse code once needed.
+ raise Exception("unsupported endian:{}".format(endian))
+
+def unpack_register_hex_unsigned(endian, value_string):
+ """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
+ if not endian:
+ raise Exception("endian cannot be None")
+ if not value_string or len(value_string) < 1:
+ raise Exception("value_string cannot be None or empty")
+
+ if endian == 'little':
+ value = 0
+ i = 0
+ while len(value_string) > 0:
+ value += (int(value_string[0:2], 16) << i)
+ value_string = value_string[2:]
+ i += 8
+ return value
+ elif endian == 'big':
+ return int(value_string, 16)
+ else:
+ # pdp is valid but need to add parse code once needed.
+ raise Exception("unsupported endian:{}".format(endian))
+
+def pack_register_hex(endian, value, byte_size=None):
+ """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
+ if not endian:
+ raise Exception("endian cannot be None")
+
+ if endian == 'little':
+ # Create the litt-endian return value.
+ retval = ""
+ while value != 0:
+ retval = retval + "{:02x}".format(value & 0xff)
+ value = value >> 8
+ if byte_size:
+ # Add zero-fill to the right/end (MSB side) of the value.
+ retval += "00" * (byte_size - len(retval)/2)
+ return retval
+
+ elif endian == 'big':
+ retval = value.encode("hex")
+ if byte_size:
+ # Add zero-fill to the left/front (MSB side) of the value.
+ retval = ("00" * (byte_size - len(retval)/2)) + retval
+ return retval
+
+ else:
+ # pdp is valid but need to add parse code once needed.
+ raise Exception("unsupported endian:{}".format(endian))
+
+class GdbRemoteEntryBase(object):
+ def is_output_matcher(self):
+ return False
+
+class GdbRemoteEntry(GdbRemoteEntryBase):
+
+ def __init__(self, is_send_to_remote=True, exact_payload=None, regex=None, capture=None, expect_captures=None):
+ """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor.
+
+ Args:
+
+ is_send_to_remote: True if this entry is a message to be
+ sent to the gdbremote debug monitor; False if this
+ entry represents text to be matched against the reply
+ from the gdbremote debug monitor.
+
+ exact_payload: if not None, then this packet is an exact
+ send (when sending to the remote) or an exact match of
+ the response from the gdbremote. The checksums are
+ ignored on exact match requests since negotiation of
+ no-ack makes the checksum content essentially
+ undefined.
+
+ regex: currently only valid for receives from gdbremote.
+ When specified (and only if exact_payload is None),
+ indicates the gdbremote response must match the given
+ regex. Match groups in the regex can be used for two
+ different purposes: saving the match (see capture
+ arg), or validating that a match group matches a
+ previously established value (see expect_captures). It
+ is perfectly valid to have just a regex arg and to
+ specify neither capture or expect_captures args. This
+ arg only makes sense if exact_payload is not
+ specified.
+
+ capture: if specified, is a dictionary of regex match
+ group indices (should start with 1) to variable names
+ that will store the capture group indicated by the
+ index. For example, {1:"thread_id"} will store capture
+ group 1's content in the context dictionary where
+ "thread_id" is the key and the match group value is
+ the value. The value stored off can be used later in a
+ expect_captures expression. This arg only makes sense
+ when regex is specified.
+
+ expect_captures: if specified, is a dictionary of regex
+ match group indices (should start with 1) to variable
+ names, where the match group should match the value
+ existing in the context at the given variable name.
+ For example, {2:"thread_id"} indicates that the second
+ match group must match the value stored under the
+ context's previously stored "thread_id" key. This arg
+ only makes sense when regex is specified.
+ """
+ self._is_send_to_remote = is_send_to_remote
+ self.exact_payload = exact_payload
+ self.regex = regex
+ self.capture = capture
+ self.expect_captures = expect_captures
+
+ def is_send_to_remote(self):
+ return self._is_send_to_remote
+
+ def is_consumed(self):
+ # For now, all packets are consumed after first use.
+ return True
+
+ def get_send_packet(self):
+ if not self.is_send_to_remote():
+ raise Exception("get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet")
+ if not self.exact_payload:
+ raise Exception("get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload")
+ return self.exact_payload
+
+ def _assert_exact_payload_match(self, asserter, actual_packet):
+ assert_packets_equal(asserter, actual_packet, self.exact_payload)
+ return None
+
+ def _assert_regex_match(self, asserter, actual_packet, context):
+ # Ensure the actual packet matches from the start of the actual packet.
+ match = self.regex.match(actual_packet)
+ if not match:
+ asserter.fail("regex '{}' failed to match against content '{}'".format(self.regex.pattern, actual_packet))
+
+ if self.capture:
+ # Handle captures.
+ for group_index, var_name in list(self.capture.items()):
+ capture_text = match.group(group_index)
+ # It is okay for capture text to be None - which it will be if it is a group that can match nothing.
+ # The user must be okay with it since the regex itself matched above.
+ context[var_name] = capture_text
+
+ if self.expect_captures:
+ # Handle comparing matched groups to context dictionary entries.
+ for group_index, var_name in list(self.expect_captures.items()):
+ capture_text = match.group(group_index)
+ if not capture_text:
+ raise Exception("No content to expect for group index {}".format(group_index))
+ asserter.assertEqual(capture_text, context[var_name])
+
+ return context
+
+ def assert_match(self, asserter, actual_packet, context=None):
+ # This only makes sense for matching lines coming from the
+ # remote debug monitor.
+ if self.is_send_to_remote():
+ raise Exception("Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.")
+
+ # Create a new context if needed.
+ if not context:
+ context = {}
+
+ # If this is an exact payload, ensure they match exactly,
+ # ignoring the packet checksum which is optional for no-ack
+ # mode.
+ if self.exact_payload:
+ self._assert_exact_payload_match(asserter, actual_packet)
+ return context
+ elif self.regex:
+ return self._assert_regex_match(asserter, actual_packet, context)
+ else:
+ raise Exception("Don't know how to match a remote-sent packet when exact_payload isn't specified.")
+
+class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
+ """Represents a query/response style packet.
+
+ Assumes the first item is sent to the gdb remote.
+ An end sequence regex indicates the end of the query/response
+ packet sequence. All responses up through (but not including) the
+ end response are stored in a context variable.
+
+ Settings accepted from params:
+
+ next_query or query: required. The typical query packet without the $ prefix or #xx suffix.
+ If there is a special first packet to start the iteration query, see the
+ first_query key.
+
+ first_query: optional. If the first query requires a special query command, specify
+ it with this key. Do not specify the $ prefix or #xx suffix.
+
+ append_iteration_suffix: defaults to False. Specify True if the 0-based iteration
+ index should be appended as a suffix to the command. e.g. qRegisterInfo with
+ this key set true will generate query packets of qRegisterInfo0, qRegisterInfo1,
+ etc.
+
+ end_regex: required. Specifies a compiled regex object that will match the full text
+ of any response that signals an end to the iteration. It must include the
+ initial $ and ending #xx and must match the whole packet.
+
+ save_key: required. Specifies the key within the context where an array will be stored.
+ Each packet received from the gdb remote that does not match the end_regex will get
+ appended to the array stored within the context at that key.
+
+ runaway_response_count: optional. Defaults to 10000. If this many responses are retrieved,
+ assume there is something wrong with either the response collection or the ending
+ detection regex and throw an exception.
+ """
+ def __init__(self, params):
+ self._next_query = params.get("next_query", params.get("query"))
+ if not self._next_query:
+ raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry"
+
+ self._first_query = params.get("first_query", self._next_query)
+ self._append_iteration_suffix = params.get("append_iteration_suffix", False)
+ self._iteration = 0
+ self._end_regex = params["end_regex"]
+ self._save_key = params["save_key"]
+ self._runaway_response_count = params.get("runaway_response_count", 10000)
+ self._is_send_to_remote = True
+ self._end_matched = False
+
+ def is_send_to_remote(self):
+ return self._is_send_to_remote
+
+ def get_send_packet(self):
+ if not self.is_send_to_remote():
+ raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state")
+ if self._end_matched:
+ raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
+
+ # Choose the first or next query for the base payload.
+ if self._iteration == 0 and self._first_query:
+ payload = self._first_query
+ else:
+ payload = self._next_query
+
+ # Append the suffix as needed.
+ if self._append_iteration_suffix:
+ payload += "%x" % self._iteration
+
+ # Keep track of the iteration.
+ self._iteration += 1
+
+ # Now that we've given the query packet, flip the mode to receive/match.
+ self._is_send_to_remote = False
+
+ # Return the result, converted to packet form.
+ return gdbremote_packet_encode_string(payload)
+
+ def is_consumed(self):
+ return self._end_matched
+
+ def assert_match(self, asserter, actual_packet, context=None):
+ # This only makes sense for matching lines coming from the remote debug monitor.
+ if self.is_send_to_remote():
+ raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.")
+
+ if self._end_matched:
+ raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
+
+ # Set up a context as needed.
+ if not context:
+ context = {}
+
+ # Check if the packet matches the end condition.
+ match = self._end_regex.match(actual_packet)
+ if match:
+ # We're done iterating.
+ self._end_matched = True
+ return context
+
+ # Not done iterating - save the packet.
+ context[self._save_key] = context.get(self._save_key, [])
+ context[self._save_key].append(actual_packet)
+
+ # Check for a runaway response cycle.
+ if len(context[self._save_key]) >= self._runaway_response_count:
+ raise Exception("runaway query/response cycle detected: %d responses captured so far. Last response: %s" %
+ (len(context[self._save_key]), context[self._save_key][-1]))
+
+ # Flip the mode to send for generating the query.
+ self._is_send_to_remote = True
+ return context
+
+class MatchRemoteOutputEntry(GdbRemoteEntryBase):
+ """Waits for output from the debug monitor to match a regex or time out.
+
+ This entry type tries to match each time new gdb remote output is accumulated
+ using a provided regex. If the output does not match the regex within the
+ given timeframe, the command fails the playback session. If the regex does
+ match, any capture fields are recorded in the context.
+
+ Settings accepted from params:
+
+ regex: required. Specifies a compiled regex object that must either succeed
+ with re.match or re.search (see regex_mode below) within the given timeout
+ (see timeout_seconds below) or cause the playback to fail.
+
+ regex_mode: optional. Available values: "match" or "search". If "match", the entire
+ stub output as collected so far must match the regex. If search, then the regex
+ must match starting somewhere within the output text accumulated thus far.
+ Default: "match" (i.e. the regex must match the entirety of the accumulated output
+ buffer, so unexpected text will generally fail the match).
+
+ capture: optional. If specified, is a dictionary of regex match group indices (should start
+ with 1) to variable names that will store the capture group indicated by the
+ index. For example, {1:"thread_id"} will store capture group 1's content in the
+ context dictionary where "thread_id" is the key and the match group value is
+ the value. The value stored off can be used later in a expect_captures expression.
+ This arg only makes sense when regex is specified.
+ """
+ def __init__(self, regex=None, regex_mode="match", capture=None):
+ self._regex = regex
+ self._regex_mode = regex_mode
+ self._capture = capture
+ self._matched = False
+
+ if not self._regex:
+ raise Exception("regex cannot be None")
+
+ if not self._regex_mode in ["match", "search"]:
+ raise Exception("unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(self._regex_mode))
+
+ def is_output_matcher(self):
+ return True
+
+ def is_send_to_remote(self):
+ # This is always a "wait for remote" command.
+ return False
+
+ def is_consumed(self):
+ return self._matched
+
+ def assert_match(self, asserter, accumulated_output, context):
+ # Validate args.
+ if not accumulated_output:
+ raise Exception("accumulated_output cannot be none")
+ if not context:
+ raise Exception("context cannot be none")
+
+ # Validate that we haven't already matched.
+ if self._matched:
+ raise Exception("invalid state - already matched, attempting to match again")
+
+ # If we don't have any content yet, we don't match.
+ if len(accumulated_output) < 1:
+ return context
+
+ # Check if we match
+ if self._regex_mode == "match":
+ match = self._regex.match(accumulated_output)
+ elif self._regex_mode == "search":
+ match = self._regex.search(accumulated_output)
+ else:
+ raise Exception("Unexpected regex mode: {}".format(self._regex_mode))
+
+ # If we don't match, wait to try again after next $O content, or time out.
+ if not match:
+ # print("re pattern \"{}\" did not match against \"{}\"".format(self._regex.pattern, accumulated_output))
+ return context
+
+ # We do match.
+ self._matched = True
+ # print("re pattern \"{}\" matched against \"{}\"".format(self._regex.pattern, accumulated_output))
+
+ # Collect up any captures into the context.
+ if self._capture:
+ # Handle captures.
+ for group_index, var_name in list(self._capture.items()):
+ capture_text = match.group(group_index)
+ if not capture_text:
+ raise Exception("No content for group index {}".format(group_index))
+ context[var_name] = capture_text
+
+ return context
+
+
+class GdbRemoteTestSequence(object):
+
+ _LOG_LINE_REGEX = re.compile(r'^.*(read|send)\s+packet:\s+(.+)$')
+
+ def __init__(self, logger):
+ self.entries = []
+ self.logger = logger
+
+ def add_log_lines(self, log_lines, remote_input_is_read):
+ for line in log_lines:
+ if type(line) == str:
+ # Handle log line import
+ # if self.logger:
+ # self.logger.debug("processing log line: {}".format(line))
+ match = self._LOG_LINE_REGEX.match(line)
+ if match:
+ playback_packet = match.group(2)
+ direction = match.group(1)
+ if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
+ # Handle as something to send to the remote debug monitor.
+ # if self.logger:
+ # self.logger.info("processed packet to send to remote: {}".format(playback_packet))
+ self.entries.append(GdbRemoteEntry(is_send_to_remote=True, exact_payload=playback_packet))
+ else:
+ # Log line represents content to be expected from the remote debug monitor.
+ # if self.logger:
+ # self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet))
+ self.entries.append(GdbRemoteEntry(is_send_to_remote=False,exact_payload=playback_packet))
+ else:
+ raise Exception("failed to interpret log line: {}".format(line))
+ elif type(line) == dict:
+ entry_type = line.get("type", "regex_capture")
+ if entry_type == "regex_capture":
+ # Handle more explicit control over details via dictionary.
+ direction = line.get("direction", None)
+ regex = line.get("regex", None)
+ capture = line.get("capture", None)
+ expect_captures = line.get("expect_captures", None)
+
+ # Compile the regex.
+ if regex and (type(regex) == str):
+ regex = re.compile(regex)
+
+ if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
+ # Handle as something to send to the remote debug monitor.
+ # if self.logger:
+ # self.logger.info("processed dict sequence to send to remote")
+ self.entries.append(GdbRemoteEntry(is_send_to_remote=True, regex=regex, capture=capture, expect_captures=expect_captures))
+ else:
+ # Log line represents content to be expected from the remote debug monitor.
+ # if self.logger:
+ # self.logger.info("processed dict sequence to match receiving from remote")
+ self.entries.append(GdbRemoteEntry(is_send_to_remote=False, regex=regex, capture=capture, expect_captures=expect_captures))
+ elif entry_type == "multi_response":
+ self.entries.append(MultiResponseGdbRemoteEntry(line))
+ elif entry_type == "output_match":
+
+ regex = line.get("regex", None)
+ # Compile the regex.
+ if regex and (type(regex) == str):
+ regex = re.compile(regex)
+
+ regex_mode = line.get("regex_mode", "match")
+ capture = line.get("capture", None)
+ self.entries.append(MatchRemoteOutputEntry(regex=regex, regex_mode=regex_mode, capture=capture))
+ else:
+ raise Exception("unknown entry type \"%s\"" % entry_type)
+
+def process_is_running(pid, unknown_value=True):
+ """If possible, validate that the given pid represents a running process on the local system.
+
+ Args:
+
+ pid: an OS-specific representation of a process id. Should be an integral value.
+
+ unknown_value: value used when we cannot determine how to check running local
+ processes on the OS.
+
+ Returns:
+
+ If we can figure out how to check running process ids on the given OS:
+ return True if the process is running, or False otherwise.
+
+ If we don't know how to check running process ids on the given OS:
+ return the value provided by the unknown_value arg.
+ """
+ if not isinstance(pid, six.integer_types):
+ raise Exception("pid must be an integral type (actual type: %s)" % str(type(pid)))
+
+ process_ids = []
+
+ if lldb.remote_platform:
+ # Don't know how to get list of running process IDs on a remote
+ # platform
+ return unknown_value
+ elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']:
+ # Build the list of running process ids
+ output = subprocess.check_output("ps ax | awk '{ print $1; }'", shell=True)
+ text_process_ids = output.split('\n')[1:]
+ # Convert text pids to ints
+ process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != '']
+ # elif {your_platform_here}:
+ # fill in process_ids as a list of int type process IDs running on
+ # the local system.
+ else:
+ # Don't know how to get list of running process IDs on this
+ # OS, so return the "don't know" value.
+ return unknown_value
+
+ # Check if the pid is in the process_ids
+ return pid in process_ids
+
+if __name__ == '__main__':
+ EXE_PATH = get_lldb_server_exe()
+ if EXE_PATH:
+ print("lldb-server path detected: {}".format(EXE_PATH))
+ else:
+ print("lldb-server could not be found")
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp
new file mode 100644
index 0000000..c65b225
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp
@@ -0,0 +1,404 @@
+#include <cstdlib>
+#include <cstring>
+#include <errno.h>
+#include <inttypes.h>
+#include <memory>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <vector>
+
+#if defined(__APPLE__)
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int pthread_threadid_np(pthread_t,__uint64_t*);
+#elif defined(__linux__)
+#include <sys/syscall.h>
+#endif
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+#endif
+
+static const char *const RETVAL_PREFIX = "retval:";
+static const char *const SLEEP_PREFIX = "sleep:";
+static const char *const STDERR_PREFIX = "stderr:";
+static const char *const SET_MESSAGE_PREFIX = "set-message:";
+static const char *const PRINT_MESSAGE_COMMAND = "print-message:";
+static const char *const GET_DATA_ADDRESS_PREFIX = "get-data-address-hex:";
+static const char *const GET_STACK_ADDRESS_COMMAND = "get-stack-address-hex:";
+static const char *const GET_HEAP_ADDRESS_COMMAND = "get-heap-address-hex:";
+
+static const char *const GET_CODE_ADDRESS_PREFIX = "get-code-address-hex:";
+static const char *const CALL_FUNCTION_PREFIX = "call-function:";
+
+static const char *const THREAD_PREFIX = "thread:";
+static const char *const THREAD_COMMAND_NEW = "new";
+static const char *const THREAD_COMMAND_PRINT_IDS = "print-ids";
+static const char *const THREAD_COMMAND_SEGFAULT = "segfault";
+
+static bool g_print_thread_ids = false;
+static pthread_mutex_t g_print_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool g_threads_do_segfault = false;
+
+static pthread_mutex_t g_jump_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static jmp_buf g_jump_buffer;
+static bool g_is_segfaulting = false;
+
+static char g_message[256];
+
+static volatile char g_c1 = '0';
+static volatile char g_c2 = '1';
+
+static void
+print_thread_id ()
+{
+ // Put in the right magic here for your platform to spit out the thread id (tid) that debugserver/lldb-gdbserver would see as a TID.
+ // Otherwise, let the else clause print out the unsupported text so that the unit test knows to skip verifying thread ids.
+#if defined(__APPLE__)
+ __uint64_t tid = 0;
+ pthread_threadid_np(pthread_self(), &tid);
+ printf ("%" PRIx64, tid);
+#elif defined (__linux__)
+ // This is a call to gettid() via syscall.
+ printf ("%" PRIx64, static_cast<uint64_t> (syscall (__NR_gettid)));
+#else
+ printf("{no-tid-support}");
+#endif
+}
+
+static void
+signal_handler (int signo)
+{
+ const char *signal_name = nullptr;
+ switch (signo)
+ {
+ case SIGUSR1: signal_name = "SIGUSR1"; break;
+ case SIGSEGV: signal_name = "SIGSEGV"; break;
+ default: signal_name = nullptr;
+ }
+
+ // Print notice that we received the signal on a given thread.
+ pthread_mutex_lock (&g_print_mutex);
+ if (signal_name)
+ printf ("received %s on thread id: ", signal_name);
+ else
+ printf ("received signo %d (%s) on thread id: ", signo, strsignal (signo));
+ print_thread_id ();
+ printf ("\n");
+ pthread_mutex_unlock (&g_print_mutex);
+
+ // Reset the signal handler if we're one of the expected signal handlers.
+ switch (signo)
+ {
+ case SIGSEGV:
+ if (g_is_segfaulting)
+ {
+ // Fix up the pointer we're writing to. This needs to happen if nothing intercepts the SIGSEGV
+ // (i.e. if somebody runs this from the command line).
+ longjmp(g_jump_buffer, 1);
+ }
+ break;
+ case SIGUSR1:
+ if (g_is_segfaulting)
+ {
+ // Fix up the pointer we're writing to. This is used to test gdb remote signal delivery.
+ // A SIGSEGV will be raised when the thread is created, switched out for a SIGUSR1, and
+ // then this code still needs to fix the seg fault.
+ // (i.e. if somebody runs this from the command line).
+ longjmp(g_jump_buffer, 1);
+ }
+ break;
+ }
+
+ // Reset the signal handler.
+ sig_t sig_result = signal (signo, signal_handler);
+ if (sig_result == SIG_ERR)
+ {
+ fprintf(stderr, "failed to set signal handler: errno=%d\n", errno);
+ exit (1);
+ }
+}
+
+static void
+swap_chars ()
+{
+ g_c1 = '1';
+ g_c2 = '0';
+
+ g_c1 = '0';
+ g_c2 = '1';
+}
+
+static void
+hello ()
+{
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("hello, world\n");
+ pthread_mutex_unlock (&g_print_mutex);
+}
+
+static void*
+thread_func (void *arg)
+{
+ static pthread_mutex_t s_thread_index_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static int s_thread_index = 1;
+
+ pthread_mutex_lock (&s_thread_index_mutex);
+ const int this_thread_index = s_thread_index++;
+ pthread_mutex_unlock (&s_thread_index_mutex);
+
+ if (g_print_thread_ids)
+ {
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("thread %d id: ", this_thread_index);
+ print_thread_id ();
+ printf ("\n");
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+
+ if (g_threads_do_segfault)
+ {
+ // Sleep for a number of seconds based on the thread index.
+ // TODO add ability to send commands to test exe so we can
+ // handle timing more precisely. This is clunky. All we're
+ // trying to do is add predictability as to the timing of
+ // signal generation by created threads.
+ int sleep_seconds = 2 * (this_thread_index - 1);
+ while (sleep_seconds > 0)
+ sleep_seconds = sleep(sleep_seconds);
+
+ // Test creating a SEGV.
+ pthread_mutex_lock (&g_jump_buffer_mutex);
+ g_is_segfaulting = true;
+ int *bad_p = nullptr;
+ if (setjmp(g_jump_buffer) == 0)
+ {
+ // Force a seg fault signal on this thread.
+ *bad_p = 0;
+ }
+ else
+ {
+ // Tell the system we're no longer seg faulting.
+ // Used by the SIGUSR1 signal handler that we inject
+ // in place of the SIGSEGV so it only tries to
+ // recover from the SIGSEGV if this seg fault code
+ // was in play.
+ g_is_segfaulting = false;
+ }
+ pthread_mutex_unlock (&g_jump_buffer_mutex);
+
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("thread ");
+ print_thread_id ();
+ printf (": past SIGSEGV\n");
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+
+ int sleep_seconds_remaining = 60;
+ while (sleep_seconds_remaining > 0)
+ {
+ sleep_seconds_remaining = sleep (sleep_seconds_remaining);
+ }
+
+ return nullptr;
+}
+
+int main (int argc, char **argv)
+{
+#if defined(__linux__)
+ // Immediately enable any ptracer so that we can allow the stub attach
+ // operation to succeed. Some Linux kernels are locked down so that
+ // only an ancestor can be a ptracer of a process. This disables that
+ // restriction. Without it, attach-related stub tests will fail.
+#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
+ const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
+ static_cast<void> (prctl_result);
+#endif
+#endif
+
+ std::vector<pthread_t> threads;
+ std::unique_ptr<uint8_t[]> heap_array_up;
+ int return_value = 0;
+
+ // Set the signal handler.
+ sig_t sig_result = signal (SIGALRM, signal_handler);
+ if (sig_result == SIG_ERR)
+ {
+ fprintf(stderr, "failed to set SIGALRM signal handler: errno=%d\n", errno);
+ exit (1);
+ }
+
+ sig_result = signal (SIGUSR1, signal_handler);
+ if (sig_result == SIG_ERR)
+ {
+ fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
+ exit (1);
+ }
+
+ sig_result = signal (SIGSEGV, signal_handler);
+ if (sig_result == SIG_ERR)
+ {
+ fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
+ exit (1);
+ }
+
+ // Process command line args.
+ for (int i = 1; i < argc; ++i)
+ {
+ if (std::strstr (argv[i], STDERR_PREFIX))
+ {
+ // Treat remainder as text to go to stderr.
+ fprintf (stderr, "%s\n", (argv[i] + strlen (STDERR_PREFIX)));
+ }
+ else if (std::strstr (argv[i], RETVAL_PREFIX))
+ {
+ // Treat as the return value for the program.
+ return_value = std::atoi (argv[i] + strlen (RETVAL_PREFIX));
+ }
+ else if (std::strstr (argv[i], SLEEP_PREFIX))
+ {
+ // Treat as the amount of time to have this process sleep (in seconds).
+ int sleep_seconds_remaining = std::atoi (argv[i] + strlen (SLEEP_PREFIX));
+
+ // Loop around, sleeping until all sleep time is used up. Note that
+ // signals will cause sleep to end early with the number of seconds remaining.
+ for (int i = 0; sleep_seconds_remaining > 0; ++i)
+ {
+ sleep_seconds_remaining = sleep (sleep_seconds_remaining);
+ // std::cout << "sleep result (call " << i << "): " << sleep_seconds_remaining << std::endl;
+ }
+ }
+ else if (std::strstr (argv[i], SET_MESSAGE_PREFIX))
+ {
+ // Copy the contents after "set-message:" to the g_message buffer.
+ // Used for reading inferior memory and verifying contents match expectations.
+ strncpy (g_message, argv[i] + strlen (SET_MESSAGE_PREFIX), sizeof (g_message));
+
+ // Ensure we're null terminated.
+ g_message[sizeof (g_message) - 1] = '\0';
+
+ }
+ else if (std::strstr (argv[i], PRINT_MESSAGE_COMMAND))
+ {
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("message: %s\n", g_message);
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i], GET_DATA_ADDRESS_PREFIX))
+ {
+ volatile void *data_p = nullptr;
+
+ if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_message"))
+ data_p = &g_message[0];
+ else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c1"))
+ data_p = &g_c1;
+ else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c2"))
+ data_p = &g_c2;
+
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("data address: %p\n", data_p);
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i], GET_HEAP_ADDRESS_COMMAND))
+ {
+ // Create a byte array if not already present.
+ if (!heap_array_up)
+ heap_array_up.reset (new uint8_t[32]);
+
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("heap address: %p\n", heap_array_up.get ());
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i], GET_STACK_ADDRESS_COMMAND))
+ {
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("stack address: %p\n", &return_value);
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i], GET_CODE_ADDRESS_PREFIX))
+ {
+ void (*func_p)() = nullptr;
+
+ if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "hello"))
+ func_p = hello;
+ else if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "swap_chars"))
+ func_p = swap_chars;
+
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("code address: %p\n", func_p);
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i], CALL_FUNCTION_PREFIX))
+ {
+ // Defaut to providing the address of main.
+ if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "hello") == 0)
+ hello();
+ else if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "swap_chars") == 0)
+ swap_chars();
+ else
+ {
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("unknown function: %s\n", argv[i] + strlen (CALL_FUNCTION_PREFIX));
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ }
+ else if (std::strstr (argv[i], THREAD_PREFIX))
+ {
+ // Check if we're creating a new thread.
+ if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_NEW))
+ {
+ // Create a new thread.
+ pthread_t new_thread;
+ const int err = ::pthread_create (&new_thread, nullptr, thread_func, nullptr);
+ if (err)
+ {
+ fprintf (stderr, "pthread_create() failed with error code %d\n", err);
+ exit (err);
+ }
+ threads.push_back (new_thread);
+ }
+ else if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_PRINT_IDS))
+ {
+ // Turn on thread id announcing.
+ g_print_thread_ids = true;
+
+ // And announce us.
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("thread 0 id: ");
+ print_thread_id ();
+ printf ("\n");
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ else if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_SEGFAULT))
+ {
+ g_threads_do_segfault = true;
+ }
+ else
+ {
+ // At this point we don't do anything else with threads.
+ // Later use thread index and send command to thread.
+ }
+ }
+ else
+ {
+ // Treat the argument as text for stdout.
+ printf("%s\n", argv[i]);
+ }
+ }
+
+ // If we launched any threads, join them
+ for (std::vector<pthread_t>::iterator it = threads.begin (); it != threads.end (); ++it)
+ {
+ void *thread_retval = nullptr;
+ const int err = ::pthread_join (*it, &thread_retval);
+ if (err != 0)
+ fprintf (stderr, "pthread_join() failed with error code %d\n", err);
+ }
+
+ return return_value;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
new file mode 100644
index 0000000..b50a030
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
@@ -0,0 +1,56 @@
+from __future__ import print_function
+
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class TestPlatformProcessConnect(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ @llgs_test
+ @no_debug_info_test
+ @skipIf(remote=False)
+ @expectedFailureAll(hostoslist=["windows"], triple='.*-android')
+ def test_platform_process_connect(self):
+ self.build()
+ self.init_llgs_test(False)
+
+ working_dir = lldb.remote_platform.GetWorkingDirectory()
+ err = lldb.remote_platform.Put(lldb.SBFileSpec(os.path.join(os.getcwd(), "a.out")),
+ lldb.SBFileSpec(os.path.join(working_dir, "a.out")))
+ if err.Fail():
+ raise RuntimeError("Unable copy '%s' to '%s'.\n>>> %s" % (f, wd, err.GetCString()))
+
+ port_file = "%s/port" % working_dir
+ commandline_args = ["platform", "--listen", "*:0", "--socket-file", port_file, "--", "%s/a.out" % working_dir, "foo"]
+ self.spawnSubprocess(self.debug_monitor_exe, commandline_args, install_remote=False)
+ self.addTearDownHook(self.cleanupSubprocesses)
+ new_port = self.run_shell_cmd("while [ ! -f %s ]; do sleep 0.25; done && cat %s" % (port_file, port_file))
+
+ new_debugger = lldb.SBDebugger.Create()
+ new_debugger.SetAsync(False)
+ def del_debugger(new_debugger=new_debugger):
+ del new_debugger
+ self.addTearDownHook(del_debugger)
+
+ new_platform = lldb.SBPlatform(lldb.remote_platform.GetName())
+ new_debugger.SetSelectedPlatform(new_platform)
+ new_interpreter = new_debugger.GetCommandInterpreter()
+
+ m = re.search("(.*):[0-9]+", configuration.lldb_platform_url)
+ command = "platform connect %s:%s" % (m.group(1), new_port)
+ result = lldb.SBCommandReturnObject()
+ new_interpreter.HandleCommand(command, result)
+ self.assertTrue(result.Succeeded(), "platform process connect failed: %s" % result.GetOutput())
+
+ target = new_debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ thread = process.GetThreadAtIndex(0)
+
+ breakpoint = target.BreakpointCreateByName("main")
+ process.Continue()
+
+ frame = thread.GetFrameAtIndex(0)
+ self.assertEqual(frame.GetFunction().GetName(), "main")
+ self.assertEqual(frame.FindVariable("argc").GetValueAsSigned(), 2)
+ process.Continue()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp
new file mode 100644
index 0000000..70ae509
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp
@@ -0,0 +1,7 @@
+#include <cstdio>
+
+int main (int argc, char **argv)
+{
+ printf("argc: %d\n", argc);
+ return argv[0][0];
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/socket_packet_pump.py b/packages/Python/lldbsuite/test/tools/lldb-server/socket_packet_pump.py
new file mode 100644
index 0000000..795a8c6
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/socket_packet_pump.py
@@ -0,0 +1,187 @@
+
+from __future__ import print_function
+
+
+
+import re
+import select
+import threading
+import traceback
+import codecs
+
+from six.moves import queue
+
+def _handle_output_packet_string(packet_contents):
+ if (not packet_contents) or (len(packet_contents) < 1):
+ return None
+ elif packet_contents[0] != "O":
+ return None
+ elif packet_contents == "OK":
+ return None
+ else:
+ return packet_contents[1:].decode("hex")
+
+def _dump_queue(the_queue):
+ while not the_queue.empty():
+ print(codecs.encode(the_queue.get(True), "string_escape"))
+ print("\n")
+
+class SocketPacketPump(object):
+ """A threaded packet reader that partitions packets into two streams.
+
+ All incoming $O packet content is accumulated with the current accumulation
+ state put into the OutputQueue.
+
+ All other incoming packets are placed in the packet queue.
+
+ A select thread can be started and stopped, and runs to place packet
+ content into the two queues.
+ """
+
+ _GDB_REMOTE_PACKET_REGEX = re.compile(r'^\$([^\#]*)#[0-9a-fA-F]{2}')
+
+ def __init__(self, pump_socket, logger=None):
+ if not pump_socket:
+ raise Exception("pump_socket cannot be None")
+
+ self._output_queue = queue.Queue()
+ self._packet_queue = queue.Queue()
+ self._thread = None
+ self._stop_thread = False
+ self._socket = pump_socket
+ self._logger = logger
+ self._receive_buffer = ""
+ self._accumulated_output = ""
+
+ def __enter__(self):
+ """Support the python 'with' statement.
+
+ Start the pump thread."""
+ self.start_pump_thread()
+ return self
+
+ def __exit__(self, exit_type, value, the_traceback):
+ """Support the python 'with' statement.
+
+ Shut down the pump thread."""
+ self.stop_pump_thread()
+
+ # Warn if there is any content left in any of the queues.
+ # That would represent unmatched packets.
+ if not self.output_queue().empty():
+ print("warning: output queue entries still exist:")
+ _dump_queue(self.output_queue())
+ print("from here:")
+ traceback.print_stack()
+
+ if not self.packet_queue().empty():
+ print("warning: packet queue entries still exist:")
+ _dump_queue(self.packet_queue())
+ print("from here:")
+ traceback.print_stack()
+
+ def start_pump_thread(self):
+ if self._thread:
+ raise Exception("pump thread is already running")
+ self._stop_thread = False
+ self._thread = threading.Thread(target=self._run_method)
+ self._thread.start()
+
+ def stop_pump_thread(self):
+ self._stop_thread = True
+ if self._thread:
+ self._thread.join()
+
+ def output_queue(self):
+ return self._output_queue
+
+ def packet_queue(self):
+ return self._packet_queue
+
+ def _process_new_bytes(self, new_bytes):
+ if not new_bytes:
+ return
+ if len(new_bytes) < 1:
+ return
+
+ # Add new bytes to our accumulated unprocessed packet bytes.
+ self._receive_buffer += new_bytes
+
+ # Parse fully-formed packets into individual packets.
+ has_more = len(self._receive_buffer) > 0
+ while has_more:
+ if len(self._receive_buffer) <= 0:
+ has_more = False
+ # handle '+' ack
+ elif self._receive_buffer[0] == "+":
+ self._packet_queue.put("+")
+ self._receive_buffer = self._receive_buffer[1:]
+ if self._logger:
+ self._logger.debug(
+ "parsed packet from stub: +\n" +
+ "new receive_buffer: {}".format(
+ self._receive_buffer))
+ else:
+ packet_match = self._GDB_REMOTE_PACKET_REGEX.match(
+ self._receive_buffer)
+ if packet_match:
+ # Our receive buffer matches a packet at the
+ # start of the receive buffer.
+ new_output_content = _handle_output_packet_string(
+ packet_match.group(1))
+ if new_output_content:
+ # This was an $O packet with new content.
+ self._accumulated_output += new_output_content
+ self._output_queue.put(self._accumulated_output)
+ else:
+ # Any packet other than $O.
+ self._packet_queue.put(packet_match.group(0))
+
+ # Remove the parsed packet from the receive
+ # buffer.
+ self._receive_buffer = self._receive_buffer[
+ len(packet_match.group(0)):]
+ if self._logger:
+ self._logger.debug(
+ "parsed packet from stub: " +
+ packet_match.group(0))
+ self._logger.debug(
+ "new receive_buffer: " +
+ self._receive_buffer)
+ else:
+ # We don't have enough in the receive bufferto make a full
+ # packet. Stop trying until we read more.
+ has_more = False
+
+ def _run_method(self):
+ self._receive_buffer = ""
+ self._accumulated_output = ""
+
+ if self._logger:
+ self._logger.info("socket pump starting")
+
+ # Keep looping around until we're asked to stop the thread.
+ while not self._stop_thread:
+ can_read, _, _ = select.select([self._socket], [], [], 0)
+ if can_read and self._socket in can_read:
+ try:
+ new_bytes = self._socket.recv(4096)
+ if self._logger and new_bytes and len(new_bytes) > 0:
+ self._logger.debug(
+ "pump received bytes: {}".format(new_bytes))
+ except:
+ # Likely a closed socket. Done with the pump thread.
+ if self._logger:
+ self._logger.debug(
+ "socket read failed, stopping pump read thread")
+ break
+ self._process_new_bytes(new_bytes)
+
+ if self._logger:
+ self._logger.info("socket pump exiting")
+
+ def get_accumulated_output(self):
+ return self._accumulated_output
+
+ def get_receive_buffer(self):
+ return self._receive_buffer
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/test/test_lldbgdbserverutils.py b/packages/Python/lldbsuite/test/tools/lldb-server/test/test_lldbgdbserverutils.py
new file mode 100644
index 0000000..8b3b6b6
--- /dev/null
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/test/test_lldbgdbserverutils.py
@@ -0,0 +1,49 @@
+from __future__ import print_function
+
+
+
+import unittest2
+import os.path
+import re
+import sys
+
+from lldbgdbserverutils import *
+
+
+class TestLldbGdbServerUtils(unittest2.TestCase):
+ def test_entry_exact_payload_match(self):
+ entry = GdbRemoteEntry(is_send_to_remote=False, exact_payload="$OK#9a")
+ entry.assert_match(self, "$OK#9a")
+
+ def test_entry_exact_payload_match_ignores_checksum(self):
+ entry = GdbRemoteEntry(is_send_to_remote=False, exact_payload="$OK#9a")
+ entry.assert_match(self, "$OK#00")
+
+ def test_entry_creates_context(self):
+ entry = GdbRemoteEntry(is_send_to_remote=False, exact_payload="$OK#9a")
+ context = entry.assert_match(self, "$OK#9a")
+ self.assertIsNotNone(context)
+
+ def test_entry_regex_matches(self):
+ entry = GdbRemoteEntry(is_send_to_remote=False, regex=re.compile(r"^\$QC([0-9a-fA-F]+)#"), capture={ 1:"thread_id" })
+ context = entry.assert_match(self, "$QC980#00")
+
+ def test_entry_regex_saves_match(self):
+ entry = GdbRemoteEntry(is_send_to_remote=False, regex=re.compile(r"^\$QC([0-9a-fA-F]+)#"), capture={ 1:"thread_id" })
+ context = entry.assert_match(self, "$QC980#00")
+ self.assertEqual(context["thread_id"], "980")
+
+ def test_entry_regex_expect_captures_success(self):
+ context = { "thread_id":"980" }
+ entry = GdbRemoteEntry(is_send_to_remote=False, regex=re.compile(r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+)"), expect_captures={ 2:"thread_id" })
+ entry.assert_match(self, "$T11thread:980;", context=context)
+
+ def test_entry_regex_expect_captures_raises_on_fail(self):
+ context = { "thread_id":"980" }
+ entry = GdbRemoteEntry(is_send_to_remote=False, regex=re.compile(r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+)"), expect_captures={ 2:"thread_id" })
+ try:
+ entry.assert_match(self, "$T11thread:970;", context=context)
+ self.fail()
+ except AssertionError:
+ # okay
+ return None
OpenPOWER on IntegriCloud