forked from OSchip/llvm-project
[lldb][NFC] Cleanup mentions and code related to lldb-mi
Summary: lldb-mi has been removed, but there are still a bunch of references in the code base. This patch removes all of them. Reviewers: JDevlieghere, jfb Reviewed By: JDevlieghere Subscribers: dexonsmith, ki.stfu, mgorny, abidh, jfb, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D64992 llvm-svn: 366590
This commit is contained in:
parent
0054230181
commit
b45853f173
|
@ -106,10 +106,6 @@ if(LLDB_INCLUDE_TESTS)
|
||||||
list(APPEND LLDB_TEST_DEPS lldb-server)
|
list(APPEND LLDB_TEST_DEPS lldb-server)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET lldb-mi)
|
|
||||||
list(APPEND LLDB_TEST_DEPS lldb-mi)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TARGET lldb-vscode)
|
if(TARGET lldb-vscode)
|
||||||
list(APPEND LLDB_TEST_DEPS lldb-vscode)
|
list(APPEND LLDB_TEST_DEPS lldb-vscode)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -21,10 +21,6 @@ D: Watchpoints, Trampolines, Target, Command Interpreter, C++ / Objective-C Lang
|
||||||
D: Expression evaluator, IR interpreter, Clang integration
|
D: Expression evaluator, IR interpreter, Clang integration
|
||||||
D: Data Formatters
|
D: Data Formatters
|
||||||
|
|
||||||
N: Ilia K
|
|
||||||
E: ki.stfu@gmail.com
|
|
||||||
D: lldb-mi
|
|
||||||
|
|
||||||
N: Ed Maste
|
N: Ed Maste
|
||||||
E: emaste@freebsd.org
|
E: emaste@freebsd.org
|
||||||
D: FreeBSD
|
D: FreeBSD
|
||||||
|
@ -34,10 +30,6 @@ E: jmolenda@apple.com
|
||||||
D: ABI, Disassembler, Unwinding, iOS, debugserver, Platform, ObjectFile, SymbolFile,
|
D: ABI, Disassembler, Unwinding, iOS, debugserver, Platform, ObjectFile, SymbolFile,
|
||||||
D: SymbolVendor, DWARF, gdb-remote
|
D: SymbolVendor, DWARF, gdb-remote
|
||||||
|
|
||||||
N: Hafiz Abid Qadeer
|
|
||||||
E: abidh.haq@gmail.com
|
|
||||||
D: lldb-mi
|
|
||||||
|
|
||||||
N: Kamil Rytarowski
|
N: Kamil Rytarowski
|
||||||
E: kamil@netbsd.org
|
E: kamil@netbsd.org
|
||||||
D: NetBSD
|
D: NetBSD
|
||||||
|
|
|
@ -16,11 +16,6 @@ def use_lldb_substitutions(config):
|
||||||
|
|
||||||
dsname = 'debugserver' if platform.system() in ['Darwin'] else 'lldb-server'
|
dsname = 'debugserver' if platform.system() in ['Darwin'] else 'lldb-server'
|
||||||
dsargs = [] if platform.system() in ['Darwin'] else ['gdbserver']
|
dsargs = [] if platform.system() in ['Darwin'] else ['gdbserver']
|
||||||
lldbmi = ToolSubst('%lldbmi',
|
|
||||||
command=FindTool('lldb-mi'),
|
|
||||||
extra_args=['--synchronous'],
|
|
||||||
unresolved='ignore')
|
|
||||||
|
|
||||||
|
|
||||||
build_script = os.path.dirname(__file__)
|
build_script = os.path.dirname(__file__)
|
||||||
build_script = os.path.join(build_script, 'build.py')
|
build_script = os.path.join(build_script, 'build.py')
|
||||||
|
@ -43,7 +38,6 @@ def use_lldb_substitutions(config):
|
||||||
ToolSubst('%lldb-init',
|
ToolSubst('%lldb-init',
|
||||||
command=FindTool('lldb'),
|
command=FindTool('lldb'),
|
||||||
extra_args=['-S', lldb_init]),
|
extra_args=['-S', lldb_init]),
|
||||||
lldbmi,
|
|
||||||
ToolSubst('%debugserver',
|
ToolSubst('%debugserver',
|
||||||
command=FindTool(dsname),
|
command=FindTool(dsname),
|
||||||
extra_args=dsargs,
|
extra_args=dsargs,
|
||||||
|
@ -61,9 +55,6 @@ def use_lldb_substitutions(config):
|
||||||
|
|
||||||
llvm_config.add_tool_substitutions(primary_tools,
|
llvm_config.add_tool_substitutions(primary_tools,
|
||||||
[config.lldb_tools_dir])
|
[config.lldb_tools_dir])
|
||||||
# lldb-mi always fails without Python support
|
|
||||||
if lldbmi.was_resolved and not config.lldb_disable_python:
|
|
||||||
config.available_features.add('lldb-mi')
|
|
||||||
|
|
||||||
def _use_msvc_substitutions(config):
|
def _use_msvc_substitutions(config):
|
||||||
# If running from a Visual Studio Command prompt (e.g. vcvars), this will
|
# If running from a Visual Studio Command prompt (e.g. vcvars), this will
|
||||||
|
|
|
@ -693,16 +693,11 @@ def setupSysPath():
|
||||||
os.environ["LLDB_SRC"] = lldbsuite.lldb_root
|
os.environ["LLDB_SRC"] = lldbsuite.lldb_root
|
||||||
|
|
||||||
pluginPath = os.path.join(scriptPath, 'plugins')
|
pluginPath = os.path.join(scriptPath, 'plugins')
|
||||||
toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi')
|
|
||||||
toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
|
toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
|
||||||
toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
|
toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
|
||||||
|
|
||||||
# Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the
|
# Insert script dir, plugin dir and lldb-server dir to the sys.path.
|
||||||
# sys.path.
|
|
||||||
sys.path.insert(0, pluginPath)
|
sys.path.insert(0, pluginPath)
|
||||||
# Adding test/tools/lldb-mi to the path makes it easy
|
|
||||||
sys.path.insert(0, toolsLLDBMIPath)
|
|
||||||
# to "import lldbmi_testcase" from the MI tests
|
|
||||||
# Adding test/tools/lldb-vscode to the path makes it easy to
|
# Adding test/tools/lldb-vscode to the path makes it easy to
|
||||||
# "import lldb_vscode_testcase" from the VSCode tests
|
# "import lldb_vscode_testcase" from the VSCode tests
|
||||||
sys.path.insert(0, toolsLLDBVSCode)
|
sys.path.insert(0, toolsLLDBVSCode)
|
||||||
|
@ -761,19 +756,7 @@ def setupSysPath():
|
||||||
print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
|
print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
|
||||||
os.system('%s -v' % lldbtest_config.lldbExec)
|
os.system('%s -v' % lldbtest_config.lldbExec)
|
||||||
|
|
||||||
# Assume lldb-mi is in same place as lldb
|
|
||||||
# If not found, disable the lldb-mi tests
|
|
||||||
# TODO: Append .exe on Windows
|
|
||||||
# - this will be in a separate commit in case the mi tests fail horribly
|
|
||||||
lldbDir = os.path.dirname(lldbtest_config.lldbExec)
|
lldbDir = os.path.dirname(lldbtest_config.lldbExec)
|
||||||
lldbMiExec = os.path.join(lldbDir, "lldb-mi")
|
|
||||||
if is_exe(lldbMiExec):
|
|
||||||
os.environ["LLDBMI_EXEC"] = lldbMiExec
|
|
||||||
else:
|
|
||||||
if not configuration.shouldSkipBecauseOfCategories(["lldb-mi"]):
|
|
||||||
print(
|
|
||||||
"The 'lldb-mi' executable cannot be located. The lldb-mi tests can not be run as a result.")
|
|
||||||
configuration.skipCategories.append("lldb-mi")
|
|
||||||
|
|
||||||
lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode")
|
lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode")
|
||||||
if is_exe(lldbVSCodeExec):
|
if is_exe(lldbVSCodeExec):
|
||||||
|
|
|
@ -711,11 +711,6 @@ class Base(unittest2.TestCase):
|
||||||
else:
|
else:
|
||||||
self.libcxxPath = None
|
self.libcxxPath = None
|
||||||
|
|
||||||
if "LLDBMI_EXEC" in os.environ:
|
|
||||||
self.lldbMiExec = os.environ["LLDBMI_EXEC"]
|
|
||||||
else:
|
|
||||||
self.lldbMiExec = None
|
|
||||||
|
|
||||||
if "LLDBVSCODE_EXEC" in os.environ:
|
if "LLDBVSCODE_EXEC" in os.environ:
|
||||||
self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"]
|
self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -34,7 +34,6 @@ all_categories = {
|
||||||
'dyntype': 'Tests related to dynamic type support',
|
'dyntype': 'Tests related to dynamic type support',
|
||||||
'stresstest': 'Tests related to stressing lldb limits',
|
'stresstest': 'Tests related to stressing lldb limits',
|
||||||
'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution',
|
'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution',
|
||||||
'lldb-mi': 'lldb-mi tests',
|
|
||||||
'darwin-log': 'Darwin log tests',
|
'darwin-log': 'Darwin log tests',
|
||||||
'watchpoint': 'Watchpoint-related tests',
|
'watchpoint': 'Watchpoint-related tests',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
lldb-mi
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,38 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -environment-cd command.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class MiEnvironmentCdTestCase(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
|
|
||||||
@skipIfDarwin # Disabled while I investigate the failure on buildbot.
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
def test_lldbmi_environment_cd(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' changes working directory for inferior."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
# Load executable
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# cd to a different directory
|
|
||||||
self.runCmd("-environment-cd /tmp")
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# Run to the end
|
|
||||||
self.runCmd("-exec-run")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect("@\"cwd: /tmp\\r\\n\"", exactly=True)
|
|
|
@ -1,60 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi =library-loaded notifications.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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 = self.getBuildArtifact(self.myexe)
|
|
||||||
symbols_path = os.path.join(
|
|
||||||
path + ".dSYM",
|
|
||||||
"Contents",
|
|
||||||
"Resources",
|
|
||||||
"DWARF",
|
|
||||||
"a.out")
|
|
||||||
|
|
||||||
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))])
|
|
|
@ -1,58 +0,0 @@
|
||||||
"""
|
|
||||||
Test that the lldb-mi driver prints prompt properly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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)
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,361 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -break-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import unittest2
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfLinux # llvm.org/pr24717
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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(self.getSourceDir(), "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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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_decl = line_number('main.cpp', '// BP_main_decl')
|
|
||||||
line_in = line_number('main.cpp', '// BP_in_main')
|
|
||||||
self.runCmd("-break-insert -f main.cpp:%d" % line_in)
|
|
||||||
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_in)
|
|
||||||
self.expect(
|
|
||||||
"\^error,msg=\"Command 'break-insert'. Breakpoint location 'main.cpp:%d' not found\"" %
|
|
||||||
line_in)
|
|
||||||
|
|
||||||
# Set target.move-to-nearest-code=on and target.skip-prologue=on and
|
|
||||||
# set BP #3 & #4
|
|
||||||
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_in)
|
|
||||||
self.expect("\^done,bkpt={number=\"3\"")
|
|
||||||
self.runCmd("-break-insert main.cpp:%d" % line_decl)
|
|
||||||
self.expect("\^done,bkpt={number=\"4\"")
|
|
||||||
|
|
||||||
# Set target.skip-prologue=off and set BP #5
|
|
||||||
self.runCmd(
|
|
||||||
"-interpreter-exec console \"settings set target.skip-prologue off\"")
|
|
||||||
self.expect("\^done")
|
|
||||||
self.runCmd("-break-insert main.cpp:%d" % line_decl)
|
|
||||||
self.expect("\^done,bkpt={number=\"5\"")
|
|
||||||
|
|
||||||
# Test that BP #5 is located before BP #4
|
|
||||||
self.runCmd("-exec-run")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect(
|
|
||||||
"\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"5\"")
|
|
||||||
|
|
||||||
# Test that BP #4 is hit
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
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 #6 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 #7 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=\"7\"")
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect(
|
|
||||||
"\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"7\"")
|
|
||||||
|
|
||||||
# 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\"")
|
|
||||||
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfNetBSD
|
|
||||||
def test_lldbmi_break_enable_disable(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' works for enabling / disabling breakpoints."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
self.runCmd("-break-insert main")
|
|
||||||
self.expect(
|
|
||||||
"\^done,bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"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+\",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+\",times=\"0\",original-location=\"main\"}")
|
|
||||||
self.expect(
|
|
||||||
"\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"1\"")
|
|
||||||
|
|
||||||
self.runCmd("-break-insert ns::foo1")
|
|
||||||
self.expect(
|
|
||||||
"\^done,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo1\(\)\"")
|
|
||||||
self.expect(
|
|
||||||
"=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo1\(\)\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",times=\"0\",original-location=\"ns::foo1\"}")
|
|
||||||
|
|
||||||
self.runCmd("-break-insert ns::foo2")
|
|
||||||
self.expect(
|
|
||||||
"\^done,bkpt={number=\"3\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo2\(\)\"")
|
|
||||||
self.expect(
|
|
||||||
"=breakpoint-modified,bkpt={number=\"3\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo2\(\)\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",times=\"0\",original-location=\"ns::foo2\"}")
|
|
||||||
|
|
||||||
# disable the 2nd breakpoint
|
|
||||||
self.runCmd("-break-disable 2")
|
|
||||||
self.expect("\^done")
|
|
||||||
self.expect(
|
|
||||||
"=breakpoint-modified,bkpt={number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"n\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo1\(\)\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",times=\"0\",original-location=\"ns::foo1\"}")
|
|
||||||
|
|
||||||
# disable the 3rd breakpoint and re-enable
|
|
||||||
self.runCmd("-break-disable 3")
|
|
||||||
self.expect("\^done")
|
|
||||||
self.expect(
|
|
||||||
"=breakpoint-modified,bkpt={number=\"3\",type=\"breakpoint\",disp=\"keep\",enabled=\"n\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo2\(\)\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",times=\"0\",original-location=\"ns::foo2\"}")
|
|
||||||
|
|
||||||
self.runCmd("-break-enable 3")
|
|
||||||
self.expect("\^done")
|
|
||||||
self.expect(
|
|
||||||
"=breakpoint-modified,bkpt={number=\"3\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"(?!0xffffffffffffffff)0x[0-9a-f]+\",func=\"ns::foo2\(\)\",file=\"main\.cpp\",fullname=\".+?main\.cpp\",line=\"\d+\",times=\"0\",original-location=\"ns::foo2\"}")
|
|
||||||
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect(
|
|
||||||
"\*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"3\"")
|
|
|
@ -1,29 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace ns
|
|
||||||
{
|
|
||||||
int foo1(void) { printf("In foo1\n"); return 1; }
|
|
||||||
int foo2(void) { printf("In foo2\n"); return 2; }
|
|
||||||
}
|
|
||||||
|
|
||||||
int x;
|
|
||||||
int main(int argc, char const *argv[]) { // BP_main_decl
|
|
||||||
printf("Print a formatted string so that GCC does not optimize this printf call: %s\n", argv[0]);
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
// BP_in_main
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
// This is a long comment with no code inside
|
|
||||||
x = ns::foo1() + ns::foo2();
|
|
||||||
return 0; // BP_return
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,141 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -exec-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class MiExecTestCase(lldbmi_testcase.MiTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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\"")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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
|
|
||||||
# Note that exactly=True is needed to avoid extra escaping for re
|
|
||||||
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\\\"", exactly=True)
|
|
||||||
#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\\\"", exactly=True)
|
|
||||||
#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\\\"", exactly=True)
|
|
||||||
#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\\\\\\\"\\\"", exactly=True)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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\"")
|
|
|
@ -1,32 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,365 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -data-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import unittest2
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class MiDataTestCase(lldbmi_testcase.MiTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@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)
|
|
||||||
|
|
||||||
# Test -data-disassemble with source line information
|
|
||||||
self.runCmd("-data-disassemble -s %#x -e %#x -- 1" % (addr, addr + 0x10))
|
|
||||||
self.expect(
|
|
||||||
'\^done,asm_insns=\[src_and_asm_line={line="\d+",file="main.cpp",'
|
|
||||||
'line_asm_insn=\[{address="0x0*%x",func-name="main",offset="0",size="[1-9]+",inst=".+?"}\],'
|
|
||||||
'fullname="%s"}' %
|
|
||||||
(addr, os.path.abspath("main.cpp")) )
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# The MIPS and PPC64le disassemblers never print stub name
|
|
||||||
if self.isMIPS() or self.isPPC64le():
|
|
||||||
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=\".+?\"}"])
|
|
||||||
else:
|
|
||||||
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\"}"])
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
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=\"1011121300\"}\]" %
|
|
||||||
(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=\"2021222300\"}\]" %
|
|
||||||
(addr, addr + size))
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@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')
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@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=\[\".+?\"\]")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@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]+\"}\]")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@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\}\}\"")
|
|
|
@ -1,60 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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];
|
|
||||||
char g = g_CharArray[0];
|
|
||||||
char s = s_CharArray[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;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,240 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi can interpret CLI commands directly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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\"")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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_list(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' can list targets by 'target list' command."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
# Test that initially there are no targets.
|
|
||||||
self.runCmd("target list")
|
|
||||||
self.expect(r"~\"No targets.\\n\"")
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# Add target.
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
|
|
||||||
# Test that "target list" lists added target.
|
|
||||||
self.runCmd("target list")
|
|
||||||
self.expect(r"~\"Current targets:\\n\* target #0: %s" % self.myexe)
|
|
||||||
|
|
||||||
@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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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\"")
|
|
|
@ -1,227 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -interpreter-exec command.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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\"")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows.
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races.
|
|
||||||
@skipIfDarwin
|
|
||||||
def test_lldbmi_target_list(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' can list targets by 'target list' command."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
# Test that initially there are no targets.
|
|
||||||
self.runCmd("-interpreter-exec console \"target list\"")
|
|
||||||
self.expect(r"~\"No targets.\\n\"")
|
|
||||||
|
|
||||||
# Add target.
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
|
|
||||||
# Test that "target list" lists added target.
|
|
||||||
self.runCmd("-interpreter-exec console \"target list\"")
|
|
||||||
self.expect(r"~\"Current targets:\\n\* target #0: %s" % self.myexe)
|
|
||||||
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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")
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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\"")
|
|
|
@ -1,18 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,68 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -stack-list-locals -stack-list-variables and -var-create commands
|
|
||||||
for variables with the same name in sibling lexical scopes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class MiLexicalScopeTestCase(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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
def test_lldbmi_var_create_in_sibling_scope(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' works with sibling lexical scopes."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
# Load executable
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# Breakpoint inside first scope
|
|
||||||
line = line_number('main.cpp', '// BP_first')
|
|
||||||
self.runCmd("-break-insert --file main.cpp:%d" % line)
|
|
||||||
self.expect("\^done,bkpt={number=\"\d+\"")
|
|
||||||
|
|
||||||
# Breakpoint inside second scope
|
|
||||||
line = line_number('main.cpp', '// BP_second')
|
|
||||||
self.runCmd("-break-insert --file main.cpp:%d" % line)
|
|
||||||
self.expect("\^done,bkpt={number=\"\d+\"")
|
|
||||||
|
|
||||||
# Run to the first scope
|
|
||||||
self.runCmd("-exec-run")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
|
||||||
|
|
||||||
# Check that only variables a and b exist with expected values
|
|
||||||
self.runCmd("-stack-list-locals --thread 1 --frame 0 --all-values")
|
|
||||||
self.expect("\^done,locals=\[{name=\"a\",value=\"1\"},{name=\"b\",value=\"2\"}\]")
|
|
||||||
|
|
||||||
# Create variable object for local variable b
|
|
||||||
self.runCmd("-var-create - * \"b\"")
|
|
||||||
self.expect(
|
|
||||||
"\^done,name=\"var\d+\",numchild=\"0\",value=\"2\",type=\"int\",thread-id=\"1\",has_more=\"0\"")
|
|
||||||
|
|
||||||
# Run to the second scope
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
|
||||||
|
|
||||||
# Check that only variables a and b exist with expected values,
|
|
||||||
# but variable b is different from previous breakpoint
|
|
||||||
self.runCmd("-stack-list-variables --thread 1 --frame 0 --all-values")
|
|
||||||
self.expect("\^done,variables=\[{name=\"a\",value=\"1\"},{name=\"b\",value=\"3\"}\]")
|
|
||||||
|
|
||||||
# Create variable object for local variable b
|
|
||||||
self.runCmd("-var-create - * \"b\"")
|
|
||||||
self.expect(
|
|
||||||
"\^done,name=\"var\d+\",numchild=\"0\",value=\"3\",type=\"short\",thread-id=\"1\",has_more=\"0\"")
|
|
|
@ -1,32 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void
|
|
||||||
some_func (void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_sibling_scope (void)
|
|
||||||
{
|
|
||||||
int a = 1;
|
|
||||||
{
|
|
||||||
int b = 2;
|
|
||||||
some_func(); // BP_first
|
|
||||||
}
|
|
||||||
{
|
|
||||||
short b = 3;
|
|
||||||
some_func(); // BP_second
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
test_sibling_scope();
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
"""
|
|
||||||
Base class for lldb-mi test cases.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
|
|
||||||
|
|
||||||
class MiTestCaseBase(Base):
|
|
||||||
|
|
||||||
mydir = None
|
|
||||||
myexe = None
|
|
||||||
mylog = None
|
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def classCleanup(cls):
|
|
||||||
if cls.myexe:
|
|
||||||
TestBase.RemoveTempFile(cls.myexe)
|
|
||||||
if cls.mylog:
|
|
||||||
TestBase.RemoveTempFile(cls.mylog)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
if not self.mydir:
|
|
||||||
raise("mydir is empty")
|
|
||||||
|
|
||||||
Base.setUp(self)
|
|
||||||
self.buildDefault()
|
|
||||||
self.child_prompt = "(gdb)"
|
|
||||||
self.myexe = self.getBuildArtifact("a.out")
|
|
||||||
|
|
||||||
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, exe=None, args=None, preconfig=True):
|
|
||||||
import pexpect
|
|
||||||
import sys
|
|
||||||
if sys.version_info.major == 3:
|
|
||||||
self.child = pexpect.spawnu("%s --interpreter %s" % (
|
|
||||||
self.lldbMiExec, args if args else ""), cwd=self.getBuildDir())
|
|
||||||
else:
|
|
||||||
self.child = pexpect.spawn("%s --interpreter %s" % (
|
|
||||||
self.lldbMiExec, args if args else ""), cwd=self.getBuildDir())
|
|
||||||
self.child.setecho(True)
|
|
||||||
self.mylog = self.getBuildArtifact("child.log")
|
|
||||||
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)
|
|
||||||
if preconfig:
|
|
||||||
self.runCmd("settings set symbols.enable-external-lookup false")
|
|
||||||
self.expect("\^done")
|
|
||||||
self.expect(self.child_prompt, exactly=True)
|
|
||||||
if exe:
|
|
||||||
self.runCmd("-file-exec-and-symbols \"%s\"" % exe)
|
|
||||||
# Testcases expect to be able to match output of this command,
|
|
||||||
# see test_lldbmi_specialchars.
|
|
||||||
|
|
||||||
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)
|
|
|
@ -1,32 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <direct.h>
|
|
||||||
#define getcwd _getcwd // suppress "deprecation" warning
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
int a = 10;
|
|
||||||
|
|
||||||
char buf[512];
|
|
||||||
char *ans = getcwd(buf, sizeof(buf));
|
|
||||||
if (ans) {
|
|
||||||
printf("cwd: %s\n", ans);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("argc=%d\n", argc); // BP_printf
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,236 +0,0 @@
|
||||||
"""
|
|
||||||
Test that the lldb-mi handles signals properly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfLinux
|
|
||||||
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")
|
|
||||||
|
|
||||||
# There's a chance that lldb didn't resume the process, we send an interruput but
|
|
||||||
# the process is not running yet. Give it some time to restart. 5 seconds ought to
|
|
||||||
# be enough for every modern CPU out there.
|
|
||||||
import time
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfDarwin # pexpect is known to be unreliable on Darwin
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
# the same as GdbRemoteTestCaseBase.get_next_port
|
|
||||||
port = 12000 + random.randint(0, 3999)
|
|
||||||
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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
# the same as GdbRemoteTestCaseBase.get_next_port
|
|
||||||
port = 12000 + random.randint(0, 3999)
|
|
||||||
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
|
|
||||||
# FIXME: self.runCmd("-exec-run")
|
|
||||||
self.runCmd("-interpreter-exec command \"process launch\"")
|
|
||||||
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")
|
|
|
@ -1,32 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,558 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -stack-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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=\".*?\"}\]")
|
|
||||||
|
|
||||||
# Test -stack-list-locals in a function with catch clause,
|
|
||||||
# having unnamed parameter
|
|
||||||
# Run to BP_catch_unnamed
|
|
||||||
line = line_number('main.cpp', '// BP_catch_unnamed')
|
|
||||||
self.runCmd("-break-insert --file main.cpp:%d" % line)
|
|
||||||
self.expect("\^done,bkpt={number=\"6\"")
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
|
||||||
|
|
||||||
# Test -stack-list-locals: use --no-values
|
|
||||||
self.runCmd("-stack-list-locals --no-values")
|
|
||||||
self.expect("\^done,locals=\[name=\"i\",name=\"j\"\]")
|
|
||||||
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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+\"\}")
|
|
|
@ -1,141 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void catch_unnamed_test()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int i = 1, j = 2;
|
|
||||||
throw std::exception(); // BP_catch_unnamed
|
|
||||||
}
|
|
||||||
catch(std::exception&)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
local_int_test();
|
|
||||||
local_struct_test();
|
|
||||||
local_array_test();
|
|
||||||
local_pointer_test();
|
|
||||||
catch_unnamed_test();
|
|
||||||
|
|
||||||
do_tests_with_args();
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,335 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi startup options.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
class MiStartupOptionsTestCase(lldbmi_testcase.MiTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
def test_lldbmi_executable_option_file(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter %s' loads executable file."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(exe=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
|
|
||||||
@skipIfDarwin
|
|
||||||
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(exe=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)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
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
|
|
||||||
self.spawnLldbMi(exe=self.myexe)
|
|
||||||
|
|
||||||
# Test that the executable is loaded when file was specified using
|
|
||||||
# absolute path
|
|
||||||
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\"")
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
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 = os.path.relpath(self.myexe, self.getBuildDir())
|
|
||||||
self.spawnLldbMi(exe=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
|
|
||||||
@skipIfDarwin
|
|
||||||
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" + self.myexe
|
|
||||||
|
|
||||||
self.spawnLldbMi(exe=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)
|
|
||||||
|
|
||||||
def copyScript(self, sourceFile):
|
|
||||||
"""copy the script to builddir and replace a.out with the full path"""
|
|
||||||
destFile = os.path.join(os.path.dirname(self.myexe),
|
|
||||||
sourceFile+'.script')
|
|
||||||
with open(sourceFile, 'r') as src:
|
|
||||||
with open(destFile, 'w+') as dest:
|
|
||||||
dest.write(src.read().replace("a.out", self.myexe))
|
|
||||||
return destFile
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfDarwin
|
|
||||||
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 = self.copyScript("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)
|
|
||||||
os.unlink(sourceFile)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@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
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfDarwin
|
|
||||||
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 = self.copyScript("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\"")
|
|
||||||
os.unlink(sourceFile)
|
|
||||||
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
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 = self.copyScript("start_script_error")
|
|
||||||
self.spawnLldbMi(args="--source %s" % sourceFile, preconfig=False)
|
|
||||||
|
|
||||||
# After 'settings set symbols.enable-external-lookup false'
|
|
||||||
self.expect("settings set symbols.enable-external-lookup false")
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
os.unlink(sourceFile)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
def test_lldbmi_log_option(self):
|
|
||||||
"""Test that 'lldb-mi --log' creates a log file in the current directory."""
|
|
||||||
|
|
||||||
logDirectory = self.getBuildDir()
|
|
||||||
self.spawnLldbMi(exe=self.myexe, args="--log")
|
|
||||||
|
|
||||||
# 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
|
|
||||||
import 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)
|
|
||||||
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
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(exe=self.myexe,
|
|
||||||
args="--log --log-dir=%s" % 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
|
|
||||||
import 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)
|
|
|
@ -1,14 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
int a = 10;
|
|
||||||
return 0; //BP_return
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
-file-exec-and-symbols a.out
|
|
||||||
-break-insert -f main
|
|
||||||
-exec-run
|
|
||||||
-break-insert main.cpp:14
|
|
||||||
-exec-continue
|
|
|
@ -1,3 +0,0 @@
|
||||||
settings set symbols.enable-external-lookup false
|
|
||||||
-file-exec-and-symbols a.out
|
|
||||||
-break-ins -f main
|
|
|
@ -1,7 +0,0 @@
|
||||||
-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
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,174 +0,0 @@
|
||||||
"""
|
|
||||||
Test that the lldb-mi driver understands MI command syntax.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
from functools import reduce
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfLinux
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
def test_lldbmi_specialchars(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' handles complicated strings."""
|
|
||||||
|
|
||||||
# Create an alias for myexe
|
|
||||||
complicated_myexe = self.getBuildArtifact("C--mpl-x file's`s @#$%^&*()_+-={}[]| name")
|
|
||||||
os.symlink(self.myexe, complicated_myexe)
|
|
||||||
self.addTearDownHook(lambda: os.unlink(complicated_myexe))
|
|
||||||
|
|
||||||
self.spawnLldbMi(exe=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
|
|
||||||
@skipIfDarwin
|
|
||||||
@expectedFlakeyNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
def test_lldbmi_output_grammar(self):
|
|
||||||
"""Test that 'lldb-mi --interpreter' uses standard output syntax."""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
self.child.setecho(False)
|
|
||||||
|
|
||||||
# Run all commands simultaneously
|
|
||||||
self.runCmd("-unknown-command")
|
|
||||||
self.runCmd("-interpreter-exec command help")
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
self.runCmd("-break-insert -f main")
|
|
||||||
self.runCmd("-gdb-set target-async off")
|
|
||||||
self.runCmd("-exec-run")
|
|
||||||
self.runCmd("-gdb-set target-async on")
|
|
||||||
self.runCmd("-exec-continue")
|
|
||||||
self.runCmd("-gdb-exit")
|
|
||||||
|
|
||||||
# Test that the program's output matches to the following pattern:
|
|
||||||
# ( async-record | stream-record )* [ result-record ] "(gdb)" nl
|
|
||||||
async_record = "^[0-9]*(\*|\+|=).+?\n" # 1
|
|
||||||
stream_record = "^(~|@|&).+?\n" # 2
|
|
||||||
result_record = "^[0-9]*\^.+?\n" # 3
|
|
||||||
prompt = "^\(gdb\)\r\n" # 4
|
|
||||||
command = "^\r\n" # 5 (it looks like empty line for pexpect)
|
|
||||||
error = "^.+?\n" # 6
|
|
||||||
import pexpect # 7 (EOF)
|
|
||||||
all_patterns = [
|
|
||||||
async_record,
|
|
||||||
stream_record,
|
|
||||||
result_record,
|
|
||||||
prompt,
|
|
||||||
command,
|
|
||||||
error,
|
|
||||||
pexpect.EOF]
|
|
||||||
|
|
||||||
# Routines to get a bit-mask for the specified list of patterns
|
|
||||||
def get_bit(pattern): return all_patterns.index(pattern)
|
|
||||||
def get_mask(pattern): return 1 << get_bit(pattern)
|
|
||||||
def or_op(x, y): return x | y
|
|
||||||
def get_state(*args): return reduce(or_op, map(get_mask, args))
|
|
||||||
|
|
||||||
next_state = get_state(command)
|
|
||||||
while True:
|
|
||||||
it = self.expect(all_patterns)
|
|
||||||
matched_pattern = all_patterns[it]
|
|
||||||
|
|
||||||
# Check that state is acceptable
|
|
||||||
if not (next_state & get_mask(matched_pattern)):
|
|
||||||
self.fail(
|
|
||||||
"error: inconsistent pattern '%s' for state %#x (matched string: %s)" %
|
|
||||||
(repr(matched_pattern), next_state, self.child.after))
|
|
||||||
elif matched_pattern == async_record or matched_pattern == stream_record:
|
|
||||||
next_state = get_state(
|
|
||||||
async_record,
|
|
||||||
stream_record,
|
|
||||||
result_record,
|
|
||||||
prompt)
|
|
||||||
elif matched_pattern == result_record:
|
|
||||||
# FIXME lldb-mi prints async-records out of turn
|
|
||||||
# ```
|
|
||||||
# ^done
|
|
||||||
# (gdb)
|
|
||||||
# ^running
|
|
||||||
# =thread-group-started,id="i1",pid="13875"
|
|
||||||
# (gdb)
|
|
||||||
# ```
|
|
||||||
# Therefore to pass that test I changed the grammar's rule:
|
|
||||||
# next_state = get_state(prompt)
|
|
||||||
# to:
|
|
||||||
next_state = get_state(async_record, prompt)
|
|
||||||
elif matched_pattern == prompt:
|
|
||||||
# FIXME lldb-mi prints the prompt out of turn
|
|
||||||
# ```
|
|
||||||
# ^done
|
|
||||||
# (gdb)
|
|
||||||
# ^running
|
|
||||||
# (gdb)
|
|
||||||
# (gdb)
|
|
||||||
# ```
|
|
||||||
# Therefore to pass that test I changed the grammar's rule:
|
|
||||||
# next_state = get_state(async_record, stream_record, result_record, command, pexpect.EOF)
|
|
||||||
# to:
|
|
||||||
next_state = get_state(
|
|
||||||
async_record,
|
|
||||||
stream_record,
|
|
||||||
result_record,
|
|
||||||
prompt,
|
|
||||||
command,
|
|
||||||
pexpect.EOF)
|
|
||||||
elif matched_pattern == command:
|
|
||||||
next_state = get_state(
|
|
||||||
async_record,
|
|
||||||
stream_record,
|
|
||||||
result_record)
|
|
||||||
elif matched_pattern == pexpect.EOF:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.fail("error: pexpect returned an unknown state")
|
|
|
@ -1,16 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
printf("'\n` - it's \\n\x12\"\\\"");
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := test_attach.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,137 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -target-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
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" % self.getBuildArtifact(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(self.getBuildArtifact(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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
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(self.getBuildArtifact(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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
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(
|
|
||||||
self.getBuildArtifact(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")
|
|
|
@ -1,20 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
i++; // BP_i++
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := test_threadinfo.cpp
|
|
||||||
|
|
||||||
ENABLE_THREADS := YES
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,42 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -thread-info command.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class MiThreadInfoTestCase(lldbmi_testcase.MiTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfWindows # pthreads not supported on Windows
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@expectedFailureNetBSD
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
def test_lldbmi_thread_info(self):
|
|
||||||
"""Test that -thread-info prints thread info and the current-thread-id"""
|
|
||||||
|
|
||||||
self.spawnLldbMi(args=None)
|
|
||||||
|
|
||||||
# Load executable
|
|
||||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
self.runCmd("-break-insert ThreadProc")
|
|
||||||
self.expect("\^done")
|
|
||||||
|
|
||||||
# Run to the breakpoint
|
|
||||||
self.runCmd("-exec-run")
|
|
||||||
self.expect("\^running")
|
|
||||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
|
||||||
|
|
||||||
self.runCmd("-thread-info")
|
|
||||||
self.expect(
|
|
||||||
"\^done,threads=\[\{id=\"1\",(.*)\},\{id=\"2\",(.*)\],current-thread-id=\"2\"")
|
|
||||||
|
|
||||||
self.runCmd("-gdb-quit")
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void
|
|
||||||
ThreadProc()
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
thread t(ThreadProc);
|
|
||||||
t.join();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,247 +0,0 @@
|
||||||
# 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.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@expectedFailureAll(compiler="gcc", bugnumber="llvm.org/pr23357")
|
|
||||||
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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.\"")
|
|
|
@ -1,465 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-mi -var-xxx commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import lldbmi_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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: use of undeclared identifier \'undef\'\\\\n\"")
|
|
||||||
self.runCmd("-data-evaluate-expression undef")
|
|
||||||
self.expect(
|
|
||||||
"\^error,msg=\"error: use of undeclared identifier \'undef\'\\\\n\"")
|
|
||||||
|
|
||||||
# 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]".
|
|
||||||
# FIXME -var-list-children shows invalid thread-id
|
|
||||||
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\"")
|
|
||||||
|
|
||||||
# Print an expression with spaces and optional arguments
|
|
||||||
self.runCmd("-data-evaluate-expression \"a + b\"")
|
|
||||||
self.expect("\^done,value=\"12\"")
|
|
||||||
self.runCmd("-var-create var7 * \"a + b\" --thread 1 --frame 0")
|
|
||||||
self.expect(
|
|
||||||
"\^done,name=\"var7\",numchild=\"0\",value=\"12\",type=\"int\",thread-id=\"1\",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
|
|
||||||
@skipIfLinux # llvm.org/pr22841: lldb-mi tests fail on all Linux buildbots
|
|
||||||
@skipIfDarwin
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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
|
|
||||||
@skipIfRemote # We do not currently support remote debugging via the MI.
|
|
||||||
@skipIfDarwin
|
|
||||||
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"')
|
|
|
@ -1,151 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
BasedOnStyle: LLVM
|
|
|
@ -1,8 +0,0 @@
|
||||||
LEVEL = ../../make
|
|
||||||
|
|
||||||
override CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
|
|
||||||
ENABLE_THREADS := YES
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
MAKE_DSYM :=NO
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,123 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
class TestAppleSimulatorOSType(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def check_simulator_ostype(self, sdk, platform, arch='x86_64'):
|
|
||||||
sim_devices_str = subprocess.check_output(['xcrun', 'simctl', 'list',
|
|
||||||
'-j', 'devices']).decode("utf-8")
|
|
||||||
sim_devices = json.loads(sim_devices_str)['devices']
|
|
||||||
# Find an available simulator for the requested platform
|
|
||||||
deviceUDID = None
|
|
||||||
for simulator in sim_devices:
|
|
||||||
if isinstance(simulator,dict):
|
|
||||||
runtime = simulator['name']
|
|
||||||
devices = simulator['devices']
|
|
||||||
else:
|
|
||||||
runtime = simulator
|
|
||||||
devices = sim_devices[simulator]
|
|
||||||
if not platform in runtime.lower():
|
|
||||||
continue
|
|
||||||
for device in devices:
|
|
||||||
if 'availability' in device and device['availability'] != '(available)':
|
|
||||||
continue
|
|
||||||
if 'isAvailable' in device and device['isAvailable'] != True:
|
|
||||||
continue
|
|
||||||
deviceUDID = device['udid']
|
|
||||||
break
|
|
||||||
if deviceUDID != None:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Launch the process using simctl
|
|
||||||
self.assertIsNotNone(deviceUDID)
|
|
||||||
exe_name = 'test_simulator_platform_{}'.format(platform)
|
|
||||||
sdkroot = subprocess.check_output(['xcrun', '--show-sdk-path', '--sdk',
|
|
||||||
sdk]).decode("utf-8")
|
|
||||||
self.build(dictionary={ 'EXE': exe_name, 'SDKROOT': sdkroot.strip(),
|
|
||||||
'ARCH': arch })
|
|
||||||
exe_path = self.getBuildArtifact(exe_name)
|
|
||||||
sim_launcher = subprocess.Popen(['xcrun', 'simctl', 'spawn',
|
|
||||||
deviceUDID, exe_path,
|
|
||||||
'print-pid', 'sleep:10'],
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
# Get the PID from the process output
|
|
||||||
pid = None
|
|
||||||
while not pid:
|
|
||||||
stderr = sim_launcher.stderr.readline().decode("utf-8")
|
|
||||||
if stderr == '':
|
|
||||||
continue
|
|
||||||
m = re.match(r"PID: (.*)", stderr)
|
|
||||||
self.assertIsNotNone(m)
|
|
||||||
pid = int(m.group(1))
|
|
||||||
|
|
||||||
# Launch debug monitor attaching to the simulated process
|
|
||||||
self.init_debugserver_test()
|
|
||||||
server = self.connect_to_debug_monitor(attach_pid=pid)
|
|
||||||
|
|
||||||
# Setup packet sequences
|
|
||||||
self.add_no_ack_remote_stream()
|
|
||||||
self.add_process_info_collection_packets()
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: " +
|
|
||||||
"$jGetLoadedDynamicLibrariesInfos:{\"fetch_all_solibs\" : true}]#ce",
|
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "dylib_info_raw"}}],
|
|
||||||
True)
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# Check that ostype is correct
|
|
||||||
self.assertEquals(process_info['ostype'], platform)
|
|
||||||
|
|
||||||
# Now for dylibs
|
|
||||||
dylib_info_raw = context.get("dylib_info_raw")
|
|
||||||
dylib_info = json.loads(self.decode_gdbremote_binary(dylib_info_raw))
|
|
||||||
images = dylib_info['images']
|
|
||||||
|
|
||||||
image_info = None
|
|
||||||
for image in images:
|
|
||||||
if image['pathname'] != exe_path:
|
|
||||||
continue
|
|
||||||
image_info = image
|
|
||||||
break
|
|
||||||
|
|
||||||
self.assertIsNotNone(image_info)
|
|
||||||
self.assertEquals(image['min_version_os_name'], platform)
|
|
||||||
|
|
||||||
|
|
||||||
@apple_simulator_test('iphone')
|
|
||||||
@debugserver_test
|
|
||||||
@skipIfDarwinEmbedded
|
|
||||||
def test_simulator_ostype_ios(self):
|
|
||||||
self.check_simulator_ostype(sdk='iphonesimulator',
|
|
||||||
platform='ios')
|
|
||||||
|
|
||||||
@apple_simulator_test('appletv')
|
|
||||||
@debugserver_test
|
|
||||||
@skipIfDarwinEmbedded
|
|
||||||
def test_simulator_ostype_tvos(self):
|
|
||||||
self.check_simulator_ostype(sdk='appletvsimulator',
|
|
||||||
platform='tvos')
|
|
||||||
|
|
||||||
@apple_simulator_test('watch')
|
|
||||||
@debugserver_test
|
|
||||||
@skipIfDarwinEmbedded
|
|
||||||
def test_simulator_ostype_watchos(self):
|
|
||||||
self.check_simulator_ostype(sdk='watchsimulator',
|
|
||||||
platform='watchos', arch='i386')
|
|
|
@ -1,67 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteAttach(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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()
|
|
|
@ -1,220 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read"
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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": self.maybe_strict_output_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()
|
|
|
@ -1,127 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# lldb test suite imports
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import TestBase
|
|
||||||
|
|
||||||
# gdb-remote-specific imports
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from gdbremote_testcase import GdbRemoteTestCaseBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteExitCode(GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
FAILED_LAUNCH_CODE = "E08"
|
|
||||||
|
|
||||||
def get_launch_fail_reason(self):
|
|
||||||
self.reset_test_sequence()
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: $qLaunchSuccess#00"],
|
|
||||||
True)
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
[{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "launch_result"}}],
|
|
||||||
True)
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
return context.get("launch_result")[1:]
|
|
||||||
|
|
||||||
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)],
|
|
||||||
True)
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
[{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "A_result"}}],
|
|
||||||
True)
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
|
|
||||||
launch_result = context.get("A_result")
|
|
||||||
self.assertIsNotNone(launch_result)
|
|
||||||
if launch_result == self.FAILED_LAUNCH_CODE:
|
|
||||||
fail_reason = self.get_launch_fail_reason()
|
|
||||||
self.fail("failed to launch inferior: " + fail_reason)
|
|
||||||
|
|
||||||
@debugserver_test
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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()
|
|
|
@ -1,162 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteExpeditedRegisters(
|
|
||||||
gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
|
|
||||||
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 (isinstance(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()
|
|
||||||
|
|
||||||
# powerpc64 has no FP register
|
|
||||||
@skipIf(triple='^powerpc64')
|
|
||||||
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()
|
|
|
@ -1,131 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# lldb test suite imports
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import TestBase
|
|
||||||
|
|
||||||
# gdb-remote-specific imports
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from gdbremote_testcase import GdbRemoteTestCaseBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteHostInfo(GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
KNOWN_HOST_INFO_KEYS = set([
|
|
||||||
"arch",
|
|
||||||
"cputype",
|
|
||||||
"cpusubtype",
|
|
||||||
"distribution_id",
|
|
||||||
"endian",
|
|
||||||
"hostname",
|
|
||||||
"ostype",
|
|
||||||
"os_build",
|
|
||||||
"os_kernel",
|
|
||||||
"os_version",
|
|
||||||
"ptrsize",
|
|
||||||
"triple",
|
|
||||||
"vendor",
|
|
||||||
"watchpoint_exceptions_received",
|
|
||||||
"default_packet_timeout",
|
|
||||||
])
|
|
||||||
|
|
||||||
DARWIN_REQUIRED_HOST_INFO_KEYS = set([
|
|
||||||
"cputype",
|
|
||||||
"cpusubtype",
|
|
||||||
"endian",
|
|
||||||
"ostype",
|
|
||||||
"ptrsize",
|
|
||||||
"vendor",
|
|
||||||
"watchpoint_exceptions_received"
|
|
||||||
])
|
|
||||||
|
|
||||||
def add_host_info_collection_packets(self):
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: $qHostInfo#9b",
|
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "host_info_raw"}}],
|
|
||||||
True)
|
|
||||||
|
|
||||||
def parse_host_info_response(self, context):
|
|
||||||
# Ensure we have a host info response.
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
host_info_raw = context.get("host_info_raw")
|
|
||||||
self.assertIsNotNone(host_info_raw)
|
|
||||||
|
|
||||||
# Pull out key:value; pairs.
|
|
||||||
host_info_dict = {match.group(1): match.group(2)
|
|
||||||
for match in re.finditer(r"([^:]+):([^;]+);",
|
|
||||||
host_info_raw)}
|
|
||||||
|
|
||||||
import pprint
|
|
||||||
print("\nqHostInfo response:")
|
|
||||||
pprint.pprint(host_info_dict)
|
|
||||||
|
|
||||||
# Validate keys are known.
|
|
||||||
for (key, val) in list(host_info_dict.items()):
|
|
||||||
self.assertTrue(key in self.KNOWN_HOST_INFO_KEYS,
|
|
||||||
"unknown qHostInfo key: " + key)
|
|
||||||
self.assertIsNotNone(val)
|
|
||||||
|
|
||||||
# Return the key:val pairs.
|
|
||||||
return host_info_dict
|
|
||||||
|
|
||||||
def get_qHostInfo_response(self):
|
|
||||||
# Launch the debug monitor stub, attaching to the inferior.
|
|
||||||
server = self.connect_to_debug_monitor()
|
|
||||||
self.assertIsNotNone(server)
|
|
||||||
self.add_no_ack_remote_stream()
|
|
||||||
|
|
||||||
# Request qHostInfo and get response
|
|
||||||
self.add_host_info_collection_packets()
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
|
|
||||||
# Parse qHostInfo response.
|
|
||||||
host_info = self.parse_host_info_response(context)
|
|
||||||
self.assertIsNotNone(host_info)
|
|
||||||
self.assertGreater(len(host_info), 0, "qHostInfo should have returned "
|
|
||||||
"at least one key:val pair.")
|
|
||||||
return host_info
|
|
||||||
|
|
||||||
def validate_darwin_minimum_host_info_keys(self, host_info_dict):
|
|
||||||
self.assertIsNotNone(host_info_dict)
|
|
||||||
missing_keys = [key for key in self.DARWIN_REQUIRED_HOST_INFO_KEYS
|
|
||||||
if key not in host_info_dict]
|
|
||||||
self.assertEquals(0, len(missing_keys),
|
|
||||||
"qHostInfo is missing the following required "
|
|
||||||
"keys: " + str(missing_keys))
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@debugserver_test
|
|
||||||
def test_qHostInfo_returns_at_least_one_key_val_pair_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.get_qHostInfo_response()
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@llgs_test
|
|
||||||
def test_qHostInfo_returns_at_least_one_key_val_pair_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.get_qHostInfo_response()
|
|
||||||
|
|
||||||
@skipUnlessDarwin
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@debugserver_test
|
|
||||||
def test_qHostInfo_contains_darwin_required_keys_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
host_info_dict = self.get_qHostInfo_response()
|
|
||||||
self.validate_darwin_minimum_host_info_keys(host_info_dict)
|
|
||||||
|
|
||||||
@skipUnlessDarwin
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@llgs_test
|
|
||||||
def test_qHostInfo_contains_darwin_required_keys_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
host_info_dict = self.get_qHostInfo_response()
|
|
||||||
self.validate_darwin_minimum_host_info_keys(host_info_dict)
|
|
|
@ -1,59 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteKill(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
|
|
||||||
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()
|
|
|
@ -1,44 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from lldbsuite.support import seven
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteModuleInfo(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def module_info(self):
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
self.add_process_info_collection_packets()
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
info = self.parse_process_info_response(context)
|
|
||||||
|
|
||||||
self.test_sequence.add_log_lines([
|
|
||||||
'read packet: $jModulesInfo:[{"file":"%s","triple":"%s"}]]#00' % (
|
|
||||||
lldbutil.append_to_process_working_directory(self, "a.out"),
|
|
||||||
seven.unhexlify(info["triple"])),
|
|
||||||
{"direction": "send",
|
|
||||||
"regex": r'^\$\[{(.*)}\]\]#[0-9A-Fa-f]{2}',
|
|
||||||
"capture": {1: "spec"}},
|
|
||||||
], True)
|
|
||||||
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
spec = context.get("spec")
|
|
||||||
self.assertRegexpMatches(spec, '"file_path":".*"')
|
|
||||||
self.assertRegexpMatches(spec, '"file_offset":\d+')
|
|
||||||
self.assertRegexpMatches(spec, '"file_size":\d+')
|
|
||||||
self.assertRegexpMatches(spec, '"triple":"\w*-\w*-.*"')
|
|
||||||
self.assertRegexpMatches(spec, '"uuid":"[A-Fa-f0-9]+"')
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test_module_info(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
self.module_info()
|
|
|
@ -1,211 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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(timeout_seconds=8)
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
def test_qProcessInfo_contains_cputype_cpusubtype_debugserver_darwin(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.qProcessInfo_contains_keys(set(['cputype', 'cpusubtype']))
|
|
||||||
|
|
||||||
@skipUnlessDarwin
|
|
||||||
@llgs_test
|
|
||||||
def test_qProcessInfo_contains_cputype_cpusubtype_llgs_darwin(self):
|
|
||||||
self.init_llgs_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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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']))
|
|
||||||
|
|
||||||
@skipUnlessDarwin
|
|
||||||
@llgs_test
|
|
||||||
def test_qProcessInfo_does_not_contain_triple_llgs_darwin(self):
|
|
||||||
self.init_llgs_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']))
|
|
|
@ -1,128 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteRegisterState(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
"""Test QSaveRegisterState/QRestoreRegisterState support."""
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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()
|
|
||||||
|
|
||||||
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)
|
|
|
@ -1,41 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteSingleStep(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@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.org/pr24739",
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"])
|
|
||||||
@expectedFailureAll(
|
|
||||||
oslist=["linux"],
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"],
|
|
||||||
bugnumber="llvm.org/pr24739")
|
|
||||||
@skipIf(triple='^mips')
|
|
||||||
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")
|
|
|
@ -1,303 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
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_fields(self, post_startup_log_lines, thread_count,
|
|
||||||
field_names):
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
self.add_register_info_collection_packets()
|
|
||||||
self.add_process_info_collection_packets()
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
hw_info = self.parse_hw_info(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)
|
|
||||||
|
|
||||||
result = dict();
|
|
||||||
result["pc_register"] = hw_info["pc_register"]
|
|
||||||
result["little_endian"] = hw_info["little_endian"]
|
|
||||||
for key_field in field_names:
|
|
||||||
result[key_field] = kv_dict.get(key_field)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def gather_stop_reply_threads(self, post_startup_log_lines, thread_count):
|
|
||||||
# Pull out threads from stop response.
|
|
||||||
stop_reply_threads_text = self.gather_stop_reply_fields(
|
|
||||||
post_startup_log_lines, thread_count, ["threads"])["threads"]
|
|
||||||
if stop_reply_threads_text:
|
|
||||||
return [int(thread_id, 16)
|
|
||||||
for thread_id in stop_reply_threads_text.split(",")]
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def gather_stop_reply_pcs(self, post_startup_log_lines, thread_count):
|
|
||||||
results = self.gather_stop_reply_fields( post_startup_log_lines,
|
|
||||||
thread_count, ["threads", "thread-pcs"])
|
|
||||||
if not results:
|
|
||||||
return []
|
|
||||||
|
|
||||||
threads_text = results["threads"]
|
|
||||||
pcs_text = results["thread-pcs"]
|
|
||||||
thread_ids = threads_text.split(",")
|
|
||||||
pcs = pcs_text.split(",")
|
|
||||||
self.assertTrue(len(thread_ids) == len(pcs))
|
|
||||||
|
|
||||||
thread_pcs = dict()
|
|
||||||
for i in range(0, len(pcs)):
|
|
||||||
thread_pcs[int(thread_ids[i], 16)] = pcs[i]
|
|
||||||
|
|
||||||
result = dict()
|
|
||||||
result["thread_pcs"] = thread_pcs
|
|
||||||
result["pc_register"] = results["pc_register"]
|
|
||||||
result["little_endian"] = results["little_endian"]
|
|
||||||
return result
|
|
||||||
|
|
||||||
def switch_endian(self, egg):
|
|
||||||
return "".join(reversed(re.findall("..", egg)))
|
|
||||||
|
|
||||||
def parse_hw_info(self, context):
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
process_info = self.parse_process_info_response(context)
|
|
||||||
endian = process_info.get("endian")
|
|
||||||
reg_info = self.parse_register_info_packets(context)
|
|
||||||
(pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_info)
|
|
||||||
|
|
||||||
hw_info = dict()
|
|
||||||
hw_info["pc_register"] = pc_lldb_reg_index
|
|
||||||
hw_info["little_endian"] = (endian == "little")
|
|
||||||
return hw_info
|
|
||||||
|
|
||||||
def gather_threads_info_pcs(self, pc_register, little_endian):
|
|
||||||
self.reset_test_sequence()
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
[
|
|
||||||
"read packet: $jThreadsInfo#c1",
|
|
||||||
{
|
|
||||||
"direction": "send",
|
|
||||||
"regex": r"^\$(.*)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {
|
|
||||||
1: "threads_info"}},
|
|
||||||
],
|
|
||||||
True)
|
|
||||||
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
threads_info = context.get("threads_info")
|
|
||||||
register = str(pc_register)
|
|
||||||
# The jThreadsInfo response is not valid JSON data, so we have to
|
|
||||||
# clean it up first.
|
|
||||||
jthreads_info = json.loads(re.sub(r"}]", "}", threads_info))
|
|
||||||
thread_pcs = dict()
|
|
||||||
for thread_info in jthreads_info:
|
|
||||||
tid = thread_info["tid"]
|
|
||||||
pc = thread_info["registers"][register]
|
|
||||||
thread_pcs[tid] = self.switch_endian(pc) if little_endian else pc
|
|
||||||
|
|
||||||
return thread_pcs
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@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)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@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)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@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)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@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)
|
|
||||||
|
|
||||||
def stop_reply_contains_thread_pcs(self, thread_count):
|
|
||||||
results = self.gather_stop_reply_pcs(
|
|
||||||
self.ENABLE_THREADS_IN_STOP_REPLY_ENTRIES, thread_count)
|
|
||||||
stop_reply_pcs = results["thread_pcs"]
|
|
||||||
pc_register = results["pc_register"]
|
|
||||||
little_endian = results["little_endian"]
|
|
||||||
self.assertEqual(len(stop_reply_pcs), thread_count)
|
|
||||||
|
|
||||||
threads_info_pcs = self.gather_threads_info_pcs(pc_register,
|
|
||||||
little_endian)
|
|
||||||
|
|
||||||
self.assertEqual(len(threads_info_pcs), thread_count)
|
|
||||||
for thread_id in stop_reply_pcs:
|
|
||||||
self.assertTrue(thread_id in threads_info_pcs)
|
|
||||||
self.assertTrue(int(stop_reply_pcs[thread_id], 16)
|
|
||||||
== int(threads_info_pcs[thread_id], 16))
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test_stop_reply_contains_thread_pcs_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
self.stop_reply_contains_thread_pcs(5)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@debugserver_test
|
|
||||||
def test_stop_reply_contains_thread_pcs_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
self.stop_reply_contains_thread_pcs(5)
|
|
|
@ -1,182 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import unittest2
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemote_qThreadStopInfo(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
THREAD_COUNT = 5
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/27005337>
|
|
||||||
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")
|
|
||||||
|
|
||||||
# test requires OS with set, equal thread names by default.
|
|
||||||
@skipUnlessPlatform(["linux"])
|
|
||||||
@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")
|
|
|
@ -1,159 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@debugserver_test
|
|
||||||
def test_vCont_supports_c_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_c()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@llgs_test
|
|
||||||
def test_vCont_supports_c_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_c()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@debugserver_test
|
|
||||||
def test_vCont_supports_C_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_C()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@llgs_test
|
|
||||||
def test_vCont_supports_C_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_C()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@debugserver_test
|
|
||||||
def test_vCont_supports_s_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_s()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@llgs_test
|
|
||||||
def test_vCont_supports_s_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_s()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@debugserver_test
|
|
||||||
def test_vCont_supports_S_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_S()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@llgs_test
|
|
||||||
def test_vCont_supports_S_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.vCont_supports_S()
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@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.org/pr24739",
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"])
|
|
||||||
@expectedFailureAll(
|
|
||||||
oslist=["linux"],
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"],
|
|
||||||
bugnumber="llvm.org/pr24739")
|
|
||||||
@skipIf(triple='^mips')
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
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")
|
|
||||||
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
@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.org/pr24739",
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"])
|
|
||||||
@expectedFailureAll(
|
|
||||||
oslist=["linux"],
|
|
||||||
archs=[
|
|
||||||
"arm",
|
|
||||||
"aarch64"],
|
|
||||||
bugnumber="llvm.org/pr24739")
|
|
||||||
@skipIf(triple='^mips')
|
|
||||||
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://27005337")
|
|
||||||
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}")
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,98 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
import re
|
|
||||||
import select
|
|
||||||
import socket
|
|
||||||
import time
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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()
|
|
|
@ -1,86 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import lldbgdbserverutils
|
|
||||||
import os
|
|
||||||
import select
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@expectedFailureAll(oslist=['freebsd'])
|
|
||||||
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()
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
||||||
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
|
|
|
@ -1,46 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import signal
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteAbort(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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()
|
|
|
@ -1,46 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import signal
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteSegFault(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
GDB_REMOTE_STOP_CODE_BAD_ACCESS = 0x91
|
|
||||||
|
|
||||||
@skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
|
|
||||||
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'))
|
|
|
@ -1,31 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -1,945 +0,0 @@
|
||||||
"""Module for supporting unit testing of the lldb-server debug monitor exe.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import division, 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,
|
|
||||||
pump_queues,
|
|
||||||
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, pump_queues, 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.encode())
|
|
||||||
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_queues.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_queues.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 = ""
|
|
||||||
while value != 0:
|
|
||||||
retval = "{:02x}".format(value & 0xff) + retval
|
|
||||||
value = value >> 8
|
|
||||||
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 isinstance(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 isinstance(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 (isinstance(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 (isinstance(regex, str)):
|
|
||||||
regex = re.compile(regex, re.DOTALL)
|
|
||||||
|
|
||||||
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).decode("utf-8")
|
|
||||||
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")
|
|
|
@ -1,370 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include <setjmp.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <thread>
|
|
||||||
#include <time.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>
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
#include <lwp.h>
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#include <windows.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 const char *const PRINT_PID_COMMAND = "print-pid";
|
|
||||||
|
|
||||||
static bool g_print_thread_ids = false;
|
|
||||||
static std::mutex g_print_mutex;
|
|
||||||
static bool g_threads_do_segfault = false;
|
|
||||||
|
|
||||||
static std::mutex g_jump_buffer_mutex;
|
|
||||||
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_pid() {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
fprintf(stderr, "PID: %d\n", ::GetCurrentProcessId());
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "PID: %d\n", getpid());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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)));
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
// Technically lwpid_t is 32-bit signed integer
|
|
||||||
printf("%" PRIx64, static_cast<uint64_t>(_lwp_self()));
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
printf("%" PRIx64, static_cast<uint64_t>(::GetCurrentThreadId()));
|
|
||||||
#else
|
|
||||||
printf("{no-tid-support}");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void signal_handler(int signo) {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
// No signal support on Windows.
|
|
||||||
#else
|
|
||||||
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.
|
|
||||||
{
|
|
||||||
std::lock_guard<std::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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void swap_chars() {
|
|
||||||
g_c1 = '1';
|
|
||||||
g_c2 = '0';
|
|
||||||
|
|
||||||
g_c1 = '0';
|
|
||||||
g_c2 = '1';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hello() {
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("hello, world\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *thread_func(void *arg) {
|
|
||||||
static std::atomic<int> s_thread_index(1);
|
|
||||||
const int this_thread_index = s_thread_index++;
|
|
||||||
if (g_print_thread_ids) {
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("thread %d id: ", this_thread_index);
|
|
||||||
print_thread_id();
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds));
|
|
||||||
|
|
||||||
// Test creating a SEGV.
|
|
||||||
{
|
|
||||||
std::lock_guard<std::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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("thread ");
|
|
||||||
print_thread_id();
|
|
||||||
printf(": past SIGSEGV\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int sleep_seconds_remaining = 60;
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds_remaining));
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
lldb_enable_attach();
|
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
|
||||||
std::unique_ptr<uint8_t[]> heap_array_up;
|
|
||||||
int return_value = 0;
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
std::this_thread::sleep_for(
|
|
||||||
std::chrono::seconds(sleep_seconds_remaining));
|
|
||||||
|
|
||||||
} 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)) {
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("message: %s\n", g_message);
|
|
||||||
} 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;
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("data address: %p\n", data_p);
|
|
||||||
} 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]);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("heap address: %p\n", heap_array_up.get());
|
|
||||||
|
|
||||||
} else if (std::strstr(argv[i], GET_STACK_ADDRESS_COMMAND)) {
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("stack address: %p\n", &return_value);
|
|
||||||
} 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;
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("code address: %p\n", func_p);
|
|
||||||
} else if (std::strstr(argv[i], CALL_FUNCTION_PREFIX)) {
|
|
||||||
void (*func_p)() = nullptr;
|
|
||||||
|
|
||||||
// Defaut to providing the address of main.
|
|
||||||
if (std::strcmp(argv[i] + strlen(CALL_FUNCTION_PREFIX), "hello") == 0)
|
|
||||||
func_p = hello;
|
|
||||||
else if (std::strcmp(argv[i] + strlen(CALL_FUNCTION_PREFIX),
|
|
||||||
"swap_chars") == 0)
|
|
||||||
func_p = swap_chars;
|
|
||||||
else {
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("unknown function: %s\n",
|
|
||||||
argv[i] + strlen(CALL_FUNCTION_PREFIX));
|
|
||||||
}
|
|
||||||
if (func_p)
|
|
||||||
func_p();
|
|
||||||
} 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)) {
|
|
||||||
threads.push_back(std::thread(thread_func, nullptr));
|
|
||||||
} 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.
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(g_print_mutex);
|
|
||||||
printf("thread 0 id: ");
|
|
||||||
print_thread_id();
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
} 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 if (std::strstr(argv[i], PRINT_PID_COMMAND)) {
|
|
||||||
print_pid();
|
|
||||||
} else {
|
|
||||||
// Treat the argument as text for stdout.
|
|
||||||
printf("%s\n", argv[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we launched any threads, join them
|
|
||||||
for (std::vector<std::thread>::iterator it = threads.begin();
|
|
||||||
it != threads.end(); ++it)
|
|
||||||
it->join();
|
|
||||||
|
|
||||||
return return_value;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,96 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import 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()
|
|
||||||
src = lldb.SBFileSpec(self.getBuildArtifact("a.out"))
|
|
||||||
dest = lldb.SBFileSpec(os.path.join(working_dir, "a.out"))
|
|
||||||
err = lldb.remote_platform.Put(src, dest)
|
|
||||||
if err.Fail():
|
|
||||||
raise RuntimeError(
|
|
||||||
"Unable copy '%s' to '%s'.\n>>> %s" %
|
|
||||||
(f, wd, err.GetCString()))
|
|
||||||
|
|
||||||
m = re.search("^(.*)://([^:/]*)", configuration.lldb_platform_url)
|
|
||||||
protocol = m.group(1)
|
|
||||||
hostname = m.group(2)
|
|
||||||
unix_protocol = protocol.startswith("unix-")
|
|
||||||
if unix_protocol:
|
|
||||||
p = re.search("^(.*)-connect", protocol)
|
|
||||||
path = lldbutil.join_remote_paths(configuration.lldb_platform_working_dir,
|
|
||||||
self.getBuildDirBasename(), "platform-%d.sock" % int(time.time()))
|
|
||||||
listen_url = "%s://%s" % (p.group(1), path)
|
|
||||||
else:
|
|
||||||
listen_url = "*:0"
|
|
||||||
|
|
||||||
port_file = "%s/port" % working_dir
|
|
||||||
commandline_args = [
|
|
||||||
"platform",
|
|
||||||
"--listen",
|
|
||||||
listen_url,
|
|
||||||
"--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)
|
|
||||||
|
|
||||||
socket_id = lldbutil.wait_for_file_on_target(self, 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()
|
|
||||||
|
|
||||||
if unix_protocol:
|
|
||||||
connect_url = "%s://%s%s" % (protocol, hostname, socket_id)
|
|
||||||
else:
|
|
||||||
connect_url = "%s://%s:%s" % (protocol, hostname, socket_id)
|
|
||||||
|
|
||||||
command = "platform connect %s" % (connect_url)
|
|
||||||
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()
|
|
|
@ -1,6 +0,0 @@
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
printf("argc: %d\n", argc);
|
|
||||||
return argv[0][0];
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,153 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
import textwrap
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_register_value(reg_info, reg_bank, byte_order, bytes_per_entry=8):
|
|
||||||
reg_offset = int(reg_info["offset"])*2
|
|
||||||
reg_byte_size = int(2 * int(reg_info["bitsize"]) / 8)
|
|
||||||
# Create slice with the contents of the register.
|
|
||||||
reg_slice = reg_bank[reg_offset:reg_offset+reg_byte_size]
|
|
||||||
|
|
||||||
reg_value = []
|
|
||||||
# Wrap slice according to bytes_per_entry.
|
|
||||||
for entry in textwrap.wrap(reg_slice, 2 * bytes_per_entry):
|
|
||||||
# Invert the bytes order if target uses little-endian.
|
|
||||||
if byte_order == lldb.eByteOrderLittle:
|
|
||||||
entry = "".join(reversed([entry[i:i+2] for i in range(0,
|
|
||||||
len(entry),2)]))
|
|
||||||
reg_value.append("0x" + entry)
|
|
||||||
|
|
||||||
return reg_value
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteGPacket(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def run_test_g_packet(self):
|
|
||||||
self.build()
|
|
||||||
self.prep_debug_monitor_and_inferior()
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: $g#67",
|
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "register_bank"}}],
|
|
||||||
True)
|
|
||||||
self.connect_to_debug_monitor()
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
register_bank = context.get("register_bank")
|
|
||||||
self.assertTrue(register_bank[0] != 'E')
|
|
||||||
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: $G" + register_bank + "#00",
|
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "G_reply"}}],
|
|
||||||
True)
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertTrue(context.get("G_reply")[0] != 'E')
|
|
||||||
|
|
||||||
@skipIfOutOfTreeDebugserver
|
|
||||||
@debugserver_test
|
|
||||||
@skipIfDarwinEmbedded
|
|
||||||
def test_g_packet_debugserver(self):
|
|
||||||
self.init_debugserver_test()
|
|
||||||
self.run_test_g_packet()
|
|
||||||
|
|
||||||
@skipIf(archs=no_match(["x86_64"]))
|
|
||||||
def g_returns_correct_data(self, with_suffix):
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
|
|
||||||
self.add_register_info_collection_packets()
|
|
||||||
if with_suffix:
|
|
||||||
self.add_thread_suffix_request_packets()
|
|
||||||
self.add_threadinfo_collection_packets()
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
|
|
||||||
# Gather register info.
|
|
||||||
reg_infos = self.parse_register_info_packets(context)
|
|
||||||
self.assertIsNotNone(reg_infos)
|
|
||||||
self.add_lldb_register_index(reg_infos)
|
|
||||||
# Index register info entries by name.
|
|
||||||
reg_infos = {info['name']: info for info in reg_infos}
|
|
||||||
|
|
||||||
# Gather thread info.
|
|
||||||
if with_suffix:
|
|
||||||
threads = self.parse_threadinfo_packets(context)
|
|
||||||
self.assertIsNotNone(threads)
|
|
||||||
thread_id = threads[0]
|
|
||||||
self.assertIsNotNone(thread_id)
|
|
||||||
else:
|
|
||||||
thread_id = None
|
|
||||||
|
|
||||||
# Send vCont packet to resume the inferior.
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Send g packet to retrieve the register bank
|
|
||||||
if thread_id:
|
|
||||||
g_request = "read packet: $g;thread:{:x}#00".format(thread_id)
|
|
||||||
else:
|
|
||||||
g_request = "read packet: $g#00"
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
[g_request,
|
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
|
|
||||||
"capture": {1: "register_bank"}}],
|
|
||||||
True)
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
reg_bank = context.get("register_bank")
|
|
||||||
self.assertTrue(reg_bank[0] != 'E')
|
|
||||||
|
|
||||||
byte_order = self.get_target_byte_order()
|
|
||||||
get_reg_value = lambda reg_name : _extract_register_value(
|
|
||||||
reg_infos[reg_name], reg_bank, byte_order)
|
|
||||||
|
|
||||||
self.assertEqual(['0x0102030405060708'], get_reg_value('r8'))
|
|
||||||
self.assertEqual(['0x1112131415161718'], get_reg_value('r9'))
|
|
||||||
self.assertEqual(['0x2122232425262728'], get_reg_value('r10'))
|
|
||||||
self.assertEqual(['0x3132333435363738'], get_reg_value('r11'))
|
|
||||||
self.assertEqual(['0x4142434445464748'], get_reg_value('r12'))
|
|
||||||
self.assertEqual(['0x5152535455565758'], get_reg_value('r13'))
|
|
||||||
self.assertEqual(['0x6162636465666768'], get_reg_value('r14'))
|
|
||||||
self.assertEqual(['0x7172737475767778'], get_reg_value('r15'))
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
['0x020406080a0c0e01', '0x030507090b0d0f00'], get_reg_value('xmm8'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x121416181a1c1e11', '0x131517191b1d1f10'], get_reg_value('xmm9'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x222426282a2c2e21', '0x232527292b2d2f20'], get_reg_value('xmm10'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x323436383a3c3e31', '0x333537393b3d3f30'], get_reg_value('xmm11'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x424446484a4c4e41', '0x434547494b4d4f40'], get_reg_value('xmm12'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x525456585a5c5e51', '0x535557595b5d5f50'], get_reg_value('xmm13'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x626466686a6c6e61', '0x636567696b6d6f60'], get_reg_value('xmm14'))
|
|
||||||
self.assertEqual(
|
|
||||||
['0x727476787a7c7e71', '0x737577797b7d7f70'], get_reg_value('xmm15'))
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test_g_returns_correct_data_with_suffix_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
self.g_returns_correct_data(True)
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test_g_returns_correct_data_no_suffix_llgs(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
self.g_returns_correct_data(False)
|
|
|
@ -1,54 +0,0 @@
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
struct alignas(16) xmm_t {
|
|
||||||
uint64_t a, b;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
uint64_t r8 = 0x0102030405060708;
|
|
||||||
uint64_t r9 = 0x1112131415161718;
|
|
||||||
uint64_t r10 = 0x2122232425262728;
|
|
||||||
uint64_t r11 = 0x3132333435363738;
|
|
||||||
uint64_t r12 = 0x4142434445464748;
|
|
||||||
uint64_t r13 = 0x5152535455565758;
|
|
||||||
uint64_t r14 = 0x6162636465666768;
|
|
||||||
uint64_t r15 = 0x7172737475767778;
|
|
||||||
|
|
||||||
xmm_t xmm8 = {0x020406080A0C0E01, 0x030507090B0D0F00};
|
|
||||||
xmm_t xmm9 = {0x121416181A1C1E11, 0x131517191B1D1F10};
|
|
||||||
xmm_t xmm10 = {0x222426282A2C2E21, 0x232527292B2D2F20};
|
|
||||||
xmm_t xmm11 = {0x323436383A3C3E31, 0x333537393B3D3F30};
|
|
||||||
xmm_t xmm12 = {0x424446484A4C4E41, 0x434547494B4D4F40};
|
|
||||||
xmm_t xmm13 = {0x525456585A5C5E51, 0x535557595B5D5F50};
|
|
||||||
xmm_t xmm14 = {0x626466686A6C6E61, 0x636567696B6D6F60};
|
|
||||||
xmm_t xmm15 = {0x727476787A7C7E71, 0x737577797B7D7F70};
|
|
||||||
|
|
||||||
asm volatile("movq %0, %%r8\n\t"
|
|
||||||
"movq %1, %%r9\n\t"
|
|
||||||
"movq %2, %%r10\n\t"
|
|
||||||
"movq %3, %%r11\n\t"
|
|
||||||
"movq %4, %%r12\n\t"
|
|
||||||
"movq %5, %%r13\n\t"
|
|
||||||
"movq %6, %%r14\n\t"
|
|
||||||
"movq %7, %%r15\n\t"
|
|
||||||
"\n\t"
|
|
||||||
"movaps %8, %%xmm8\n\t"
|
|
||||||
"movaps %9, %%xmm9\n\t"
|
|
||||||
"movaps %10, %%xmm10\n\t"
|
|
||||||
"movaps %11, %%xmm11\n\t"
|
|
||||||
"movaps %12, %%xmm12\n\t"
|
|
||||||
"movaps %13, %%xmm13\n\t"
|
|
||||||
"movaps %14, %%xmm14\n\t"
|
|
||||||
"movaps %15, %%xmm15\n\t"
|
|
||||||
"\n\t"
|
|
||||||
"int3"
|
|
||||||
:
|
|
||||||
: "g"(r8), "g"(r9), "g"(r10), "g"(r11), "g"(r12), "g"(r13),
|
|
||||||
"g"(r14), "g"(r15), "m"(xmm8), "m"(xmm9), "m"(xmm10),
|
|
||||||
"m"(xmm11), "m"(xmm12), "m"(xmm13), "m"(xmm14), "m"(xmm15)
|
|
||||||
: "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
|
|
||||||
"%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13",
|
|
||||||
"%xmm14", "%xmm15");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,115 +0,0 @@
|
||||||
# This test makes sure that lldb-server supports and properly handles
|
|
||||||
# QPassSignals GDB protocol package.
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
class TestGdbRemote_QPassSignals(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def expect_signal(self, expected_signo):
|
|
||||||
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)
|
|
||||||
|
|
||||||
def expect_exit_code(self, exit_code):
|
|
||||||
self.test_sequence.add_log_lines(
|
|
||||||
["read packet: $vCont;c#a8",
|
|
||||||
"send packet: $W{0:02x}#00".format(exit_code)],
|
|
||||||
True)
|
|
||||||
self.expect_gdbremote_sequence()
|
|
||||||
|
|
||||||
|
|
||||||
def ignore_signals(self, signals):
|
|
||||||
def signal_name_to_hex(signame):
|
|
||||||
return format(lldbutil.get_signal_number(signame), 'x')
|
|
||||||
signals_str = ";".join(map(signal_name_to_hex, signals))
|
|
||||||
|
|
||||||
self.test_sequence.add_log_lines(["read packet: $QPassSignals:"
|
|
||||||
+ signals_str + " #00",
|
|
||||||
"send packet: $OK#00"],
|
|
||||||
True)
|
|
||||||
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
@skipUnlessPlatform(["linux", "android"])
|
|
||||||
def test_q_pass_signals(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
expected_signals = ["SIGSEGV",
|
|
||||||
"SIGALRM", "SIGFPE", "SIGBUS", "SIGINT", "SIGHUP"]
|
|
||||||
signals_to_ignore = ["SIGUSR1", "SIGUSR2"]
|
|
||||||
self.ignore_signals(signals_to_ignore)
|
|
||||||
for signal_name in expected_signals:
|
|
||||||
signo = lldbutil.get_signal_number(signal_name)
|
|
||||||
self.expect_signal(signo)
|
|
||||||
self.expect_exit_code(len(signals_to_ignore))
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
@skipUnlessPlatform(["linux", "android"])
|
|
||||||
def test_change_signals_at_runtime(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
expected_signals = ["SIGSEGV", "SIGUSR1", "SIGUSR2",
|
|
||||||
"SIGALRM", "SIGHUP"]
|
|
||||||
signals_to_ignore = ["SIGFPE", "SIGBUS", "SIGINT"]
|
|
||||||
|
|
||||||
for signal_name in expected_signals:
|
|
||||||
signo = lldbutil.get_signal_number(signal_name)
|
|
||||||
self.expect_signal(signo)
|
|
||||||
if signal_name == "SIGALRM":
|
|
||||||
self.ignore_signals(signals_to_ignore)
|
|
||||||
self.expect_exit_code(len(signals_to_ignore))
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test_default_signals_behavior(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
expected_signals = ["SIGSEGV", "SIGUSR1", "SIGUSR2",
|
|
||||||
"SIGALRM", "SIGFPE", "SIGBUS", "SIGINT", "SIGHUP"]
|
|
||||||
for signal_name in expected_signals:
|
|
||||||
signo = lldbutil.get_signal_number(signal_name)
|
|
||||||
self.expect_signal(signo)
|
|
||||||
self.expect_exit_code(0)
|
|
||||||
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
@skipUnlessPlatform(["linux", "android"])
|
|
||||||
def test_support_q_pass_signals(self):
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
|
|
||||||
# Start up the stub and start/prep the inferior.
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
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 and check QPassSignals+
|
|
||||||
supported_dict = self.parse_qSupported_response(context)
|
|
||||||
self.assertEqual(supported_dict["QPassSignals"], "+")
|
|
|
@ -1,36 +0,0 @@
|
||||||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
static int signal_counter = 0;
|
|
||||||
|
|
||||||
static void count_signal(int signo) {
|
|
||||||
++signal_counter;
|
|
||||||
printf("Signal %d\n", signo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void raise_signals() {
|
|
||||||
std::vector<int> signals(
|
|
||||||
{SIGSEGV, SIGUSR1, SIGUSR2, SIGALRM, SIGFPE, SIGBUS, SIGINT, SIGHUP});
|
|
||||||
|
|
||||||
for (int signal_num : signals) {
|
|
||||||
signal(signal_num, count_signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int signal_num : signals) {
|
|
||||||
raise(signal_num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
raise_signals();
|
|
||||||
return signal_counter;
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
|
||||||
import select
|
|
||||||
import threading
|
|
||||||
import traceback
|
|
||||||
import codecs
|
|
||||||
|
|
||||||
from six.moves import queue
|
|
||||||
from lldbsuite.support import seven
|
|
||||||
|
|
||||||
|
|
||||||
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 seven.unhexlify(packet_contents[1:])
|
|
||||||
|
|
||||||
|
|
||||||
def _dump_queue(the_queue):
|
|
||||||
while not the_queue.empty():
|
|
||||||
print(codecs.encode(the_queue.get(True), "string_escape"))
|
|
||||||
print("\n")
|
|
||||||
|
|
||||||
|
|
||||||
class PumpQueues(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._output_queue = queue.Queue()
|
|
||||||
self._packet_queue = queue.Queue()
|
|
||||||
|
|
||||||
def output_queue(self):
|
|
||||||
return self._output_queue
|
|
||||||
|
|
||||||
def packet_queue(self):
|
|
||||||
return self._packet_queue
|
|
||||||
|
|
||||||
def verify_queues_empty(self):
|
|
||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
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, pump_queues, logger=None):
|
|
||||||
if not pump_socket:
|
|
||||||
raise Exception("pump_socket cannot be None")
|
|
||||||
|
|
||||||
self._thread = None
|
|
||||||
self._stop_thread = False
|
|
||||||
self._socket = pump_socket
|
|
||||||
self._logger = logger
|
|
||||||
self._receive_buffer = ""
|
|
||||||
self._accumulated_output = ""
|
|
||||||
self._pump_queues = pump_queues
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
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 _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._pump_queues.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._pump_queues.output_queue().put(self._accumulated_output)
|
|
||||||
else:
|
|
||||||
# Any packet other than $O.
|
|
||||||
self._pump_queues.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 = seven.bitcast_to_string(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\n" +
|
|
||||||
traceback.format_exc(3))
|
|
||||||
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
|
|
|
@ -1,65 +0,0 @@
|
||||||
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
|
|
|
@ -1,6 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
ENABLE_THREADS := YES
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,41 +0,0 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import gdbremote_testcase
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
|
|
||||||
|
|
||||||
class TestGdbRemoteThreadName(gdbremote_testcase.GdbRemoteTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def run_and_check_name(self, expected_name):
|
|
||||||
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: "signal",
|
|
||||||
2: "key_vals_text"}},
|
|
||||||
],
|
|
||||||
True)
|
|
||||||
|
|
||||||
context = self.expect_gdbremote_sequence()
|
|
||||||
self.assertIsNotNone(context)
|
|
||||||
|
|
||||||
sigint = lldbutil.get_signal_number("SIGINT")
|
|
||||||
self.assertEqual(sigint, int(context.get("signal"), 16))
|
|
||||||
kv_dict = self.parse_key_val_dict(context.get("key_vals_text"))
|
|
||||||
self.assertEqual(expected_name, kv_dict.get("name"))
|
|
||||||
|
|
||||||
@llgs_test
|
|
||||||
def test(self):
|
|
||||||
""" Make sure lldb-server can retrieve inferior thread name"""
|
|
||||||
self.init_llgs_test()
|
|
||||||
self.build()
|
|
||||||
self.set_inferior_startup_launch()
|
|
||||||
procs = self.prep_debug_monitor_and_inferior()
|
|
||||||
|
|
||||||
self.run_and_check_name("hello world")
|
|
||||||
self.run_and_check_name("goodbye world")
|
|
|
@ -1,22 +0,0 @@
|
||||||
#include <pthread.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
void set_thread_name(const char *name) {
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
::pthread_setname_np(name);
|
|
||||||
#elif defined(__FreeBSD__)
|
|
||||||
::pthread_set_name_np(::pthread_self(), name);
|
|
||||||
#elif defined(__linux__)
|
|
||||||
::pthread_setname_np(::pthread_self(), name);
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
::pthread_setname_np(::pthread_self(), "%s", name);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
set_thread_name("hello world");
|
|
||||||
raise(SIGINT);
|
|
||||||
set_thread_name("goodbye world");
|
|
||||||
raise(SIGINT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
lldb-vscode
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
C_SOURCES := main.c
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,193 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-vscode setBreakpoints request
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import unittest2
|
|
||||||
import vscode
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
import lldbvscode_testcase
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import tempfile
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def spawn_and_wait(program, delay):
|
|
||||||
if delay:
|
|
||||||
time.sleep(delay)
|
|
||||||
process = subprocess.Popen([program],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process.wait()
|
|
||||||
|
|
||||||
|
|
||||||
class TestVSCode_attach(lldbvscode_testcase.VSCodeTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
def set_and_hit_breakpoint(self, continueToExit=True):
|
|
||||||
source = 'main.c'
|
|
||||||
breakpoint1_line = line_number(source, '// breakpoint 1')
|
|
||||||
lines = [breakpoint1_line]
|
|
||||||
# Set breakoint in the thread function so we can step the threads
|
|
||||||
breakpoint_ids = self.set_source_breakpoints(source, lines)
|
|
||||||
self.assertEqual(len(breakpoint_ids), len(lines),
|
|
||||||
"expect correct number of breakpoints")
|
|
||||||
self.continue_to_breakpoints(breakpoint_ids)
|
|
||||||
if continueToExit:
|
|
||||||
self.continue_to_exit()
|
|
||||||
|
|
||||||
|
|
||||||
@skipIfWindows
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@skipIfNetBSD # Hangs on NetBSD as well
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_by_pid(self):
|
|
||||||
'''
|
|
||||||
Tests attaching to a process by process ID.
|
|
||||||
'''
|
|
||||||
self.build_and_create_debug_adaptor()
|
|
||||||
program = self.getBuildArtifact("a.out")
|
|
||||||
self.process = subprocess.Popen([program],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
self.attach(pid=self.process.pid)
|
|
||||||
self.set_and_hit_breakpoint(continueToExit=True)
|
|
||||||
|
|
||||||
@skipIfWindows
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@skipIfNetBSD # Hangs on NetBSD as well
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_by_name(self):
|
|
||||||
'''
|
|
||||||
Tests attaching to a process by process name.
|
|
||||||
'''
|
|
||||||
self.build_and_create_debug_adaptor()
|
|
||||||
orig_program = self.getBuildArtifact("a.out")
|
|
||||||
# Since we are going to attach by process name, we need a unique
|
|
||||||
# process name that has minimal chance to match a process that is
|
|
||||||
# already running. To do this we use tempfile.mktemp() to give us a
|
|
||||||
# full path to a location where we can copy our executable. We then
|
|
||||||
# run this copy to ensure we don't get the error "more that one
|
|
||||||
# process matches 'a.out'".
|
|
||||||
program = tempfile.mktemp()
|
|
||||||
shutil.copyfile(orig_program, program)
|
|
||||||
shutil.copymode(orig_program, program)
|
|
||||||
|
|
||||||
def cleanup():
|
|
||||||
if os.path.exists(program):
|
|
||||||
os.unlink(program)
|
|
||||||
# Execute the cleanup function during test case tear down.
|
|
||||||
self.addTearDownHook(cleanup)
|
|
||||||
|
|
||||||
self.process = subprocess.Popen([program],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
# Wait for a bit to ensure the process is launched, but not for so long
|
|
||||||
# that the process has already finished by the time we attach.
|
|
||||||
time.sleep(3)
|
|
||||||
self.attach(program=program)
|
|
||||||
self.set_and_hit_breakpoint(continueToExit=True)
|
|
||||||
|
|
||||||
@skipUnlessDarwin
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@skipIfNetBSD # Hangs on NetBSD as well
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_by_name_waitFor(self):
|
|
||||||
'''
|
|
||||||
Tests attaching to a process by process name and waiting for the
|
|
||||||
next instance of a process to be launched, ingoring all current
|
|
||||||
ones.
|
|
||||||
'''
|
|
||||||
self.build_and_create_debug_adaptor()
|
|
||||||
program = self.getBuildArtifact("a.out")
|
|
||||||
self.spawn_thread = threading.Thread(target=spawn_and_wait,
|
|
||||||
args=(program, 1.0,))
|
|
||||||
self.spawn_thread.start()
|
|
||||||
self.attach(program=program, waitFor=True)
|
|
||||||
self.set_and_hit_breakpoint(continueToExit=True)
|
|
||||||
|
|
||||||
@skipIfWindows
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@skipIfNetBSD # Hangs on NetBSD as well
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_commands(self):
|
|
||||||
'''
|
|
||||||
Tests the "initCommands", "preRunCommands", "stopCommands",
|
|
||||||
"exitCommands", and "attachCommands" that can be passed during
|
|
||||||
attach.
|
|
||||||
|
|
||||||
"initCommands" are a list of LLDB commands that get executed
|
|
||||||
before the targt is created.
|
|
||||||
"preRunCommands" are a list of LLDB commands that get executed
|
|
||||||
after the target has been created and before the launch.
|
|
||||||
"stopCommands" are a list of LLDB commands that get executed each
|
|
||||||
time the program stops.
|
|
||||||
"exitCommands" are a list of LLDB commands that get executed when
|
|
||||||
the process exits
|
|
||||||
"attachCommands" are a list of LLDB commands that get executed and
|
|
||||||
must have a valid process in the selected target in LLDB after
|
|
||||||
they are done executing. This allows custom commands to create any
|
|
||||||
kind of debug session.
|
|
||||||
'''
|
|
||||||
self.build_and_create_debug_adaptor()
|
|
||||||
program = self.getBuildArtifact("a.out")
|
|
||||||
# Here we just create a target and launch the process as a way to test
|
|
||||||
# if we are able to use attach commands to create any kind of a target
|
|
||||||
# and use it for debugging
|
|
||||||
attachCommands = [
|
|
||||||
'target create -d "%s"' % (program),
|
|
||||||
'process launch -- arg1'
|
|
||||||
]
|
|
||||||
initCommands = ['target list', 'platform list']
|
|
||||||
preRunCommands = ['image list a.out', 'image dump sections a.out']
|
|
||||||
stopCommands = ['frame variable', 'bt']
|
|
||||||
exitCommands = ['expr 2+3', 'expr 3+4']
|
|
||||||
self.attach(program=program,
|
|
||||||
attachCommands=attachCommands,
|
|
||||||
initCommands=initCommands,
|
|
||||||
preRunCommands=preRunCommands,
|
|
||||||
stopCommands=stopCommands,
|
|
||||||
exitCommands=exitCommands)
|
|
||||||
|
|
||||||
# Get output from the console. This should contain both the
|
|
||||||
# "initCommands" and the "preRunCommands".
|
|
||||||
output = self.get_console()
|
|
||||||
# Verify all "initCommands" were found in console output
|
|
||||||
self.verify_commands('initCommands', output, initCommands)
|
|
||||||
# Verify all "preRunCommands" were found in console output
|
|
||||||
self.verify_commands('preRunCommands', output, preRunCommands)
|
|
||||||
|
|
||||||
functions = ['main']
|
|
||||||
breakpoint_ids = self.set_function_breakpoints(functions)
|
|
||||||
self.assertTrue(len(breakpoint_ids) == len(functions),
|
|
||||||
"expect one breakpoint")
|
|
||||||
self.continue_to_breakpoints(breakpoint_ids)
|
|
||||||
output = self.get_console(timeout=1.0)
|
|
||||||
self.verify_commands('stopCommands', output, stopCommands)
|
|
||||||
|
|
||||||
# Continue after launch and hit the "pause()" call and stop the target.
|
|
||||||
# Get output from the console. This should contain both the
|
|
||||||
# "stopCommands" that were run after we stop.
|
|
||||||
self.vscode.request_continue()
|
|
||||||
time.sleep(0.5)
|
|
||||||
self.vscode.request_pause()
|
|
||||||
self.vscode.wait_for_stopped()
|
|
||||||
output = self.get_console(timeout=1.0)
|
|
||||||
self.verify_commands('stopCommands', output, stopCommands)
|
|
||||||
|
|
||||||
# Continue until the program exits
|
|
||||||
self.continue_to_exit()
|
|
||||||
# Get output from the console. This should contain both the
|
|
||||||
# "exitCommands" that were run after the second breakpoint was hit
|
|
||||||
output = self.get_console(timeout=1.0)
|
|
||||||
self.verify_commands('exitCommands', output, exitCommands)
|
|
|
@ -1,11 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
lldb_enable_attach();
|
|
||||||
|
|
||||||
printf("pid = %i\n", getpid());
|
|
||||||
sleep(10);
|
|
||||||
return 0; // breakpoint 1
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
LEVEL = ../../../make
|
|
||||||
|
|
||||||
CXX_SOURCES := main.cpp
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.rules
|
|
|
@ -1,211 +0,0 @@
|
||||||
"""
|
|
||||||
Test lldb-vscode setBreakpoints request
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import pprint
|
|
||||||
import unittest2
|
|
||||||
import vscode
|
|
||||||
from lldbsuite.test.decorators import *
|
|
||||||
from lldbsuite.test.lldbtest import *
|
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
import lldbvscode_testcase
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class TestVSCode_setBreakpoints(lldbvscode_testcase.VSCodeTestCaseBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
|
||||||
|
|
||||||
@skipIfWindows
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_set_and_clear(self):
|
|
||||||
'''Tests setting and clearing source file and line breakpoints.
|
|
||||||
This packet is a bit tricky on the debug adaptor side since there
|
|
||||||
is no "clearBreakpoints" packet. Source file and line breakpoints
|
|
||||||
are set by sending a "setBreakpoints" packet with a source file
|
|
||||||
specified and zero or more source lines. If breakpoints have been
|
|
||||||
set in the source file before, any exising breakpoints must remain
|
|
||||||
set, and any new breakpoints must be created, and any breakpoints
|
|
||||||
that were in previous requests and are not in the current request
|
|
||||||
must be removed. This function tests this setting and clearing
|
|
||||||
and makes sure things happen correctly. It doesn't test hitting
|
|
||||||
breakpoints and the functionality of each breakpoint, like
|
|
||||||
'conditions' and 'hitCondition' settings.'''
|
|
||||||
source_basename = 'main.cpp'
|
|
||||||
source_path = os.path.join(os.getcwd(), source_basename)
|
|
||||||
first_line = line_number('main.cpp', 'break 12')
|
|
||||||
second_line = line_number('main.cpp', 'break 13')
|
|
||||||
third_line = line_number('main.cpp', 'break 14')
|
|
||||||
lines = [first_line, second_line, third_line]
|
|
||||||
|
|
||||||
# Visual Studio Code Debug Adaptors have no way to specify the file
|
|
||||||
# without launching or attaching to a process, so we must start a
|
|
||||||
# process in order to be able to set breakpoints.
|
|
||||||
program = self.getBuildArtifact("a.out")
|
|
||||||
self.build_and_launch(program)
|
|
||||||
|
|
||||||
# Set 3 breakoints and verify that they got set correctly
|
|
||||||
response = self.vscode.request_setBreakpoints(source_path, lines)
|
|
||||||
line_to_id = {}
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
for breakpoint in breakpoints:
|
|
||||||
line = breakpoint['line']
|
|
||||||
# Store the "id" of the breakpoint that was set for later
|
|
||||||
line_to_id[line] = breakpoint['id']
|
|
||||||
self.assertTrue(line in lines, "line expected in lines array")
|
|
||||||
self.assertTrue(breakpoint['verified'],
|
|
||||||
"expect breakpoint verified")
|
|
||||||
|
|
||||||
# There is no breakpoint delete packet, clients just send another
|
|
||||||
# setBreakpoints packet with the same source file with fewer lines.
|
|
||||||
# Below we remove the second line entry and call the setBreakpoints
|
|
||||||
# function again. We want to verify that any breakpoints that were set
|
|
||||||
# before still have the same "id". This means we didn't clear the
|
|
||||||
# breakpoint and set it again at the same location. We also need to
|
|
||||||
# verify that the second line location was actually removed.
|
|
||||||
lines.remove(second_line)
|
|
||||||
# Set 2 breakoints and verify that the previous breakoints that were
|
|
||||||
# set above are still set.
|
|
||||||
response = self.vscode.request_setBreakpoints(source_path, lines)
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
for breakpoint in breakpoints:
|
|
||||||
line = breakpoint['line']
|
|
||||||
# Verify the same breakpoints are still set within LLDB by
|
|
||||||
# making sure the breakpoint ID didn't change
|
|
||||||
self.assertTrue(line_to_id[line] == breakpoint['id'],
|
|
||||||
"verify previous breakpoints stayed the same")
|
|
||||||
self.assertTrue(line in lines, "line expected in lines array")
|
|
||||||
self.assertTrue(breakpoint['verified'],
|
|
||||||
"expect breakpoint still verified")
|
|
||||||
|
|
||||||
# Now get the full list of breakpoints set in the target and verify
|
|
||||||
# we have only 2 breakpoints set. The response above could have told
|
|
||||||
# us about 2 breakpoints, but we want to make sure we don't have the
|
|
||||||
# third one still set in the target
|
|
||||||
response = self.vscode.request_testGetTargetBreakpoints()
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
for breakpoint in breakpoints:
|
|
||||||
line = breakpoint['line']
|
|
||||||
# Verify the same breakpoints are still set within LLDB by
|
|
||||||
# making sure the breakpoint ID didn't change
|
|
||||||
self.assertTrue(line_to_id[line] == breakpoint['id'],
|
|
||||||
"verify previous breakpoints stayed the same")
|
|
||||||
self.assertTrue(line in lines, "line expected in lines array")
|
|
||||||
self.assertTrue(breakpoint['verified'],
|
|
||||||
"expect breakpoint still verified")
|
|
||||||
|
|
||||||
# Now clear all breakpoints for the source file by passing down an
|
|
||||||
# empty lines array
|
|
||||||
lines = []
|
|
||||||
response = self.vscode.request_setBreakpoints(source_path, lines)
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
|
|
||||||
# Verify with the target that all breakpoints have been cleared
|
|
||||||
response = self.vscode.request_testGetTargetBreakpoints()
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
|
|
||||||
# Now set a breakpoint again in the same source file and verify it
|
|
||||||
# was added.
|
|
||||||
lines = [second_line]
|
|
||||||
response = self.vscode.request_setBreakpoints(source_path, lines)
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
for breakpoint in breakpoints:
|
|
||||||
line = breakpoint['line']
|
|
||||||
self.assertTrue(line in lines, "line expected in lines array")
|
|
||||||
self.assertTrue(breakpoint['verified'],
|
|
||||||
"expect breakpoint still verified")
|
|
||||||
|
|
||||||
# Now get the full list of breakpoints set in the target and verify
|
|
||||||
# we have only 2 breakpoints set. The response above could have told
|
|
||||||
# us about 2 breakpoints, but we want to make sure we don't have the
|
|
||||||
# third one still set in the target
|
|
||||||
response = self.vscode.request_testGetTargetBreakpoints()
|
|
||||||
if response:
|
|
||||||
breakpoints = response['body']['breakpoints']
|
|
||||||
self.assertTrue(len(breakpoints) == len(lines),
|
|
||||||
"expect %u source breakpoints" % (len(lines)))
|
|
||||||
for breakpoint in breakpoints:
|
|
||||||
line = breakpoint['line']
|
|
||||||
self.assertTrue(line in lines, "line expected in lines array")
|
|
||||||
self.assertTrue(breakpoint['verified'],
|
|
||||||
"expect breakpoint still verified")
|
|
||||||
|
|
||||||
@skipIfWindows
|
|
||||||
@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots
|
|
||||||
@no_debug_info_test
|
|
||||||
def test_functionality(self):
|
|
||||||
'''Tests hitting breakpoints and the functionality of a single
|
|
||||||
breakpoint, like 'conditions' and 'hitCondition' settings.'''
|
|
||||||
source_basename = 'main.cpp'
|
|
||||||
source_path = os.path.join(os.getcwd(), source_basename)
|
|
||||||
loop_line = line_number('main.cpp', '// break loop')
|
|
||||||
|
|
||||||
program = self.getBuildArtifact("a.out")
|
|
||||||
self.build_and_launch(program)
|
|
||||||
# Set a breakpoint at the loop line with no condition and no
|
|
||||||
# hitCondition
|
|
||||||
breakpoint_ids = self.set_source_breakpoints(source_path, [loop_line])
|
|
||||||
self.assertTrue(len(breakpoint_ids) == 1, "expect one breakpoint")
|
|
||||||
self.vscode.request_continue()
|
|
||||||
|
|
||||||
# Verify we hit the breakpoint we just set
|
|
||||||
self.verify_breakpoint_hit(breakpoint_ids)
|
|
||||||
|
|
||||||
# Make sure i is zero at first breakpoint
|
|
||||||
i = int(self.vscode.get_local_variable_value('i'))
|
|
||||||
self.assertTrue(i == 0, 'i != 0 after hitting breakpoint')
|
|
||||||
|
|
||||||
# Update the condition on our breakpoint
|
|
||||||
new_breakpoint_ids = self.set_source_breakpoints(source_path,
|
|
||||||
[loop_line],
|
|
||||||
condition="i==4")
|
|
||||||
self.assertTrue(breakpoint_ids == new_breakpoint_ids,
|
|
||||||
"existing breakpoint should have its condition "
|
|
||||||
"updated")
|
|
||||||
|
|
||||||
self.continue_to_breakpoints(breakpoint_ids)
|
|
||||||
i = int(self.vscode.get_local_variable_value('i'))
|
|
||||||
self.assertTrue(i == 4,
|
|
||||||
'i != 4 showing conditional works')
|
|
||||||
|
|
||||||
new_breakpoint_ids = self.set_source_breakpoints(source_path,
|
|
||||||
[loop_line],
|
|
||||||
hitCondition="2")
|
|
||||||
|
|
||||||
self.assertTrue(breakpoint_ids == new_breakpoint_ids,
|
|
||||||
"existing breakpoint should have its condition "
|
|
||||||
"updated")
|
|
||||||
|
|
||||||
# Continue with a hitContidtion of 2 and expect it to skip 1 value
|
|
||||||
self.continue_to_breakpoints(breakpoint_ids)
|
|
||||||
i = int(self.vscode.get_local_variable_value('i'))
|
|
||||||
self.assertTrue(i == 6,
|
|
||||||
'i != 6 showing hitCondition works')
|
|
||||||
|
|
||||||
# continue after hitting our hitCondition and make sure it only goes
|
|
||||||
# up by 1
|
|
||||||
self.continue_to_breakpoints(breakpoint_ids)
|
|
||||||
i = int(self.vscode.get_local_variable_value('i'))
|
|
||||||
self.assertTrue(i == 7,
|
|
||||||
'i != 7 showing post hitCondition hits every time')
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue