mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 16:36:06 +00:00

This reverts commit f0c16f89124f2dc0630162ff9ea23934f5b2b75b because it breaks linux and mac bots.
455 lines
19 KiB
Python
455 lines
19 KiB
Python
"""
|
|
Test lldb-vscode setBreakpoints request
|
|
"""
|
|
|
|
|
|
import vscode
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
import lldbvscode_testcase
|
|
import time
|
|
import os
|
|
|
|
|
|
class TestVSCode_launch(lldbvscode_testcase.VSCodeTestCaseBase):
|
|
|
|
@skipIfWindows
|
|
@skipIfDarwin # Flaky
|
|
@skipIfRemote
|
|
def test_default(self):
|
|
'''
|
|
Tests the default launch of a simple program. No arguments,
|
|
environment, or anything else is specified.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program)
|
|
self.continue_to_exit()
|
|
# Now get the STDOUT and verify our program argument is correct
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect program output")
|
|
lines = output.splitlines()
|
|
self.assertIn(program, lines[0],
|
|
"make sure program path is in first argument")
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_termination(self):
|
|
'''
|
|
Tests the correct termination of lldb-vscode upon a 'disconnect'
|
|
request.
|
|
'''
|
|
self.create_debug_adaptor()
|
|
# The underlying lldb-vscode process must be alive
|
|
self.assertEqual(self.vscode.process.poll(), None)
|
|
|
|
# The lldb-vscode process should finish even though
|
|
# we didn't close the communication socket explicitly
|
|
self.vscode.request_disconnect()
|
|
|
|
# Wait until the underlying lldb-vscode process dies.
|
|
# We need to do this because the popen.wait function in python2.7
|
|
# doesn't have a timeout argument.
|
|
for _ in range(10):
|
|
time.sleep(1)
|
|
if self.vscode.process.poll() is not None:
|
|
break
|
|
# Check the return code
|
|
self.assertEqual(self.vscode.process.poll(), 0)
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_stopOnEntry(self):
|
|
'''
|
|
Tests the default launch of a simple program that stops at the
|
|
entry point instead of continuing.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program, stopOnEntry=True)
|
|
self.set_function_breakpoints(['main'])
|
|
stopped_events = self.continue_to_next_stop()
|
|
for stopped_event in stopped_events:
|
|
if 'body' in stopped_event:
|
|
body = stopped_event['body']
|
|
if 'reason' in body:
|
|
reason = body['reason']
|
|
self.assertNotEqual(
|
|
reason, 'breakpoint',
|
|
'verify stop isn\'t "main" breakpoint')
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_cwd(self):
|
|
'''
|
|
Tests the default launch of a simple program with a current working
|
|
directory.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
program_parent_dir = os.path.realpath(
|
|
os.path.dirname(os.path.dirname(program)))
|
|
self.build_and_launch(program,
|
|
cwd=program_parent_dir)
|
|
self.continue_to_exit()
|
|
# Now get the STDOUT and verify our program argument is correct
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect program output")
|
|
lines = output.splitlines()
|
|
found = False
|
|
for line in lines:
|
|
if line.startswith('cwd = \"'):
|
|
quote_path = '"%s"' % (program_parent_dir)
|
|
found = True
|
|
self.assertIn(quote_path, line,
|
|
"working directory '%s' not in '%s'" % (
|
|
program_parent_dir, line))
|
|
self.assertTrue(found, "verified program working directory")
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_debuggerRoot(self):
|
|
'''
|
|
Tests the "debuggerRoot" will change the working directory of
|
|
the lldb-vscode debug adaptor.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
program_parent_dir = os.path.realpath(
|
|
os.path.dirname(os.path.dirname(program)))
|
|
commands = ['platform shell echo cwd = $PWD']
|
|
self.build_and_launch(program,
|
|
debuggerRoot=program_parent_dir,
|
|
initCommands=commands)
|
|
output = self.get_console()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect console output")
|
|
lines = output.splitlines()
|
|
prefix = 'cwd = '
|
|
found = False
|
|
for line in lines:
|
|
if line.startswith(prefix):
|
|
found = True
|
|
self.assertEquals(program_parent_dir, line[len(prefix):],
|
|
"lldb-vscode working dir '%s' == '%s'" % (
|
|
program_parent_dir, line[6:]))
|
|
self.assertTrue(found, "verified lldb-vscode working directory")
|
|
self.continue_to_exit()
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_sourcePath(self):
|
|
'''
|
|
Tests the "sourcePath" will set the target.source-map.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
program_dir = os.path.dirname(program)
|
|
self.build_and_launch(program,
|
|
sourcePath=program_dir)
|
|
output = self.get_console()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect console output")
|
|
lines = output.splitlines()
|
|
prefix = '(lldb) settings set target.source-map "." '
|
|
found = False
|
|
for line in lines:
|
|
if line.startswith(prefix):
|
|
found = True
|
|
quoted_path = '"%s"' % (program_dir)
|
|
self.assertEquals(quoted_path, line[len(prefix):],
|
|
"lldb-vscode working dir %s == %s" % (
|
|
quoted_path, line[6:]))
|
|
self.assertTrue(found, 'found "sourcePath" in console output')
|
|
self.continue_to_exit()
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_disableSTDIO(self):
|
|
'''
|
|
Tests the default launch of a simple program with STDIO disabled.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program,
|
|
disableSTDIO=True)
|
|
self.continue_to_exit()
|
|
# Now get the STDOUT and verify our program argument is correct
|
|
output = self.get_stdout()
|
|
self.assertEquals(output, None,
|
|
"expect no program output")
|
|
|
|
@skipIfWindows
|
|
@skipIfLinux # shell argument expansion doesn't seem to work on Linux
|
|
@expectedFailureAll(oslist=["freebsd", "netbsd"],
|
|
bugnumber="llvm.org/pr48349")
|
|
@skipIfRemote
|
|
def test_shellExpandArguments_enabled(self):
|
|
'''
|
|
Tests the default launch of a simple program with shell expansion
|
|
enabled.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
program_dir = os.path.dirname(program)
|
|
glob = os.path.join(program_dir, '*.out')
|
|
self.build_and_launch(program, args=[glob], shellExpandArguments=True)
|
|
self.continue_to_exit()
|
|
# Now get the STDOUT and verify our program argument is correct
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect no program output")
|
|
lines = output.splitlines()
|
|
for line in lines:
|
|
quote_path = '"%s"' % (program)
|
|
if line.startswith("arg[1] ="):
|
|
self.assertIn(quote_path, line,
|
|
'verify "%s" expanded to "%s"' % (
|
|
glob, program))
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_shellExpandArguments_disabled(self):
|
|
'''
|
|
Tests the default launch of a simple program with shell expansion
|
|
disabled.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
program_dir = os.path.dirname(program)
|
|
glob = os.path.join(program_dir, '*.out')
|
|
self.build_and_launch(program,
|
|
args=[glob],
|
|
shellExpandArguments=False)
|
|
self.continue_to_exit()
|
|
# Now get the STDOUT and verify our program argument is correct
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect no program output")
|
|
lines = output.splitlines()
|
|
for line in lines:
|
|
quote_path = '"%s"' % (glob)
|
|
if line.startswith("arg[1] ="):
|
|
self.assertIn(quote_path, line,
|
|
'verify "%s" stayed to "%s"' % (
|
|
glob, glob))
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_args(self):
|
|
'''
|
|
Tests launch of a simple program with arguments
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
args = ["one", "with space", "'with single quotes'",
|
|
'"with double quotes"']
|
|
self.build_and_launch(program,
|
|
args=args)
|
|
self.continue_to_exit()
|
|
|
|
# Now get the STDOUT and verify our arguments got passed correctly
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect program output")
|
|
lines = output.splitlines()
|
|
# Skip the first argument that contains the program name
|
|
lines.pop(0)
|
|
# Make sure arguments we specified are correct
|
|
for (i, arg) in enumerate(args):
|
|
quoted_arg = '"%s"' % (arg)
|
|
self.assertIn(quoted_arg, lines[i],
|
|
'arg[%i] "%s" not in "%s"' % (i+1, quoted_arg, lines[i]))
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_environment(self):
|
|
'''
|
|
Tests launch of a simple program with environment variables
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=",
|
|
"SPACE=Hello World"]
|
|
self.build_and_launch(program,
|
|
env=env)
|
|
self.continue_to_exit()
|
|
|
|
# Now get the STDOUT and verify our arguments got passed correctly
|
|
output = self.get_stdout()
|
|
self.assertTrue(output and len(output) > 0,
|
|
"expect program output")
|
|
lines = output.splitlines()
|
|
# Skip the all arguments so we have only environment vars left
|
|
while len(lines) and lines[0].startswith("arg["):
|
|
lines.pop(0)
|
|
# Make sure each environment variable in "env" is actually set in the
|
|
# program environment that was printed to STDOUT
|
|
for var in env:
|
|
found = False
|
|
for program_var in lines:
|
|
if var in program_var:
|
|
found = True
|
|
break
|
|
self.assertTrue(found,
|
|
'"%s" must exist in program environment (%s)' % (
|
|
var, lines))
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
@skipIf(archs=["arm", "aarch64"]) # failed run https://lab.llvm.org/buildbot/#/builders/96/builds/6933
|
|
def test_commands(self):
|
|
'''
|
|
Tests the "initCommands", "preRunCommands", "stopCommands",
|
|
"terminateCommands" and "exitCommands" that can be passed during
|
|
launch.
|
|
|
|
"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
|
|
"terminateCommands" are a list of LLDB commands that get executed when
|
|
the debugger session terminates.
|
|
'''
|
|
program = self.getBuildArtifact("a.out")
|
|
initCommands = ['target list', 'platform list']
|
|
preRunCommands = ['image list a.out', 'image dump sections a.out']
|
|
postRunCommands = ['help trace', 'help process trace']
|
|
stopCommands = ['frame variable', 'bt']
|
|
exitCommands = ['expr 2+3', 'expr 3+4']
|
|
terminateCommands = ['expr 4+2']
|
|
self.build_and_launch(program,
|
|
initCommands=initCommands,
|
|
preRunCommands=preRunCommands,
|
|
postRunCommands=postRunCommands,
|
|
stopCommands=stopCommands,
|
|
exitCommands=exitCommands,
|
|
terminateCommands=terminateCommands)
|
|
|
|
# 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)
|
|
# Verify all "postRunCommands" were found in console output
|
|
self.verify_commands('postRunCommands', output, postRunCommands)
|
|
|
|
source = 'main.c'
|
|
first_line = line_number(source, '// breakpoint 1')
|
|
second_line = line_number(source, '// breakpoint 2')
|
|
lines = [first_line, second_line]
|
|
|
|
# Set 2 breakpoints so we can verify that "stopCommands" get run as the
|
|
# breakpoints get hit
|
|
breakpoint_ids = self.set_source_breakpoints(source, lines)
|
|
self.assertEquals(len(breakpoint_ids), len(lines),
|
|
"expect correct number of breakpoints")
|
|
|
|
# Continue after launch and hit the first breakpoint.
|
|
# Get output from the console. This should contain both the
|
|
# "stopCommands" that were run after the first breakpoint was hit
|
|
self.continue_to_breakpoints(breakpoint_ids)
|
|
output = self.get_console(timeout=1.0)
|
|
self.verify_commands('stopCommands', output, stopCommands)
|
|
|
|
# Continue again and hit the second breakpoint.
|
|
# Get output from the console. This should contain both the
|
|
# "stopCommands" that were run after the second breakpoint was hit
|
|
self.continue_to_breakpoints(breakpoint_ids)
|
|
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
|
|
# and the "terminateCommands" due to the debugging session ending
|
|
output = self.collect_console(duration=1.0)
|
|
self.verify_commands('exitCommands', output, exitCommands)
|
|
self.verify_commands('terminateCommands', output, terminateCommands)
|
|
|
|
@skipIfWindows
|
|
@skipIfRemote
|
|
def test_extra_launch_commands(self):
|
|
'''
|
|
Tests the "launchCommands" with extra launching settings
|
|
'''
|
|
self.build_and_create_debug_adaptor()
|
|
program = self.getBuildArtifact("a.out")
|
|
|
|
source = 'main.c'
|
|
first_line = line_number(source, '// breakpoint 1')
|
|
second_line = line_number(source, '// breakpoint 2')
|
|
# Set target binary and 2 breakpoints
|
|
# then we can varify the "launchCommands" get run
|
|
# also we can verify that "stopCommands" get run as the
|
|
# breakpoints get hit
|
|
launchCommands = [
|
|
'target create "%s"' % (program),
|
|
'breakpoint s -f main.c -l %d' % first_line,
|
|
'breakpoint s -f main.c -l %d' % second_line,
|
|
'process launch --stop-at-entry'
|
|
]
|
|
|
|
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.launch(program,
|
|
initCommands=initCommands,
|
|
preRunCommands=preRunCommands,
|
|
stopCommands=stopCommands,
|
|
exitCommands=exitCommands,
|
|
launchCommands=launchCommands)
|
|
|
|
# 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)
|
|
|
|
# Verify all "launchCommands" were founc in console output
|
|
# After execution, program should launch
|
|
self.verify_commands('launchCommands', output, launchCommands)
|
|
# Verify the "stopCommands" here
|
|
self.continue_to_next_stop()
|
|
output = self.get_console(timeout=1.0)
|
|
self.verify_commands('stopCommands', output, stopCommands)
|
|
|
|
# Continue and hit the second breakpoint.
|
|
# Get output from the console. This should contain both the
|
|
# "stopCommands" that were run after the first breakpoint was hit
|
|
self.continue_to_next_stop()
|
|
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)
|
|
|
|
@skipIfWindows
|
|
@skipIfNetBSD # Hangs on NetBSD as well
|
|
@skipIfDarwin
|
|
@skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5540/steps/test/logs/stdio
|
|
def test_terminate_commands(self):
|
|
'''
|
|
Tests that the "terminateCommands", that can be passed during
|
|
launch, are run when the debugger is disconnected.
|
|
'''
|
|
self.build_and_create_debug_adaptor()
|
|
program = self.getBuildArtifact("a.out")
|
|
|
|
terminateCommands = ['expr 4+2']
|
|
self.launch(program=program,
|
|
terminateCommands=terminateCommands)
|
|
self.get_console()
|
|
# Once it's disconnected the console should contain the
|
|
# "terminateCommands"
|
|
self.vscode.request_disconnect(terminateDebuggee=True)
|
|
output = self.collect_console(duration=1.0)
|
|
self.verify_commands('terminateCommands', output, terminateCommands)
|