diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /packages | |
parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
download | src-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz src-14f1b3e8826ce43b978db93a62d1166055db5394.zip |
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=311128
svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'packages')
879 files changed, 33621 insertions, 14456 deletions
diff --git a/packages/Python/lldbsuite/.clang-format b/packages/Python/lldbsuite/.clang-format new file mode 100644 index 000000000000..7de7a512ad7e --- /dev/null +++ b/packages/Python/lldbsuite/.clang-format @@ -0,0 +1,4 @@ +DisableFormat: true + +# Disabling formatting doesn't implicitly disable include sorting +SortIncludes: false diff --git a/packages/Python/lldbsuite/__init__.py b/packages/Python/lldbsuite/__init__.py index aa6874e78bc2..4b59e4119b2a 100644 --- a/packages/Python/lldbsuite/__init__.py +++ b/packages/Python/lldbsuite/__init__.py @@ -4,6 +4,7 @@ import inspect import os import sys + def find_lldb_root(): lldb_root = os.path.dirname(inspect.getfile(inspect.currentframe())) while True: diff --git a/packages/Python/lldbsuite/pre_kill_hook/README.md b/packages/Python/lldbsuite/pre_kill_hook/README.md new file mode 100644 index 000000000000..921eedb4a869 --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/README.md @@ -0,0 +1,55 @@ +# pre\_kill\_hook package + +## Overview + +The pre\_kill\_hook package provides a per-platform method for running code +after a test process times out but before the concurrent test runner kills the +timed-out process. + +## Detailed Description of Usage + +If a platform defines the hook, then the hook gets called right after a timeout +is detected in a test run, but before the process is killed. + +The pre-kill-hook mechanism works as follows: + +* When a timeout is detected in the process_control.ProcessDriver class that + runs the per-test lldb process, a new overridable on\_timeout\_pre\_kill() method + is called on the ProcessDriver instance. + +* The concurrent test driver's derived ProcessDriver overrides this method. It + looks to see if a module called + "lldbsuite.pre\_kill\_hook.{platform-system-name}" module exists, where + platform-system-name is replaced with platform.system().lower(). (e.g. + "Darwin" becomes the darwin.py module). + + * If that module doesn't exist, the rest of the new behavior is skipped. + + * If that module does exist, it is loaded, and the method + "do\_pre\_kill(process\_id, context\_dict, output\_stream)" is called. If + that method throws an exception, we log it and we ignore further processing + of the pre-killed process. + + * The process\_id argument of the do\_pre\_kill function is the process id as + returned by the ProcessDriver.pid property. + + * The output\_stream argument of the do\_pre\_kill function takes a file-like + object. Output to be collected from doing any processing on the + process-to-be-killed should be written into the file-like object. The + current impl uses a six.StringIO and then writes this output to + {TestFilename}-{pid}.sample in the session directory. + +* Platforms where platform.system() is "Darwin" will get a pre-kill action that + runs the 'sample' program on the lldb that has timed out. That data will be + collected on CI and analyzed to determine what is happening during timeouts. + (This has an advantage over a core in that it is much smaller and that it + clearly demonstrates any liveness of the process, if there is any). + +## Running the tests + +To run the tests in the pre\_kill\_hook package, open a console, change into +this directory and run the following: + +``` +python -m unittest discover +``` diff --git a/packages/Python/lldbsuite/pre_kill_hook/__init__.py b/packages/Python/lldbsuite/pre_kill_hook/__init__.py new file mode 100644 index 000000000000..c3a852ea1bfe --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/__init__.py @@ -0,0 +1 @@ +"""Initialize the package.""" diff --git a/packages/Python/lldbsuite/pre_kill_hook/darwin.py b/packages/Python/lldbsuite/pre_kill_hook/darwin.py new file mode 100644 index 000000000000..2bee65a01e3f --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/darwin.py @@ -0,0 +1,46 @@ +"""Provides a pre-kill method to run on macOS.""" +from __future__ import print_function + +# system imports +import subprocess +import sys + +# third-party module imports +import six + + +def do_pre_kill(process_id, runner_context, output_stream, sample_time=3): + """Samples the given process id, and puts the output to output_stream. + + @param process_id the local process to sample. + + @param runner_context a dictionary of details about the architectures + and platform on which the given process is running. Expected keys are + archs (array of architectures), platform_name, platform_url, and + platform_working_dir. + + @param output_stream file-like object that should be used to write the + results of sampling. + + @param sample_time specifies the time in seconds that should be captured. + """ + + # Validate args. + if runner_context is None: + raise Exception("runner_context argument is required") + if not isinstance(runner_context, dict): + raise Exception("runner_context argument must be a dictionary") + + # We will try to run sample on the local host only if there is no URL + # to a remote. + if "platform_url" in runner_context and ( + runner_context["platform_url"] is not None): + import pprint + sys.stderr.write( + "warning: skipping timeout pre-kill sample invocation because we " + "don't know how to run on a remote yet. runner_context={}\n" + .format(pprint.pformat(runner_context))) + + output = subprocess.check_output(['sample', six.text_type(process_id), + str(sample_time)]) + output_stream.write(output) diff --git a/packages/Python/lldbsuite/pre_kill_hook/linux.py b/packages/Python/lldbsuite/pre_kill_hook/linux.py new file mode 100644 index 000000000000..d4cd9be27c82 --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/linux.py @@ -0,0 +1,76 @@ +"""Provides a pre-kill method to run on Linux. + +This timeout pre-kill method relies on the Linux perf-tools +distribution. The appropriate way to obtain this set of tools +will depend on the Linux distribution. + +For Ubuntu 16.04, the invoke the following command: +sudo apt-get install perf-tools-unstable +""" +from __future__ import print_function + +# system imports +import os +import subprocess +import sys +import tempfile + + +def do_pre_kill(process_id, runner_context, output_stream, sample_time=3): + """Samples the given process id, and puts the output to output_stream. + + @param process_id the local process to sample. + + @param runner_context a dictionary of details about the architectures + and platform on which the given process is running. Expected keys are + archs (array of architectures), platform_name, platform_url, and + platform_working_dir. + + @param output_stream file-like object that should be used to write the + results of sampling. + + @param sample_time specifies the time in seconds that should be captured. + """ + + # Validate args. + if runner_context is None: + raise Exception("runner_context argument is required") + if not isinstance(runner_context, dict): + raise Exception("runner_context argument must be a dictionary") + + # We will try to run sample on the local host only if there is no URL + # to a remote. + if "platform_url" in runner_context and ( + runner_context["platform_url"] is not None): + import pprint + sys.stderr.write( + "warning: skipping timeout pre-kill sample invocation because we " + "don't know how to run on a remote yet. runner_context={}\n" + .format(pprint.pformat(runner_context))) + + # We're going to create a temp file, and immediately overwrite it with the + # following command. This just ensures we don't have any races in + # creation of the temporary sample file. + fileno, filename = tempfile.mkstemp(suffix='perfdata') + os.close(fileno) + fileno = None + + try: + with open(os.devnull, 'w') as devnull: + returncode = subprocess.call(['timeout', str(sample_time), 'perf', + 'record', '-g', '-o', filename, '-p', str(process_id)], + stdout=devnull, stderr=devnull) + if returncode == 0 or returncode == 124: + # This is okay - this is the timeout return code, which is totally + # expected. + pass + else: + raise Exception("failed to call 'perf record .., error: {}".format( + returncode)) + + with open(os.devnull, 'w') as devnull: + output = subprocess.check_output(['perf', 'report', '--call-graph', + '--stdio', '-i', filename], stderr=devnull) + output_stream.write(output) + finally: + os.remove(filename) diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py b/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py b/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py new file mode 100644 index 000000000000..810b364b07c3 --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py @@ -0,0 +1,107 @@ +"""Test the pre-kill hook on Darwin.""" +from __future__ import print_function + +# system imports +from multiprocessing import Process, Queue +import platform +import re +from unittest import main, TestCase + +# third party +from six import StringIO + + +def do_child_process(child_work_queue, parent_work_queue, verbose): + import os + + pid = os.getpid() + if verbose: + print("child: pid {} started, sending to parent".format(pid)) + parent_work_queue.put(pid) + if verbose: + print("child: waiting for shut-down request from parent") + child_work_queue.get() + if verbose: + print("child: received shut-down request. Child exiting.") + + +class DarwinPreKillTestCase(TestCase): + + def __init__(self, methodName): + super(DarwinPreKillTestCase, self).__init__(methodName) + self.process = None + self.child_work_queue = None + self.verbose = False + + def tearDown(self): + if self.verbose: + print("parent: sending shut-down request to child") + if self.process: + self.child_work_queue.put("hello, child") + self.process.join() + if self.verbose: + print("parent: child is fully shut down") + + def test_sample(self): + # Ensure we're Darwin. + if platform.system() != 'Darwin': + self.skipTest("requires a Darwin-based OS") + + # Start the child process. + self.child_work_queue = Queue() + parent_work_queue = Queue() + self.process = Process(target=do_child_process, + args=(self.child_work_queue, parent_work_queue, + self.verbose)) + if self.verbose: + print("parent: starting child") + self.process.start() + + # Wait for the child to report its pid. Then we know we're running. + if self.verbose: + print("parent: waiting for child to start") + child_pid = parent_work_queue.get() + + # Sample the child process. + from darwin import do_pre_kill + context_dict = { + "archs": [platform.machine()], + "platform_name": None, + "platform_url": None, + "platform_working_dir": None + } + + if self.verbose: + print("parent: running pre-kill action on child") + output_io = StringIO() + do_pre_kill(child_pid, context_dict, output_io) + output = output_io.getvalue() + + if self.verbose: + print("parent: do_pre_kill() wrote the following output:", output) + self.assertIsNotNone(output) + + # We should have a line with: + # Process: .* [{pid}] + process_re = re.compile(r"Process:[^[]+\[([^]]+)\]") + match = process_re.search(output) + self.assertIsNotNone(match, "should have found process id for " + "sampled process") + self.assertEqual(1, len(match.groups())) + self.assertEqual(child_pid, int(match.group(1))) + + # We should see a Call graph: section. + callgraph_re = re.compile(r"Call graph:") + match = callgraph_re.search(output) + self.assertIsNotNone(match, "should have found the Call graph section" + "in sample output") + + # We should see a Binary Images: section. + binary_images_re = re.compile(r"Binary Images:") + match = binary_images_re.search(output) + self.assertIsNotNone(match, "should have found the Binary Images " + "section in sample output") + + +if __name__ == "__main__": + main() diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py b/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py new file mode 100644 index 000000000000..ab989df0d203 --- /dev/null +++ b/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py @@ -0,0 +1,133 @@ +"""Test the pre-kill hook on Linux.""" +from __future__ import print_function + +# system imports +from multiprocessing import Process, Queue +import platform +import re +import subprocess +from unittest import main, TestCase + +# third party +from six import StringIO + + +def do_child_thread(): + import os + x = 0 + while True: + x = x + 42 * os.getpid() + return x + + +def do_child_process(child_work_queue, parent_work_queue, verbose): + import os + + pid = os.getpid() + if verbose: + print("child: pid {} started, sending to parent".format(pid)) + parent_work_queue.put(pid) + + # Spin up a daemon thread to do some "work", which will show + # up in a sample of this process. + import threading + worker = threading.Thread(target=do_child_thread) + worker.daemon = True + worker.start() + + if verbose: + print("child: waiting for shut-down request from parent") + child_work_queue.get() + if verbose: + print("child: received shut-down request. Child exiting.") + + +class LinuxPreKillTestCase(TestCase): + + def __init__(self, methodName): + super(LinuxPreKillTestCase, self).__init__(methodName) + self.process = None + self.child_work_queue = None + self.verbose = False + # self.verbose = True + + def tearDown(self): + if self.verbose: + print("parent: sending shut-down request to child") + if self.process: + self.child_work_queue.put("hello, child") + self.process.join() + if self.verbose: + print("parent: child is fully shut down") + + def test_sample(self): + # Ensure we're Darwin. + if platform.system() != 'Linux': + self.skipTest("requires a Linux-based OS") + + # Ensure we have the 'perf' tool. If not, skip the test. + try: + perf_version = subprocess.check_output(["perf", "version"]) + if perf_version is None or not ( + perf_version.startswith("perf version")): + raise Exception("The perf executable doesn't appear" + " to be the Linux perf tools perf") + except Exception: + self.skipTest("requires the Linux perf tools 'perf' command") + + # Start the child process. + self.child_work_queue = Queue() + parent_work_queue = Queue() + self.process = Process(target=do_child_process, + args=(self.child_work_queue, parent_work_queue, + self.verbose)) + if self.verbose: + print("parent: starting child") + self.process.start() + + # Wait for the child to report its pid. Then we know we're running. + if self.verbose: + print("parent: waiting for child to start") + child_pid = parent_work_queue.get() + + # Sample the child process. + from linux import do_pre_kill + context_dict = { + "archs": [platform.machine()], + "platform_name": None, + "platform_url": None, + "platform_working_dir": None + } + + if self.verbose: + print("parent: running pre-kill action on child") + output_io = StringIO() + do_pre_kill(child_pid, context_dict, output_io) + output = output_io.getvalue() + + if self.verbose: + print("parent: do_pre_kill() wrote the following output:", output) + self.assertIsNotNone(output) + + # We should have a samples count entry. + # Samples: + self.assertTrue("Samples:" in output, "should have found a 'Samples:' " + "field in the sampled process output") + + # We should see an event count entry + event_count_re = re.compile(r"Event count[^:]+:\s+(\d+)") + match = event_count_re.search(output) + self.assertIsNotNone(match, "should have found the event count entry " + "in sample output") + if self.verbose: + print("cpu-clock events:", match.group(1)) + + # We should see some percentages in the file. + percentage_re = re.compile(r"\d+\.\d+%") + match = percentage_re.search(output) + self.assertIsNotNone(match, "should have found at least one percentage " + "in the sample output") + + +if __name__ == "__main__": + main() diff --git a/packages/Python/lldbsuite/support/encoded_file.py b/packages/Python/lldbsuite/support/encoded_file.py index 7581564f7e3a..2c2fef383f7f 100644 --- a/packages/Python/lldbsuite/support/encoded_file.py +++ b/packages/Python/lldbsuite/support/encoded_file.py @@ -14,6 +14,7 @@ import io # Third party modules import six + def _encoded_read(old_read, encoding): def impl(size): result = old_read(size) @@ -24,6 +25,7 @@ def _encoded_read(old_read, encoding): return result return impl + def _encoded_write(old_write, encoding): def impl(s): # If we were asked to write a `str` (in Py2) or a `bytes` (in Py3) decode it @@ -38,9 +40,24 @@ Create a Text I/O file object that can be written to with either unicode strings under Python 2 and Python 3, and automatically encodes and decodes as necessary to return the native string type for the current Python version ''' -def open(file, encoding, mode='r', buffering=-1, errors=None, newline=None, closefd=True): - wrapped_file = io.open(file, mode=mode, buffering=buffering, encoding=encoding, - errors=errors, newline=newline, closefd=closefd) + + +def open( + file, + encoding, + mode='r', + buffering=-1, + errors=None, + newline=None, + closefd=True): + wrapped_file = io.open( + file, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline, + closefd=closefd) new_read = _encoded_read(getattr(wrapped_file, 'read'), encoding) new_write = _encoded_write(getattr(wrapped_file, 'write'), encoding) setattr(wrapped_file, 'read', new_read) diff --git a/packages/Python/lldbsuite/support/fs.py b/packages/Python/lldbsuite/support/fs.py index 9a56808369de..30388596ea16 100644 --- a/packages/Python/lldbsuite/support/fs.py +++ b/packages/Python/lldbsuite/support/fs.py @@ -31,6 +31,7 @@ def _find_file_in_paths(paths, exe_basename): return os.path.normcase(trial_exe_path) return None + def find_executable(executable): """Finds the specified executable in the PATH or known good locations.""" @@ -59,6 +60,6 @@ def find_executable(executable): if not result or len(result) < 1: raise os.OSError( - "failed to find exe='%s' in paths='%s'" % (executable, paths_to_check)) + "failed to find exe='%s' in paths='%s'" % + (executable, paths_to_check)) return result - diff --git a/packages/Python/lldbsuite/support/funcutils.py b/packages/Python/lldbsuite/support/funcutils.py index 53dd1fb370ba..2fa10097d43b 100644 --- a/packages/Python/lldbsuite/support/funcutils.py +++ b/packages/Python/lldbsuite/support/funcutils.py @@ -8,9 +8,17 @@ import inspect # LLDB modules + def requires_self(func): func_argc = len(inspect.getargspec(func).args) - if func_argc == 0 or (getattr(func,'im_self', None) is not None) or (hasattr(func, '__self__')): + if func_argc == 0 or ( + getattr( + func, + 'im_self', + None) is not None) or ( + hasattr( + func, + '__self__')): return False else: return True diff --git a/packages/Python/lldbsuite/support/gmodules.py b/packages/Python/lldbsuite/support/gmodules.py index 4f2fd9643b14..5d66bd14896d 100644 --- a/packages/Python/lldbsuite/support/gmodules.py +++ b/packages/Python/lldbsuite/support/gmodules.py @@ -22,9 +22,8 @@ def is_compiler_clang_with_gmodules(compiler_path): else: # Check the compiler help for the -gmodules option. clang_help = os.popen("%s --help" % compiler_path).read() - return GMODULES_HELP_REGEX.search(clang_help, re.DOTALL) is not None + return GMODULES_HELP_REGEX.search( + clang_help, re.DOTALL) is not None GMODULES_SUPPORT_MAP[compiler_path] = _gmodules_supported_internal() return GMODULES_SUPPORT_MAP[compiler_path] - - diff --git a/packages/Python/lldbsuite/support/optional_with.py b/packages/Python/lldbsuite/support/optional_with.py index 41342288bc6a..f91b3c6fdeb6 100644 --- a/packages/Python/lldbsuite/support/optional_with.py +++ b/packages/Python/lldbsuite/support/optional_with.py @@ -2,6 +2,7 @@ # Provides a with-style resource handler for optionally-None resources # ==================================================================== + class optional_with(object): # pylint: disable=too-few-public-methods # This is a wrapper - it is not meant to provide any extra methods. @@ -39,6 +40,7 @@ class optional_with(object): forget the try/finally using optional_with(), since the with syntax can be used. """ + def __init__(self, wrapped_object): self.wrapped_object = wrapped_object diff --git a/packages/Python/lldbsuite/support/seven.py b/packages/Python/lldbsuite/support/seven.py index 56ddd8db3f66..e04f48308b7d 100644 --- a/packages/Python/lldbsuite/support/seven.py +++ b/packages/Python/lldbsuite/support/seven.py @@ -10,11 +10,16 @@ else: def get_command_status_output(command): try: import subprocess - return (0, subprocess.check_output(command, shell=True, universal_newlines=True)) + return ( + 0, + subprocess.check_output( + command, + shell=True, + universal_newlines=True)) except subprocess.CalledProcessError as e: return (e.returncode, e.output) def get_command_output(command): return get_command_status_output(command)[1] - cmp_ = lambda x, y: (x > y) - (x < y)
\ No newline at end of file + cmp_ = lambda x, y: (x > y) - (x < y) diff --git a/packages/Python/lldbsuite/support/sockutil.py b/packages/Python/lldbsuite/support/sockutil.py index b3d81d14884a..789deed8017a 100644 --- a/packages/Python/lldbsuite/support/sockutil.py +++ b/packages/Python/lldbsuite/support/sockutil.py @@ -14,6 +14,7 @@ import socket # LLDB modules import use_lldb_suite + def recvall(sock, size): bytes = io.BytesIO() while size > 0: diff --git a/packages/Python/lldbsuite/test/android/platform/TestDefaultCacheLineSize.py b/packages/Python/lldbsuite/test/android/platform/TestDefaultCacheLineSize.py index 2b6ac1818de7..c038c0726c27 100644 --- a/packages/Python/lldbsuite/test/android/platform/TestDefaultCacheLineSize.py +++ b/packages/Python/lldbsuite/test/android/platform/TestDefaultCacheLineSize.py @@ -5,13 +5,13 @@ Verify the default cache line size for android targets from __future__ import print_function - import os import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class DefaultCacheLineSizeTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -24,15 +24,23 @@ class DefaultCacheLineSizeTestCase(TestBase): self.assertTrue(target and target.IsValid(), "Target is valid") breakpoint = target.BreakpointCreateByName("main") - self.assertTrue(breakpoint and breakpoint.IsValid(), "Breakpoint is valid") + self.assertTrue( + breakpoint and breakpoint.IsValid(), + "Breakpoint is valid") # Run the program. - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) - self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + self.assertEqual( + process.GetState(), + lldb.eStateStopped, + PROCESS_STOPPED) # check the setting value - self.expect("settings show target.process.memory-cache-line-size", patterns=[" = 2048"]) + self.expect( + "settings show target.process.memory-cache-line-size", + patterns=[" = 2048"]) # Run to completion. process.Continue() diff --git a/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py b/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py index 0ed2df3ceab1..dd6dbe0a37ed 100644 --- a/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py +++ b/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py @@ -6,21 +6,22 @@ should compile and link with the LLDB framework.""" from __future__ import print_function - -import os, re +import os +import re from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class SBDirCheckerCase(TestBase): mydir = TestBase.compute_mydir(__file__) def setUp(self): TestBase.setUp(self) - self.template = 'main.cpp.template' self.source = 'main.cpp' self.exe_name = 'a.out' + self.generateSource(self.source) @skipIfNoSBHeaders def test_sb_api_directory(self): @@ -30,60 +31,38 @@ class SBDirCheckerCase(TestBase): if not (self.platformIsDarwin() and self.getArchitecture() == "x86_64"): self.skipTest("This test is only for LLDB.framework built 64-bit") if self.getArchitecture() == "i386": - self.skipTest("LLDB is 64-bit and cannot be linked to 32-bit test program.") + self.skipTest( + "LLDB is 64-bit and cannot be linked to 32-bit test program.") - # Generate main.cpp, build it, and execute. - self.generate_main_cpp() self.buildDriver(self.source, self.exe_name) self.sanity_check_executable(self.exe_name) - def generate_main_cpp(self): - """Generate main.cpp from main.cpp.template.""" - temp = os.path.join(os.getcwd(), self.template) - with open(temp, 'r') as f: - content = f.read() - - public_api_dir = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API") - - # Look under the include/lldb/API directory and add #include statements - # for all the SB API headers. - public_headers = os.listdir(public_api_dir) - # For different platforms, the include statement can vary. - if self.platformIsDarwin(): - include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" - if self.getPlatform() == "freebsd" or self.getPlatform() == "linux" or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': - include_stmt = "'#include <%s>' % os.path.join(public_api_dir, header)" - list = [eval(include_stmt) for header in public_headers if (header.startswith("SB") and - header.endswith(".h"))] - includes = '\n'.join(list) - new_content = content.replace('%include_SB_APIs%', includes) - src = os.path.join(os.getcwd(), self.source) - with open(src, 'w') as f: - f.write(new_content) - - # The main.cpp has been generated, add a teardown hook to remove it. - self.addTearDownHook(lambda: os.remove(src)) - def sanity_check_executable(self, exe_name): """Sanity check executable compiled from the auto-generated program.""" exe = os.path.join(os.getcwd(), exe_name) self.runCmd("file %s" % exe, CURRENT_EXECUTABLE_SET) - self.line_to_break = line_number(self.source, '// Set breakpoint here.') + self.line_to_break = line_number( + self.source, '// Set breakpoint here.') - env_cmd = "settings set target.env-vars %s=%s" %(self.dylibPath, self.getLLDBLibraryEnvVal()) + env_cmd = "settings set target.env-vars %s=%s" % ( + self.dylibPath, self.getLLDBLibraryEnvVal()) if self.TraceOn(): print("Set environment to: ", env_cmd) self.runCmd(env_cmd) - self.addTearDownHook(lambda: self.dbg.HandleCommand("settings remove target.env-vars %s" % self.dylibPath)) + self.addTearDownHook( + lambda: self.dbg.HandleCommand( + "settings remove target.env-vars %s" % + self.dylibPath)) - lldbutil.run_break_set_by_file_and_line (self, self.source, self.line_to_break, num_expected_locations = -1) + lldbutil.run_break_set_by_file_and_line( + self, self.source, self.line_to_break, num_expected_locations=-1) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs = ['stopped', - 'stop reason = breakpoint']) + substrs=['stopped', + 'stop reason = breakpoint']) self.runCmd('frame variable') diff --git a/packages/Python/lldbsuite/test/api/listeners/TestListener.py b/packages/Python/lldbsuite/test/api/listeners/TestListener.py index bd8c204e78cb..65232f014102 100644 --- a/packages/Python/lldbsuite/test/api/listeners/TestListener.py +++ b/packages/Python/lldbsuite/test/api/listeners/TestListener.py @@ -15,6 +15,7 @@ from lldbsuite.test import lldbutil import six + class ListenToModuleLoadedEvents (TestBase): mydir = TestBase.compute_mydir(__file__) @@ -24,14 +25,17 @@ class ListenToModuleLoadedEvents (TestBase): TestBase.setUp(self) self.build() - def test_receiving_breakpoint_added (self): + def test_receiving_breakpoint_added(self): """Test that we get breakpoint added events, waiting on event classes on the debugger""" my_listener = lldb.SBListener("test_listener") - - my_listener.StartListeningForEventClass(self.dbg, lldb.SBTarget.GetBroadcasterClassName(), lldb.SBTarget.eBroadcastBitBreakpointChanged) - exe = os.path.join (os.getcwd(), "a.out") + my_listener.StartListeningForEventClass( + self.dbg, + lldb.SBTarget.GetBroadcasterClassName(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) + + exe = os.path.join(os.getcwd(), "a.out") target = self.dbg.CreateTarget(exe) @@ -39,17 +43,29 @@ class ListenToModuleLoadedEvents (TestBase): event = lldb.SBEvent() my_listener.WaitForEvent(1, event) - + self.assertTrue(event.IsValid(), "Got a valid event.") - self.assertTrue(lldb.SBBreakpoint.EventIsBreakpointEvent(event), "It is a breakpoint event.") - self.assertTrue(lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) == lldb.eBreakpointEventTypeAdded, "It is a breakpoint added event.") - self.assertTrue(bkpt == lldb.SBBreakpoint.GetBreakpointFromEvent(event), "It is our breakpoint.") + self.assertTrue( + lldb.SBBreakpoint.EventIsBreakpointEvent(event), + "It is a breakpoint event.") + self.assertTrue(lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent( + event) == lldb.eBreakpointEventTypeAdded, "It is a breakpoint added event.") + self.assertTrue( + bkpt == lldb.SBBreakpoint.GetBreakpointFromEvent(event), + "It is our breakpoint.") # Now make sure if we stop listening for events we don't get them: - my_listener.StopListeningForEventClass(self.dbg, lldb.SBTarget.GetBroadcasterClassName(), lldb.SBTarget.eBroadcastBitBreakpointChanged) - my_listener.StopListeningForEvents(target.GetBroadcaster(), lldb.SBTarget.eBroadcastBitBreakpointChanged) + my_listener.StopListeningForEventClass( + self.dbg, + lldb.SBTarget.GetBroadcasterClassName(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) + my_listener.StopListeningForEvents( + target.GetBroadcaster(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) bkpt2 = target.BreakpointCreateByName("main") my_listener.WaitForEvent(1, event) - self.assertTrue(not event.IsValid(), "We don't get events we aren't listening to.") + self.assertTrue( + not event.IsValid(), + "We don't get events we aren't listening to.") diff --git a/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py b/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py index ca2b986ce740..20e41f0f4121 100644 --- a/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py +++ b/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py @@ -3,8 +3,8 @@ from __future__ import print_function - -import os, re +import os +import re import subprocess import lldb @@ -12,16 +12,23 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class TestMultipleSimultaneousDebuggers(TestBase): mydir = TestBase.compute_mydir(__file__) @skipIfNoSBHeaders - @expectedFlakeyDarwin() - @expectedFailureAll(archs="i[3-6]86", bugnumber="multi-process-driver.cpp creates an x64 target") - @expectedFailureAll(oslist=["windows", "linux", "freebsd"], bugnumber="llvm.org/pr20282") + @expectedFailureAll( + archs="i[3-6]86", + bugnumber="multi-process-driver.cpp creates an x64 target") + @expectedFailureAll( + oslist=[ + "windows", + "linux", + "freebsd"], + bugnumber="llvm.org/pr20282") def test_multiple_debuggers(self): - env = {self.dylibPath : self.getLLDBLibraryEnvVal()} + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} self.driver_exe = os.path.join(os.getcwd(), "multi-process-driver") self.buildDriver('multi-process-driver.cpp', self.driver_exe) @@ -41,4 +48,5 @@ class TestMultipleSimultaneousDebuggers(TestBase): check_call([self.driver_exe, self.inferior_exe], env=env) else: with open(os.devnull, 'w') as fnull: - check_call([self.driver_exe, self.inferior_exe], env=env, stdout=fnull, stderr=fnull) + check_call([self.driver_exe, self.inferior_exe], + env=env, stdout=fnull, stderr=fnull) diff --git a/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp b/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp index 1c2689ff6c4f..448304d83c75 100644 --- a/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp +++ b/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp @@ -25,7 +25,7 @@ #include <chrono> #include <thread> -#define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 20 +#define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 10 #define DEBUG 0 diff --git a/packages/Python/lldbsuite/test/api/multiple-targets/Makefile b/packages/Python/lldbsuite/test/api/multiple-targets/Makefile new file mode 100644 index 000000000000..bee559c8ecdd --- /dev/null +++ b/packages/Python/lldbsuite/test/api/multiple-targets/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../make + +MAKE_DSYM := NO + +ENABLE_THREADS := YES +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py b/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py new file mode 100644 index 000000000000..decb3fd4f0c5 --- /dev/null +++ b/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py @@ -0,0 +1,44 @@ +"""Test the lldb public C++ api when creating multiple targets simultaneously.""" + +from __future__ import print_function + + +import os +import re +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestMultipleTargets(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfNoSBHeaders + @skipIfHostIncompatibleWithRemote + @expectedFailureAll( + oslist=["windows", "freebsd"], + bugnumber="llvm.org/pr20282") + def test_multiple_targets(self): + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} + + self.driver_exe = os.path.join(os.getcwd(), "multi-target") + self.buildDriver('main.cpp', self.driver_exe) + self.addTearDownHook(lambda: os.remove(self.driver_exe)) + self.signBinary(self.driver_exe) + +# check_call will raise a CalledProcessError if multi-process-driver doesn't return +# exit code 0 to indicate success. We can let this exception go - the test harness +# will recognize it as a test failure. + + if self.TraceOn(): + print("Running test %s" % self.driver_exe) + check_call([self.driver_exe, self.driver_exe], env=env) + else: + with open(os.devnull, 'w') as fnull: + check_call([self.driver_exe, self.driver_exe], + env=env, stdout=fnull, stderr=fnull) diff --git a/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp b/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp new file mode 100644 index 000000000000..35fb4e0d613e --- /dev/null +++ b/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp @@ -0,0 +1,31 @@ +#include <thread> + +#include "lldb/API/LLDB.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBTarget.h" + +using namespace lldb; +int main (int argc, char **argv) +{ + // We are expecting the program path and a path to an executable to load + if (argc != 2) + return 1; + const char *program_file = argv[1]; + SBDebugger::Initialize(); + SBDebugger debugger = SBDebugger::Create(false); + auto lambda = [&](){ + SBError error; + SBTarget target = debugger.CreateTarget(program_file, nullptr, nullptr, + false, error); + }; + + // Create 3 targets at the same time and make sure we don't crash. + std::thread thread1(lambda); + std::thread thread2(lambda); + std::thread thread3(lambda); + thread1.join(); + thread2.join(); + thread3.join(); + SBDebugger::Terminate(); + return 0; +} diff --git a/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py b/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py index 7959bb73de02..0d6a6002d522 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py +++ b/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py @@ -5,19 +5,31 @@ from __future__ import print_function # __package__ = "lldbsuite.test" -import os, re +import os +import re from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil import subprocess + class SBBreakpointCallbackCase(TestBase): + def setUp(self): + TestBase.setUp(self) + self.generateSource('driver.cpp') + self.generateSource('listener_test.cpp') + self.generateSource('test_breakpoint_callback.cpp') + self.generateSource('test_listener_event_description.cpp') + self.generateSource('test_listener_event_process_state.cpp') + self.generateSource('test_listener_resume.cpp') + mydir = TestBase.compute_mydir(__file__) @skipIfRemote @skipIfNoSBHeaders - @skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538) + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows def test_breakpoint_callback(self): """Test the that SBBreakpoint callback is invoked when a breakpoint is hit. """ self.build_and_test('driver.cpp test_breakpoint_callback.cpp', @@ -25,40 +37,44 @@ class SBBreakpointCallbackCase(TestBase): @skipIfRemote @skipIfNoSBHeaders - @skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538) + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows @expectedFlakeyFreeBSD def test_sb_api_listener_event_description(self): """ Test the description of an SBListener breakpoint event is valid.""" - self.build_and_test('driver.cpp listener_test.cpp test_listener_event_description.cpp', - 'test_listener_event_description') + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_event_description.cpp', + 'test_listener_event_description') pass @skipIfRemote @skipIfNoSBHeaders - @skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538) + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows @expectedFlakeyFreeBSD - @expectedFailureAll("llvm.org/pr23139", oslist=["linux"], compiler="gcc", compiler_version=[">=","4.9"], archs=["x86_64"]) def test_sb_api_listener_event_process_state(self): """ Test that a registered SBListener receives events when a process changes state. """ - self.build_and_test('driver.cpp listener_test.cpp test_listener_event_process_state.cpp', - 'test_listener_event_process_state') + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_event_process_state.cpp', + 'test_listener_event_process_state') pass - @skipIfRemote @skipIfNoSBHeaders - @skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538) + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows @expectedFlakeyFreeBSD @expectedFailureAll(oslist=["linux"]) def test_sb_api_listener_resume(self): """ Test that a process can be resumed from a non-main thread. """ - self.build_and_test('driver.cpp listener_test.cpp test_listener_resume.cpp', - 'test_listener_resume') + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_resume.cpp', + 'test_listener_resume') pass - def build_and_test(self, sources, test_name, args = None): + def build_and_test(self, sources, test_name, args=None): """ Build LLDB test from sources, and run expecting 0 exit code """ # These tests link against host lldb API. @@ -66,7 +82,8 @@ class SBBreakpointCallbackCase(TestBase): # because remote is disabled, we can assume that the os is the same # still need to check architecture if self.getLldbArchitecture() != self.getArchitecture(): - self.skipTest("This test is only run if the target arch is the same as the lldb binary arch") + self.skipTest( + "This test is only run if the target arch is the same as the lldb binary arch") self.inferior = 'inferior_program' self.buildProgram('inferior.cpp', self.inferior) @@ -79,7 +96,7 @@ class SBBreakpointCallbackCase(TestBase): self.signBinary(test_exe) exe = [test_exe, self.inferior] - env = {self.dylibPath : self.getLLDBLibraryEnvVal()} + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} if self.TraceOn(): print("Running test %s" % " ".join(exe)) check_call(exe, env=env) diff --git a/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp b/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template index fa0c48e0ecfb..f4bd021632ce 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template @@ -6,8 +6,11 @@ #include <iterator> #include <string> #include <vector> +#if !defined(_MSC_VER) + #include <signal.h> +#endif -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" @@ -17,6 +20,13 @@ using namespace lldb; void test(SBDebugger &dbg, std::vector<string> args); int main(int argc, char** argv) { + +// Ignore SIGPIPE. The lldb driver does this as well, +// because we seem to get spurious SIGPIPES on some +// Unixen that take the driver down. +#if !defined(_MSC_VER) + signal(SIGPIPE, SIG_IGN); +#endif int code = 0; SBDebugger::Initialize(); diff --git a/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp b/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template index b20868ff94f4..e305d1af4893 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template @@ -7,7 +7,7 @@ #include <thread> #include <vector> -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" using namespace lldb; diff --git a/packages/Python/lldbsuite/test/api/multithreaded/lldb-headers.h b/packages/Python/lldbsuite/test/api/multithreaded/lldb-headers.h deleted file mode 100644 index da0914b3b071..000000000000 --- a/packages/Python/lldbsuite/test/api/multithreaded/lldb-headers.h +++ /dev/null @@ -1,11 +0,0 @@ - -#ifndef LLDB_HEADERS_H -#define LLDB_HEADERS_H - -#ifdef __APPLE__ -#include <LLDB/LLDB.h> -#else -#include "lldb/API/LLDB.h" -#endif - -#endif // LLDB_HEADERS_H diff --git a/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp b/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template index def31f82b0c7..4133025aa495 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template @@ -7,7 +7,7 @@ #include <vector> #include <string> -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" diff --git a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template index 0d7844dce6d0..63e3f3631e5d 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template @@ -8,7 +8,7 @@ #include <string> #include <thread> -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" diff --git a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template index a79c5cb2a08b..2926ece4d8d9 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template @@ -8,7 +8,7 @@ #include <string> #include <thread> -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" @@ -31,6 +31,11 @@ void listener_func() { throw Exception("event is not valid in listener thread"); // send process description SBProcess process = SBProcess::GetProcessFromEvent(event); + if (!process.IsValid()) + throw Exception("process is not valid"); + if (SBProcess::GetStateFromEvent(event) != lldb::eStateStopped || SBProcess::GetRestartedFromEvent(event)) + continue; // Only interested in "stopped" events. + SBStream description; for (int i = 0; i < process.GetNumThreads(); ++i) { diff --git a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template index 8cf786b11603..4adc9b338879 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp +++ b/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template @@ -8,7 +8,7 @@ #include <string> #include <thread> -#include "lldb-headers.h" +%include_SB_APIs% #include "common.h" diff --git a/packages/Python/lldbsuite/test/arm_emulation/TestEmulations.py b/packages/Python/lldbsuite/test/arm_emulation/TestEmulations.py index d502b6dfca8a..4ddda525537c 100644 --- a/packages/Python/lldbsuite/test/arm_emulation/TestEmulations.py +++ b/packages/Python/lldbsuite/test/arm_emulation/TestEmulations.py @@ -5,52 +5,53 @@ Test some ARM instruction emulation. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ARMEmulationTestCase(TestBase): - + mydir = TestBase.compute_mydir(__file__) @no_debug_info_test - def test_thumb_emulations (self): - current_dir = os.getcwd(); - test_dir = os.path.join (current_dir, "new-test-files") - files = os.listdir (test_dir) + def test_thumb_emulations(self): + current_dir = os.getcwd() + test_dir = os.path.join(current_dir, "new-test-files") + files = os.listdir(test_dir) thumb_files = list() for f in files: if '-thumb.dat' in f: - thumb_files.append (f) - + thumb_files.append(f) + for f in thumb_files: - test_file = os.path.join (test_dir, f) - self.run_a_single_test (test_file) + test_file = os.path.join(test_dir, f) + self.run_a_single_test(test_file) @no_debug_info_test - def test_arm_emulations (self): - current_dir = os.getcwd(); - test_dir = os.path.join (current_dir, "new-test-files") - files = os.listdir (test_dir) + def test_arm_emulations(self): + current_dir = os.getcwd() + test_dir = os.path.join(current_dir, "new-test-files") + files = os.listdir(test_dir) arm_files = list() for f in files: if '-arm.dat' in f: - arm_files.append (f) - + arm_files.append(f) + for f in arm_files: - test_file = os.path.join (test_dir, f) - self.run_a_single_test (test_file) - - def run_a_single_test (self, filename): - insn = lldb.SBInstruction (); - stream = lldb.SBStream (); - success = insn.TestEmulation (stream, filename); - output = stream.GetData(); + test_file = os.path.join(test_dir, f) + self.run_a_single_test(test_file) + + def run_a_single_test(self, filename): + insn = lldb.SBInstruction() + stream = lldb.SBStream() + success = insn.TestEmulation(stream, filename) + output = stream.GetData() if self.TraceOn(): print('\nRunning test ' + os.path.basename(filename)) print(output) - self.assertTrue (success, 'Emulation test succeeded.') + self.assertTrue(success, 'Emulation test succeeded.') diff --git a/packages/Python/lldbsuite/test/attic/tester.py b/packages/Python/lldbsuite/test/attic/tester.py index 5c1a2370ced8..2e783512369d 100644 --- a/packages/Python/lldbsuite/test/attic/tester.py +++ b/packages/Python/lldbsuite/test/attic/tester.py @@ -3,112 +3,146 @@ from __future__ import print_function -import math, os.path, re, sys, time, unittest +import math +import os.path +import re +import sys +import time +import unittest + def setupSysPath(): - testPath = sys.path[0] - rem = re.match("(^.*/)test$", testPath) - if not rem: - print("This script expects to reside in .../test.") - sys.exit(-1) - lldbBasePath = rem.group(1) - lldbDebugPythonPath = "build/Debug/LLDB.framework/Resources/Python" - lldbReleasePythonPath = "build/Release/LLDB.framework/Resources/Python" - lldbPythonPath = None - if os.path.isfile(lldbDebugPythonPath + "/lldb.py"): - lldbPythonPath = lldbDebugPythonPath - if os.path.isfile(lldbReleasePythonPath + "/lldb.py"): - lldbPythonPath = lldbReleasePythonPath - if not lldbPythonPath: - print("This script requires lldb.py to be in either " + lldbDebugPythonPath, end='') - print("or" + lldbReleasePythonPath) - sys.exit(-1) - sys.path.append(lldbPythonPath) + testPath = sys.path[0] + rem = re.match("(^.*/)test$", testPath) + if not rem: + print("This script expects to reside in .../test.") + sys.exit(-1) + lldbBasePath = rem.group(1) + lldbDebugPythonPath = "build/Debug/LLDB.framework/Resources/Python" + lldbReleasePythonPath = "build/Release/LLDB.framework/Resources/Python" + lldbPythonPath = None + if os.path.isfile(lldbDebugPythonPath + "/lldb.py"): + lldbPythonPath = lldbDebugPythonPath + if os.path.isfile(lldbReleasePythonPath + "/lldb.py"): + lldbPythonPath = lldbReleasePythonPath + if not lldbPythonPath: + print( + "This script requires lldb.py to be in either " + + lldbDebugPythonPath, + end='') + print("or" + lldbReleasePythonPath) + sys.exit(-1) + sys.path.append(lldbPythonPath) + def prettyTime(t): - if t == 0.0: - return "0s" - if t < 0.000001: - return ("%.3f" % (t * 1000000000.0)) + "ns" - if t < 0.001: - return ("%.3f" % (t * 1000000.0)) + "µs" - if t < 1: - return ("%.3f" % (t * 1000.0)) + "ms" - return str(t) + "s" + if t == 0.0: + return "0s" + if t < 0.000001: + return ("%.3f" % (t * 1000000000.0)) + "ns" + if t < 0.001: + return ("%.3f" % (t * 1000000.0)) + "µs" + if t < 1: + return ("%.3f" % (t * 1000.0)) + "ms" + return str(t) + "s" + class ExecutionTimes: - @classmethod - def executionTimes(cls): - if cls.m_executionTimes == None: - cls.m_executionTimes = ExecutionTimes() - for i in range(100): - cls.m_executionTimes.start() - cls.m_executionTimes.end("null") - return cls.m_executionTimes - def __init__(self): - self.m_times = dict() - def start(self): - self.m_start = time.time() - def end(self, component): - e = time.time() - if component not in self.m_times: - self.m_times[component] = list() - self.m_times[component].append(e - self.m_start) - def dumpStats(self): - for key in list(self.m_times.keys()): - if len(self.m_times[key]): - sampleMin = float('inf') - sampleMax = float('-inf') - sampleSum = 0.0 - sampleCount = 0.0 - for time in self.m_times[key]: - if time > sampleMax: - sampleMax = time - if time < sampleMin: - sampleMin = time - sampleSum += time - sampleCount += 1.0 - sampleMean = sampleSum / sampleCount - sampleVariance = 0 - for time in self.m_times[key]: - sampleVariance += (time - sampleMean) ** 2 - sampleVariance /= sampleCount - sampleStandardDeviation = math.sqrt(sampleVariance) - print(key + ": [" + prettyTime(sampleMin) + ", " + prettyTime(sampleMax) + "] ", end='') - print("µ " + prettyTime(sampleMean) + ", σ " + prettyTime(sampleStandardDeviation)) - m_executionTimes = None + + @classmethod + def executionTimes(cls): + if cls.m_executionTimes is None: + cls.m_executionTimes = ExecutionTimes() + for i in range(100): + cls.m_executionTimes.start() + cls.m_executionTimes.end("null") + return cls.m_executionTimes + + def __init__(self): + self.m_times = dict() + + def start(self): + self.m_start = time.time() + + def end(self, component): + e = time.time() + if component not in self.m_times: + self.m_times[component] = list() + self.m_times[component].append(e - self.m_start) + + def dumpStats(self): + for key in list(self.m_times.keys()): + if len(self.m_times[key]): + sampleMin = float('inf') + sampleMax = float('-inf') + sampleSum = 0.0 + sampleCount = 0.0 + for time in self.m_times[key]: + if time > sampleMax: + sampleMax = time + if time < sampleMin: + sampleMin = time + sampleSum += time + sampleCount += 1.0 + sampleMean = sampleSum / sampleCount + sampleVariance = 0 + for time in self.m_times[key]: + sampleVariance += (time - sampleMean) ** 2 + sampleVariance /= sampleCount + sampleStandardDeviation = math.sqrt(sampleVariance) + print( + key + + ": [" + + prettyTime(sampleMin) + + ", " + + prettyTime(sampleMax) + + "] ", + end='') + print( + "µ " + + prettyTime(sampleMean) + + ", σ " + + prettyTime(sampleStandardDeviation)) + m_executionTimes = None setupSysPath() import lldb + class LLDBTestCase(unittest.TestCase): - def setUp(self): - debugger = lldb.SBDebugger.Create() - debugger.SetAsync(True) - self.m_commandInterpreter = debugger.GetCommandInterpreter() - if not self.m_commandInterpreter: - print("Couldn't get the command interpreter") - sys.exit(-1) - def runCommand(self, command, component): - res = lldb.SBCommandReturnObject() - ExecutionTimes.executionTimes().start() - self.m_commandInterpreter.HandleCommand(command, res, False) - ExecutionTimes.executionTimes().end(component) - if res.Succeeded(): - return res.GetOutput() - else: - self.fail("Command " + command + " returned an error") - return None - def getCategories(self): - return [] + + def setUp(self): + debugger = lldb.SBDebugger.Create() + debugger.SetAsync(True) + self.m_commandInterpreter = debugger.GetCommandInterpreter() + if not self.m_commandInterpreter: + print("Couldn't get the command interpreter") + sys.exit(-1) + + def runCommand(self, command, component): + res = lldb.SBCommandReturnObject() + ExecutionTimes.executionTimes().start() + self.m_commandInterpreter.HandleCommand(command, res, False) + ExecutionTimes.executionTimes().end(component) + if res.Succeeded(): + return res.GetOutput() + else: + self.fail("Command " + command + " returned an error") + return None + + def getCategories(self): + return [] + class SanityCheckTestCase(LLDBTestCase): - def runTest(self): - ret = self.runCommand("show arch", "show-arch") - #print(ret) - def getCategories(self): - return [] + + def runTest(self): + ret = self.runCommand("show arch", "show-arch") + # print(ret) + + def getCategories(self): + return [] suite = unittest.TestLoader().loadTestsFromTestCase(SanityCheckTestCase) unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/packages/Python/lldbsuite/test/bench.py b/packages/Python/lldbsuite/test/bench.py index ce9c2e75d711..5a0fec7534a8 100644 --- a/packages/Python/lldbsuite/test/bench.py +++ b/packages/Python/lldbsuite/test/bench.py @@ -17,14 +17,16 @@ See also bench-history. from __future__ import print_function from __future__ import absolute_import -import os, sys +import os +import sys import re from optparse import OptionParser # dotest.py invocation with no '-e exe-path' uses lldb as the inferior program, # unless there is a mentioning of custom executable program. benches = [ - # Measure startup delays creating a target, setting a breakpoint, and run to breakpoint stop. + # Measure startup delays creating a target, setting a breakpoint, and run + # to breakpoint stop. './dotest.py -v +b %E %X -n -p TestStartupDelays.py', # Measure 'frame variable' response after stopping at a breakpoint. @@ -40,6 +42,7 @@ benches = [ './dotest.py -v +b -n %E -p TestDoAttachThenDisassembly.py' ] + def main(): """Read the items from 'benches' and run the command line one by one.""" parser = OptionParser(usage="""\ @@ -57,14 +60,14 @@ Run the standard benchmarks defined in the list named 'benches'.\ # Parses the options, if any. opts, args = parser.parse_args() - + print("Starting bench runner....") for item in benches: command = item.replace('%E', '-e "%s"' % opts.exe if opts.exe else '') - command = command.replace('%X', - '-x "%s"' % opts.break_spec if opts.break_spec else '') + command = command.replace('%X', '-x "%s"' % + opts.break_spec if opts.break_spec else '') print("Running %s" % (command)) os.system(command) diff --git a/packages/Python/lldbsuite/test/benchmarks/continue/TestBenchmarkContinue.py b/packages/Python/lldbsuite/test/benchmarks/continue/TestBenchmarkContinue.py index f7c274522f9b..74336693bcb2 100644 --- a/packages/Python/lldbsuite/test/benchmarks/continue/TestBenchmarkContinue.py +++ b/packages/Python/lldbsuite/test/benchmarks/continue/TestBenchmarkContinue.py @@ -5,14 +5,15 @@ Test lldb data formatter subsystem. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class TestBenchmarkContinue(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -31,14 +32,16 @@ class TestBenchmarkContinue(BenchBase): """Benchmark different ways to continue a process""" self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - bkpt = self.target().FindBreakpointByID(lldbutil.run_break_set_by_source_regexp (self, "// break here")) + bkpt = self.target().FindBreakpointByID( + lldbutil.run_break_set_by_source_regexp( + self, "// break here")) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs = ['stopped', - 'stop reason = breakpoint']) + substrs=['stopped', + 'stop reason = breakpoint']) # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -47,22 +50,24 @@ class TestBenchmarkContinue(BenchBase): self.runCmd('type summary clear', check=False) self.runCmd('type filter clear', check=False) self.runCmd('type synth clear', check=False) - self.runCmd("settings set target.max-children-count 256", check=False) + self.runCmd( + "settings set target.max-children-count 256", + check=False) # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) - + runCmd_sw = Stopwatch() lldbutil_sw = Stopwatch() - for i in range(0,15): + for i in range(0, 15): runCmd_sw.start() self.runCmd("continue") runCmd_sw.stop() - - for i in range(0,15): + + for i in range(0, 15): lldbutil_sw.start() lldbutil.continue_to_breakpoint(self.process(), bkpt) lldbutil_sw.stop() - - print("runCmd: %s\nlldbutil: %s" % (runCmd_sw,lldbutil_sw)) + + print("runCmd: %s\nlldbutil: %s" % (runCmd_sw, lldbutil_sw)) diff --git a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDisassembly.py b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDisassembly.py index 8a0c044147a0..8bce4815894d 100644 --- a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDisassembly.py +++ b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDisassembly.py @@ -3,18 +3,20 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + def is_exe(fpath): """Returns true if fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + class DisassembleDriverMainLoop(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -42,7 +44,9 @@ class DisassembleDriverMainLoop(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_lldb_then_gdb(self): """Test disassembly on a large function with lldb vs. gdb.""" print() @@ -54,11 +58,13 @@ class DisassembleDriverMainLoop(BenchBase): print("lldb benchmark:", self.stopwatch) self.run_gdb_disassembly(self.exe, self.function, self.count) print("gdb benchmark:", self.stopwatch) - print("lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)) + print("lldb_avg/gdb_avg: %f" % (self.lldb_avg / self.gdb_avg)) @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_gdb_then_lldb(self): """Test disassembly on a large function with lldb vs. gdb.""" print() @@ -70,7 +76,7 @@ class DisassembleDriverMainLoop(BenchBase): print("gdb benchmark:", self.stopwatch) self.run_lldb_disassembly(self.exe, self.function, self.count) print("lldb benchmark:", self.stopwatch) - print("lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)) + print("lldb_avg/gdb_avg: %f" % (self.lldb_avg / self.gdb_avg)) def run_lldb_disassembly(self, exe, function, count): import pexpect @@ -79,7 +85,9 @@ class DisassembleDriverMainLoop(BenchBase): prompt = self.child_prompt # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. diff --git a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDoAttachThenDisassembly.py b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDoAttachThenDisassembly.py index f8e3d94b6577..36f23572648d 100644 --- a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDoAttachThenDisassembly.py +++ b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestDoAttachThenDisassembly.py @@ -5,13 +5,14 @@ inferior and traverses the stack for thread0 to arrive at frame with function from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * from lldbsuite.test.lldbtest import * + class AttachThenDisassemblyBench(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -32,10 +33,11 @@ class AttachThenDisassemblyBench(BenchBase): def run_lldb_attach_then_disassembly(self, exe, count): target = self.dbg.CreateTarget(exe) - # Spawn a new process and don't display the stdout if not in TraceOn() mode. + # Spawn a new process and don't display the stdout if not in TraceOn() + # mode. import subprocess - popen = subprocess.Popen([exe, self.lldbOption], - stdout = open(os.devnull, 'w') if not self.TraceOn() else None) + popen = subprocess.Popen([exe, self.lldbOption], stdout=open( + os.devnull, 'w') if not self.TraceOn() else None) if self.TraceOn(): print("pid of spawned process: %d" % popen.pid) @@ -51,7 +53,7 @@ class AttachThenDisassemblyBench(BenchBase): i = 0 found = False for f in thread0: - #print("frame#%d %s" % (i, f.GetFunctionName())) + # print("frame#%d %s" % (i, f.GetFunctionName())) if "MainLoop" in f.GetFunctionName(): found = True thread0.SetSelectedFrame(i) @@ -59,7 +61,7 @@ class AttachThenDisassemblyBench(BenchBase): print("Found frame#%d for function 'MainLoop'" % i) break i += 1 - + # Reset the stopwatch now. self.stopwatch.reset() for i in range(count): diff --git a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestXcode41Vs42GDBDisassembly.py b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestXcode41Vs42GDBDisassembly.py index 618aac7eafcd..fd91bb441d9f 100644 --- a/packages/Python/lldbsuite/test/benchmarks/disassembly/TestXcode41Vs42GDBDisassembly.py +++ b/packages/Python/lldbsuite/test/benchmarks/disassembly/TestXcode41Vs42GDBDisassembly.py @@ -3,8 +3,8 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * @@ -12,6 +12,7 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test import configuration from lldbsuite.test import lldbutil + class XCode41Vs42GDBDisassembly(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -28,31 +29,53 @@ class XCode41Vs42GDBDisassembly(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_41_then_42(self): """Test disassembly on a large function with 4.1 vs. 4.2's gdb.""" print() - self.run_gdb_disassembly(self.gdb_41_exe, self.exe, self.function, self.count) + self.run_gdb_disassembly( + self.gdb_41_exe, + self.exe, + self.function, + self.count) print("4.1 gdb benchmark:", self.stopwatch) self.gdb_41_avg = self.stopwatch.avg() - self.run_gdb_disassembly(self.gdb_42_exe, self.exe, self.function, self.count) + self.run_gdb_disassembly( + self.gdb_42_exe, + self.exe, + self.function, + self.count) print("4.2 gdb benchmark:", self.stopwatch) self.gdb_42_avg = self.stopwatch.avg() - print("gdb_42_avg/gdb_41_avg: %f" % (self.gdb_42_avg/self.gdb_41_avg)) + print("gdb_42_avg/gdb_41_avg: %f" % + (self.gdb_42_avg / self.gdb_41_avg)) @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_42_then_41(self): """Test disassembly on a large function with 4.1 vs. 4.2's gdb.""" print() - self.run_gdb_disassembly(self.gdb_42_exe, self.exe, self.function, self.count) + self.run_gdb_disassembly( + self.gdb_42_exe, + self.exe, + self.function, + self.count) print("4.2 gdb benchmark:", self.stopwatch) self.gdb_42_avg = self.stopwatch.avg() - self.run_gdb_disassembly(self.gdb_41_exe, self.exe, self.function, self.count) + self.run_gdb_disassembly( + self.gdb_41_exe, + self.exe, + self.function, + self.count) print("4.1 gdb benchmark:", self.stopwatch) self.gdb_41_avg = self.stopwatch.avg() - print("gdb_42_avg/gdb_41_avg: %f" % (self.gdb_42_avg/self.gdb_41_avg)) + print("gdb_42_avg/gdb_41_avg: %f" % + (self.gdb_42_avg / self.gdb_41_avg)) def run_gdb_disassembly(self, gdb_exe_path, exe, function, count): import pexpect diff --git a/packages/Python/lldbsuite/test/benchmarks/expression/TestExpressionCmd.py b/packages/Python/lldbsuite/test/benchmarks/expression/TestExpressionCmd.py index 68d2bd9793e1..a9899d93bf03 100644 --- a/packages/Python/lldbsuite/test/benchmarks/expression/TestExpressionCmd.py +++ b/packages/Python/lldbsuite/test/benchmarks/expression/TestExpressionCmd.py @@ -3,8 +3,8 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * @@ -12,6 +12,7 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test import configuration from lldbsuite.test import lldbutil + class ExpressionEvaluationCase(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -19,11 +20,14 @@ class ExpressionEvaluationCase(BenchBase): def setUp(self): BenchBase.setUp(self) self.source = 'main.cpp' - self.line_to_break = line_number(self.source, '// Set breakpoint here.') + self.line_to_break = line_number( + self.source, '// Set breakpoint here.') self.count = 25 @benchmarks_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_expr_cmd(self): """Test lldb's expression commands and collect statistics.""" self.build() @@ -45,7 +49,9 @@ class ExpressionEvaluationCase(BenchBase): self.stopwatch.reset() for i in range(count): # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. @@ -53,7 +59,9 @@ class ExpressionEvaluationCase(BenchBase): child.logfile_read = sys.stdout child.expect_exact(prompt) - child.sendline('breakpoint set -f %s -l %d' % (self.source, self.line_to_break)) + child.sendline( + 'breakpoint set -f %s -l %d' % + (self.source, self.line_to_break)) child.expect_exact(prompt) child.sendline('run') child.expect_exact(prompt) diff --git a/packages/Python/lldbsuite/test/benchmarks/expression/TestRepeatedExprs.py b/packages/Python/lldbsuite/test/benchmarks/expression/TestRepeatedExprs.py index 2ad409e53b07..a223d2cf1fa7 100644 --- a/packages/Python/lldbsuite/test/benchmarks/expression/TestRepeatedExprs.py +++ b/packages/Python/lldbsuite/test/benchmarks/expression/TestRepeatedExprs.py @@ -3,8 +3,8 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.lldbbench import BenchBase from lldbsuite.test.decorators import * @@ -12,6 +12,7 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test import configuration from lldbsuite.test import lldbutil + class RepeatedExprsCase(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -19,13 +20,16 @@ class RepeatedExprsCase(BenchBase): def setUp(self): BenchBase.setUp(self) self.source = 'main.cpp' - self.line_to_break = line_number(self.source, '// Set breakpoint here.') + self.line_to_break = line_number( + self.source, '// Set breakpoint here.') self.lldb_avg = None self.gdb_avg = None self.count = 100 @benchmarks_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_compare_lldb_to_gdb(self): """Test repeated expressions with lldb vs. gdb.""" self.build() @@ -36,7 +40,7 @@ class RepeatedExprsCase(BenchBase): print("lldb benchmark:", self.stopwatch) self.run_gdb_repeated_exprs(self.exe_name, self.count) print("gdb benchmark:", self.stopwatch) - print("lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)) + print("lldb_avg/gdb_avg: %f" % (self.lldb_avg / self.gdb_avg)) def run_lldb_repeated_exprs(self, exe_name, count): import pexpect @@ -47,7 +51,9 @@ class RepeatedExprsCase(BenchBase): prompt = self.child_prompt # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. @@ -55,7 +61,9 @@ class RepeatedExprsCase(BenchBase): child.logfile_read = sys.stdout child.expect_exact(prompt) - child.sendline('breakpoint set -f %s -l %d' % (self.source, self.line_to_break)) + child.sendline( + 'breakpoint set -f %s -l %d' % + (self.source, self.line_to_break)) child.expect_exact(prompt) child.sendline('run') child.expect_exact(prompt) @@ -71,7 +79,7 @@ class RepeatedExprsCase(BenchBase): child.sendline(expr_cmd2) child.expect_exact(prompt) child.sendline('process continue') - child.expect_exact(prompt) + child.expect_exact(prompt) child.sendline('quit') try: @@ -117,7 +125,7 @@ class RepeatedExprsCase(BenchBase): child.sendline(expr_cmd2) child.expect_exact(prompt) child.sendline('continue') - child.expect_exact(prompt) + child.expect_exact(prompt) child.sendline('quit') child.expect_exact('The program is running. Exit anyway?') diff --git a/packages/Python/lldbsuite/test/benchmarks/frame_variable/TestFrameVariableResponse.py b/packages/Python/lldbsuite/test/benchmarks/frame_variable/TestFrameVariableResponse.py index 9f5835297379..3ed23e615409 100644 --- a/packages/Python/lldbsuite/test/benchmarks/frame_variable/TestFrameVariableResponse.py +++ b/packages/Python/lldbsuite/test/benchmarks/frame_variable/TestFrameVariableResponse.py @@ -3,14 +3,15 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test import configuration from lldbsuite.test import lldbtest_config from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * + class FrameVariableResponseBench(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -23,7 +24,9 @@ class FrameVariableResponseBench(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_startup_delay(self): """Test response time for the 'frame variable' command.""" print() @@ -40,7 +43,9 @@ class FrameVariableResponseBench(BenchBase): self.stopwatch.reset() for i in range(count): # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. @@ -52,9 +57,9 @@ class FrameVariableResponseBench(BenchBase): child.expect_exact(prompt) # Run the target and expect it to be stopped due to breakpoint. - child.sendline('run') # Aka 'process launch'. + child.sendline('run') # Aka 'process launch'. child.expect_exact(prompt) - + with self.stopwatch: # Measure the 'frame variable' response time. child.sendline('frame variable') diff --git a/packages/Python/lldbsuite/test/benchmarks/libcxxlist/TestBenchmarkLibcxxList.py b/packages/Python/lldbsuite/test/benchmarks/libcxxlist/TestBenchmarkLibcxxList.py index 12e23e956943..659382e7311b 100644 --- a/packages/Python/lldbsuite/test/benchmarks/libcxxlist/TestBenchmarkLibcxxList.py +++ b/packages/Python/lldbsuite/test/benchmarks/libcxxlist/TestBenchmarkLibcxxList.py @@ -5,14 +5,15 @@ Test lldb data formatter subsystem. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class TestBenchmarkLibcxxList(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -31,14 +32,16 @@ class TestBenchmarkLibcxxList(BenchBase): """Benchmark the std::list data formatter (libc++)""" self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - bkpt = self.target().FindBreakpointByID(lldbutil.run_break_set_by_source_regexp (self, "break here")) + bkpt = self.target().FindBreakpointByID( + lldbutil.run_break_set_by_source_regexp( + self, "break here")) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs = ['stopped', - 'stop reason = breakpoint']) + substrs=['stopped', + 'stop reason = breakpoint']) # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -47,15 +50,17 @@ class TestBenchmarkLibcxxList(BenchBase): self.runCmd('type summary clear', check=False) self.runCmd('type filter clear', check=False) self.runCmd('type synth clear', check=False) - self.runCmd("settings set target.max-children-count 256", check=False) + self.runCmd( + "settings set target.max-children-count 256", + check=False) # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) - + sw = Stopwatch() - + sw.start() self.expect('frame variable -A list', substrs=['[300]', '300']) sw.stop() - + print("time to print: %s" % (sw)) diff --git a/packages/Python/lldbsuite/test/benchmarks/libcxxmap/TestBenchmarkLibcxxMap.py b/packages/Python/lldbsuite/test/benchmarks/libcxxmap/TestBenchmarkLibcxxMap.py index 4466cd083ca3..343f93d95c4e 100644 --- a/packages/Python/lldbsuite/test/benchmarks/libcxxmap/TestBenchmarkLibcxxMap.py +++ b/packages/Python/lldbsuite/test/benchmarks/libcxxmap/TestBenchmarkLibcxxMap.py @@ -5,14 +5,15 @@ Test lldb data formatter subsystem. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.lldbbench import * from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class TestBenchmarkLibcxxMap(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -31,14 +32,16 @@ class TestBenchmarkLibcxxMap(BenchBase): """Benchmark the std::map data formatter (libc++)""" self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - bkpt = self.target().FindBreakpointByID(lldbutil.run_break_set_by_source_regexp (self, "break here")) + bkpt = self.target().FindBreakpointByID( + lldbutil.run_break_set_by_source_regexp( + self, "break here")) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs = ['stopped', - 'stop reason = breakpoint']) + substrs=['stopped', + 'stop reason = breakpoint']) # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -47,15 +50,17 @@ class TestBenchmarkLibcxxMap(BenchBase): self.runCmd('type summary clear', check=False) self.runCmd('type filter clear', check=False) self.runCmd('type synth clear', check=False) - self.runCmd("settings set target.max-children-count 256", check=False) + self.runCmd( + "settings set target.max-children-count 256", + check=False) # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) - + sw = Stopwatch() - + sw.start() self.expect('frame variable -A map', substrs=['[300]', '300']) sw.stop() - + print("time to print: %s" % (sw)) diff --git a/packages/Python/lldbsuite/test/benchmarks/startup/TestStartupDelays.py b/packages/Python/lldbsuite/test/benchmarks/startup/TestStartupDelays.py index 9d2356ab54f9..baacdc81e237 100644 --- a/packages/Python/lldbsuite/test/benchmarks/startup/TestStartupDelays.py +++ b/packages/Python/lldbsuite/test/benchmarks/startup/TestStartupDelays.py @@ -3,14 +3,15 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test import configuration from lldbsuite.test import lldbtest_config from lldbsuite.test.decorators import * from lldbsuite.test.lldbbench import * + class StartupDelaysBench(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -28,14 +29,22 @@ class StartupDelaysBench(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_startup_delay(self): """Test start up delays creating a target, setting a breakpoint, and run to breakpoint stop.""" print() self.run_startup_delays_bench(self.exe, self.break_spec, self.count) - print("lldb startup delay (create fresh target) benchmark:", self.stopwatch) - print("lldb startup delay (set first breakpoint) benchmark:", self.stopwatch2) - print("lldb startup delay (run to breakpoint) benchmark:", self.stopwatch3) + print( + "lldb startup delay (create fresh target) benchmark:", + self.stopwatch) + print( + "lldb startup delay (set first breakpoint) benchmark:", + self.stopwatch2) + print( + "lldb startup delay (run to breakpoint) benchmark:", + self.stopwatch3) def run_startup_delays_bench(self, exe, break_spec, count): import pexpect @@ -48,7 +57,9 @@ class StartupDelaysBench(BenchBase): self.stopwatch2.reset() for i in range(count): # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s' % (lldbtest_config.lldbExec, self.lldbOption)) + self.child = pexpect.spawn( + '%s %s' % + (lldbtest_config.lldbExec, self.lldbOption)) child = self.child # Turn on logging for what the child sends back. @@ -57,7 +68,7 @@ class StartupDelaysBench(BenchBase): with self.stopwatch: # Create a fresh target. - child.sendline('file %s' % exe) # Aka 'target create'. + child.sendline('file %s' % exe) # Aka 'target create'. child.expect_exact(prompt) with self.stopwatch2: diff --git a/packages/Python/lldbsuite/test/benchmarks/stepping/TestSteppingSpeed.py b/packages/Python/lldbsuite/test/benchmarks/stepping/TestSteppingSpeed.py index 3ab760d4abe8..2a2a8ef000a7 100644 --- a/packages/Python/lldbsuite/test/benchmarks/stepping/TestSteppingSpeed.py +++ b/packages/Python/lldbsuite/test/benchmarks/stepping/TestSteppingSpeed.py @@ -2,7 +2,8 @@ from __future__ import print_function -import os, sys +import os +import sys import lldb from lldbsuite.test import configuration from lldbsuite.test import lldbtest_config @@ -11,6 +12,7 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class SteppingSpeedBench(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -26,7 +28,9 @@ class SteppingSpeedBench(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_lldb_steppings(self): """Test lldb steppings on a large executable.""" print() @@ -40,7 +44,9 @@ class SteppingSpeedBench(BenchBase): prompt = self.child_prompt # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. @@ -58,7 +64,7 @@ class SteppingSpeedBench(BenchBase): for i in range(count): with self.stopwatch: # Disassemble the function. - child.sendline('next') # Aka 'thread step-over'. + child.sendline('next') # Aka 'thread step-over'. child.expect_exact(prompt) child.sendline('quit') diff --git a/packages/Python/lldbsuite/test/benchmarks/turnaround/TestCompileRunToBreakpointTurnaround.py b/packages/Python/lldbsuite/test/benchmarks/turnaround/TestCompileRunToBreakpointTurnaround.py index 3106c4511f58..ab2b2004fc5d 100644 --- a/packages/Python/lldbsuite/test/benchmarks/turnaround/TestCompileRunToBreakpointTurnaround.py +++ b/packages/Python/lldbsuite/test/benchmarks/turnaround/TestCompileRunToBreakpointTurnaround.py @@ -3,8 +3,8 @@ from __future__ import print_function - -import os, sys +import os +import sys import lldb from lldbsuite.test.lldbbench import * from lldbsuite.test.decorators import * @@ -12,6 +12,7 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test import configuration from lldbsuite.test import lldbutil + class CompileRunToBreakpointBench(BenchBase): mydir = TestBase.compute_mydir(__file__) @@ -27,7 +28,9 @@ class CompileRunToBreakpointBench(BenchBase): @benchmarks_test @no_debug_info_test - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_run_lldb_then_gdb(self): """Benchmark turnaround time with lldb vs. gdb.""" print() @@ -35,15 +38,18 @@ class CompileRunToBreakpointBench(BenchBase): print("lldb turnaround benchmark:", self.stopwatch) self.run_gdb_turnaround(self.exe, self.function, self.count) print("gdb turnaround benchmark:", self.stopwatch) - print("lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)) + print("lldb_avg/gdb_avg: %f" % (self.lldb_avg / self.gdb_avg)) def run_lldb_turnaround(self, exe, function, count): import pexpect + def run_one_round(): prompt = self.child_prompt # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. @@ -62,7 +68,8 @@ class CompileRunToBreakpointBench(BenchBase): self.stopwatch.reset() for i in range(count + 1): - # Ignore the first invoke lldb and run to the breakpoint turnaround time. + # Ignore the first invoke lldb and run to the breakpoint turnaround + # time. if i == 0: run_one_round() else: @@ -80,6 +87,7 @@ class CompileRunToBreakpointBench(BenchBase): def run_gdb_turnaround(self, exe, function, count): import pexpect + def run_one_round(): prompt = self.child_prompt @@ -102,8 +110,9 @@ class CompileRunToBreakpointBench(BenchBase): # Reset the stopwatch now. self.stopwatch.reset() - for i in range(count+1): - # Ignore the first invoke lldb and run to the breakpoint turnaround time. + for i in range(count + 1): + # Ignore the first invoke lldb and run to the breakpoint turnaround + # time. if i == 0: run_one_round() else: diff --git a/packages/Python/lldbsuite/test/concurrent_base.py b/packages/Python/lldbsuite/test/concurrent_base.py new file mode 100644 index 000000000000..4a7ae0b9c279 --- /dev/null +++ b/packages/Python/lldbsuite/test/concurrent_base.py @@ -0,0 +1,288 @@ +""" +A stress-test of sorts for LLDB's handling of threads in the inferior. + +This test sets a breakpoint in the main thread where test parameters (numbers of +threads) can be adjusted, runs the inferior to that point, and modifies the +locals that control the event thread counts. This test also sets a breakpoint in +breakpoint_func (the function executed by each 'breakpoint' thread) and a +watchpoint on a global modified in watchpoint_func. The inferior is continued +until exit or a crash takes place, and the number of events seen by LLDB is +verified to match the expected number of events. +""" + +from __future__ import print_function + + +import unittest2 +import os +import time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ConcurrentEventsBase(TestBase): + + # Concurrency is the primary test factor here, not debug info variants. + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + # Call super's setUp(). + super(ConcurrentEventsBase, self).setUp() + # Find the line number for our breakpoint. + self.filename = 'main.cpp' + source_relpath = os.path.join(os.path.pardir, self.filename) + self.thread_breakpoint_line = line_number( + source_relpath, '// Set breakpoint here') + self.setup_breakpoint_line = line_number( + source_relpath, '// Break here and adjust num') + self.finish_breakpoint_line = line_number( + source_relpath, '// Break here and verify one thread is active') + + def describe_threads(self): + ret = [] + for x in self.inferior_process: + id = x.GetIndexID() + reason = x.GetStopReason() + status = "stopped" if x.IsStopped() else "running" + reason_str = lldbutil.stop_reason_to_str(reason) + if reason == lldb.eStopReasonBreakpoint: + bpid = x.GetStopReasonDataAtIndex(0) + bp = self.inferior_target.FindBreakpointByID(bpid) + reason_str = "%s hit %d times" % ( + lldbutil.get_description(bp), bp.GetHitCount()) + elif reason == lldb.eStopReasonWatchpoint: + watchid = x.GetStopReasonDataAtIndex(0) + watch = self.inferior_target.FindWatchpointByID(watchid) + reason_str = "%s hit %d times" % ( + lldbutil.get_description(watch), watch.GetHitCount()) + elif reason == lldb.eStopReasonSignal: + signals = self.inferior_process.GetUnixSignals() + signal_name = signals.GetSignalAsCString( + x.GetStopReasonDataAtIndex(0)) + reason_str = "signal %s" % signal_name + + location = "\t".join([lldbutil.get_description( + x.GetFrameAtIndex(i)) for i in range(x.GetNumFrames())]) + ret.append( + "thread %d %s due to %s at\n\t%s" % + (id, status, reason_str, location)) + return ret + + def add_breakpoint(self, line, descriptions): + """ Adds a breakpoint at self.filename:line and appends its description to descriptions, and + returns the LLDB SBBreakpoint object. + """ + + bpno = lldbutil.run_break_set_by_file_and_line( + self, self.filename, line, num_expected_locations=-1) + bp = self.inferior_target.FindBreakpointByID(bpno) + descriptions.append( + ": file = 'main.cpp', line = %d" % + self.finish_breakpoint_line) + return bp + + def inferior_done(self): + """ Returns true if the inferior is done executing all the event threads (and is stopped at self.finish_breakpoint, + or has terminated execution. + """ + return self.finish_breakpoint.GetHitCount() > 0 or \ + self.crash_count > 0 or \ + self.inferior_process.GetState() == lldb.eStateExited + + def count_signaled_threads(self): + count = 0 + for thread in self.inferior_process: + if thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex( + 0) == self.inferior_process.GetUnixSignals().GetSignalNumberFromName('SIGUSR1'): + count += 1 + return count + + def do_thread_actions(self, + num_breakpoint_threads=0, + num_signal_threads=0, + num_watchpoint_threads=0, + num_crash_threads=0, + num_delay_breakpoint_threads=0, + num_delay_signal_threads=0, + num_delay_watchpoint_threads=0, + num_delay_crash_threads=0): + """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior + to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in + breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in + watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB + is verified to match the expected number of events. + """ + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Get the target + self.inferior_target = self.dbg.GetSelectedTarget() + + expected_bps = [] + + # Initialize all the breakpoints (main thread/aux thread) + self.setup_breakpoint = self.add_breakpoint( + self.setup_breakpoint_line, expected_bps) + self.finish_breakpoint = self.add_breakpoint( + self.finish_breakpoint_line, expected_bps) + + # Set the thread breakpoint + if num_breakpoint_threads + num_delay_breakpoint_threads > 0: + self.thread_breakpoint = self.add_breakpoint( + self.thread_breakpoint_line, expected_bps) + + # Verify breakpoints + self.expect( + "breakpoint list -f", + "Breakpoint locations shown correctly", + substrs=expected_bps) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + # Check we are at line self.setup_breakpoint + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint 1."]) + + # Initialize the (single) watchpoint on the global variable (g_watchme) + if num_watchpoint_threads + num_delay_watchpoint_threads > 0: + self.runCmd("watchpoint set variable g_watchme") + for w in self.inferior_target.watchpoint_iter(): + self.thread_watchpoint = w + self.assertTrue( + "g_watchme" in str( + self.thread_watchpoint), + "Watchpoint location not shown correctly") + + # Get the process + self.inferior_process = self.inferior_target.GetProcess() + + # We should be stopped at the setup site where we can set the number of + # threads doing each action (break/crash/signal/watch) + self.assertEqual( + self.inferior_process.GetNumThreads(), + 1, + 'Expected to stop before any additional threads are spawned.') + + self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads) + self.runCmd("expr num_crash_threads=%d" % num_crash_threads) + self.runCmd("expr num_signal_threads=%d" % num_signal_threads) + self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads) + + self.runCmd( + "expr num_delay_breakpoint_threads=%d" % + num_delay_breakpoint_threads) + self.runCmd( + "expr num_delay_crash_threads=%d" % + num_delay_crash_threads) + self.runCmd( + "expr num_delay_signal_threads=%d" % + num_delay_signal_threads) + self.runCmd( + "expr num_delay_watchpoint_threads=%d" % + num_delay_watchpoint_threads) + + # Continue the inferior so threads are spawned + self.runCmd("continue") + + # Make sure we see all the threads. The inferior program's threads all synchronize with a pseudo-barrier; that is, + # the inferior program ensures all threads are started and running + # before any thread triggers its 'event'. + num_threads = self.inferior_process.GetNumThreads() + expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \ + + num_signal_threads + num_delay_signal_threads \ + + num_watchpoint_threads + num_delay_watchpoint_threads \ + + num_crash_threads + num_delay_crash_threads + 1 + self.assertEqual( + num_threads, + expected_num_threads, + 'Expected to see %d threads, but seeing %d. Details:\n%s' % + (expected_num_threads, + num_threads, + "\n\t".join( + self.describe_threads()))) + + self.signal_count = self.count_signaled_threads() + self.crash_count = len( + lldbutil.get_crashed_threads( + self, self.inferior_process)) + + # Run to completion (or crash) + while not self.inferior_done(): + if self.TraceOn(): + self.runCmd("thread backtrace all") + self.runCmd("continue") + self.signal_count += self.count_signaled_threads() + self.crash_count += len( + lldbutil.get_crashed_threads( + self, self.inferior_process)) + + if num_crash_threads > 0 or num_delay_crash_threads > 0: + # Expecting a crash + self.assertTrue( + self.crash_count > 0, + "Expecting at least one thread to crash. Details: %s" % + "\t\n".join( + self.describe_threads())) + + # Ensure the zombie process is reaped + self.runCmd("process kill") + + elif num_crash_threads == 0 and num_delay_crash_threads == 0: + # There should be a single active thread (the main one) which hit + # the breakpoint after joining + self.assertEqual( + 1, + self.finish_breakpoint.GetHitCount(), + "Expected main thread (finish) breakpoint to be hit once") + + num_threads = self.inferior_process.GetNumThreads() + self.assertEqual( + 1, + num_threads, + "Expecting 1 thread but seeing %d. Details:%s" % + (num_threads, + "\n\t".join( + self.describe_threads()))) + self.runCmd("continue") + + # The inferior process should have exited without crashing + self.assertEqual( + 0, + self.crash_count, + "Unexpected thread(s) in crashed state") + self.assertEqual( + self.inferior_process.GetState(), + lldb.eStateExited, + PROCESS_EXITED) + + # Verify the number of actions took place matches expected numbers + expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads + breakpoint_hit_count = self.thread_breakpoint.GetHitCount( + ) if expected_breakpoint_threads > 0 else 0 + self.assertEqual( + expected_breakpoint_threads, + breakpoint_hit_count, + "Expected %d breakpoint hits, but got %d" % + (expected_breakpoint_threads, + breakpoint_hit_count)) + + expected_signal_threads = num_delay_signal_threads + num_signal_threads + self.assertEqual( + expected_signal_threads, + self.signal_count, + "Expected %d stops due to signal delivery, but got %d" % + (expected_signal_threads, + self.signal_count)) + + expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads + watchpoint_hit_count = self.thread_watchpoint.GetHitCount( + ) if expected_watchpoint_threads > 0 else 0 + self.assertEqual( + expected_watchpoint_threads, + watchpoint_hit_count, + "Expected %d watchpoint hits, got %d" % + (expected_watchpoint_threads, + watchpoint_hit_count)) diff --git a/packages/Python/lldbsuite/test/configuration.py b/packages/Python/lldbsuite/test/configuration.py index d797b17c164e..a0553a72c19d 100644 --- a/packages/Python/lldbsuite/test/configuration.py +++ b/packages/Python/lldbsuite/test/configuration.py @@ -23,26 +23,31 @@ import unittest2 # LLDB Modules import lldbsuite + def __setCrashInfoHook_Mac(text): from . import crashinfo crashinfo.setCrashReporterDescription(text) + def setupCrashInfoHook(): if platform.system() == "Darwin": from . import lock test_dir = os.environ['LLDB_TEST'] if not test_dir or not os.path.exists(test_dir): return - dylib_lock = os.path.join(test_dir,"crashinfo.lock") - dylib_src = os.path.join(test_dir,"crashinfo.c") - dylib_dst = os.path.join(test_dir,"crashinfo.so") + dylib_lock = os.path.join(test_dir, "crashinfo.lock") + dylib_src = os.path.join(test_dir, "crashinfo.c") + dylib_dst = os.path.join(test_dir, "crashinfo.so") try: compile_lock = lock.Lock(dylib_lock) compile_lock.acquire() - if not os.path.isfile(dylib_dst) or os.path.getmtime(dylib_dst) < os.path.getmtime(dylib_src): + if not os.path.isfile(dylib_dst) or os.path.getmtime( + dylib_dst) < os.path.getmtime(dylib_src): # we need to compile - cmd = "SDKROOT= xcrun clang %s -o %s -framework Python -Xlinker -dylib -iframework /System/Library/Frameworks/ -Xlinker -F /System/Library/Frameworks/" % (dylib_src,dylib_dst) - if subprocess.call(cmd,shell=True) != 0 or not os.path.isfile(dylib_dst): + cmd = "SDKROOT= xcrun clang %s -o %s -framework Python -Xlinker -dylib -iframework /System/Library/Frameworks/ -Xlinker -F /System/Library/Frameworks/" % ( + dylib_src, dylib_dst) + if subprocess.call( + cmd, shell=True) != 0 or not os.path.isfile(dylib_dst): raise Exception('command failed: "{}"'.format(cmd)) finally: compile_lock.release() @@ -92,9 +97,14 @@ skip_long_running_test = True # prints machine-readable output similar to what clang tests produce. parsable = False -# The regular expression pattern to match against eligible filenames as our test cases. +# The regular expression pattern to match against eligible filenames as +# our test cases. regexp = None +# Sets of tests which are excluded at runtime +skip_tests = None +xfail_tests = None + # By default, recorded session info for errored/failed test are dumped into its # own file under a session directory named after the timestamp of the test suite # run. Use '-s session-dir-name' to specify a specific dir name. @@ -121,7 +131,7 @@ verbose = 0 # By default, search from the script directory. # We can't use sys.path[0] to determine the script directory # because it doesn't work under a debugger -testdirs = [ os.path.dirname(os.path.realpath(__file__)) ] +testdirs = [os.path.dirname(os.path.realpath(__file__))] # Separator string. separator = '-' * 70 @@ -152,15 +162,18 @@ test_result = None rerun_all_issues = False rerun_max_file_threhold = 0 -# The names of all tests. Used to assert we don't have two tests with the same base name. +# The names of all tests. Used to assert we don't have two tests with the +# same base name. all_tests = set() # safe default -setCrashInfoHook = lambda x : None +setCrashInfoHook = lambda x: None + def shouldSkipBecauseOfCategories(test_categories): if useCategories: - if len(test_categories) == 0 or len(categoriesList & set(test_categories)) == 0: + if len(test_categories) == 0 or len( + categoriesList & set(test_categories)) == 0: return True for category in skipCategories: diff --git a/packages/Python/lldbsuite/test/darwin_log.py b/packages/Python/lldbsuite/test/darwin_log.py new file mode 100644 index 000000000000..3207ef0bccd8 --- /dev/null +++ b/packages/Python/lldbsuite/test/darwin_log.py @@ -0,0 +1,457 @@ +""" +Base class for DarwinLog tests. +""" + +# System imports +from __future__ import print_function + +import json +import os +import platform +import re +import sys +import threading + + +# lldb imports +import lldb +from lldb import SBProcess, SBTarget + +from lldbsuite.test import decorators +from lldbsuite.test import lldbtest +from lldbsuite.test import lldbtest_config +from lldbsuite.test import lldbutil + + +def expand_darwinlog_command(command): + return "plugin structured-data darwin-log " + command + + +def expand_darwinlog_settings_set_command(command): + return "settings set plugin.structured-data.darwin-log." + command + + +class DarwinLogTestBase(lldbtest.TestBase): + """Base class for DarwinLog test cases that are pexpect-based.""" + NO_DEBUG_INFO_TESTCASE = True + + CONTINUE_REGEX = re.compile(r"Process \d+ resuming") + + def setUp(self): + # Call super's setUp(). + super(DarwinLogTestBase, self).setUp() + + # Until other systems support this, exit + # early if we're not macOS version 10.12 + # or greater. + version = platform.mac_ver()[0].split('.') + if ((int(version[0]) == 10) and (int(version[1]) < 12) or + (int(version[0]) < 10)): + self.skipTest("DarwinLog tests currently require macOS 10.12+") + return + + self.child = None + self.child_prompt = '(lldb) ' + self.strict_sources = False + self.enable_process_monitor_logging = False + + def run_lldb_to_breakpoint(self, exe, source_file, line, + enable_command=None, settings_commands=None): + + import pexpect + # Set self.child_prompt, which is "(lldb) ". + prompt = self.child_prompt + + # So that the child gets torn down after the test. + self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, + self.lldbOption, exe)) + child = self.child + + # Turn on logging for what the child sends back. + if self.TraceOn(): + child.logfile_read = sys.stdout + + if self.enable_process_monitor_logging: + if platform.system() == 'Darwin': + self.runCmd( + "settings set target.process.extra-startup-command " + "QSetLogging:bitmask=LOG_DARWIN_LOG;") + self.expect_prompt() + + # Run the enable command if we have one. + if enable_command is not None: + self.runCmd(enable_command) + self.expect_prompt() + + # Disable showing of source lines at our breakpoint. + # This is necessary for the logging tests, because the very + # text we want to match for output from the running inferior + # will show up in the source as well. We don't want the source + # output to erroneously make a match with our expected output. + self.runCmd("settings set stop-line-count-before 0") + self.expect_prompt() + self.runCmd("settings set stop-line-count-after 0") + self.expect_prompt() + + # While we're debugging, turn on packet logging. + self.runCmd("log enable -f /tmp/packets.log gdb-remote packets") + self.expect_prompt() + + # Prevent mirroring of NSLog/os_log content to stderr. We want log + # messages to come exclusively through our log channel. + self.runCmd( + "settings set target.env-vars IDE_DISABLED_OS_ACTIVITY_DT_MODE=1") + self.expect_prompt() + + # Run any darwin-log settings commands now, before we enable logging. + if settings_commands is not None: + for setting_command in settings_commands: + self.runCmd( + expand_darwinlog_settings_set_command(setting_command)) + self.expect_prompt() + + # Set breakpoint right before the os_log() macros. We don't + # set it on the os_log*() calls because these are a number of + # nested-scoped calls that will cause the debugger to stop + # multiple times on the same line. That is difficult to match + # os_log() content by since it is non-deterministic what the + # ordering between stops and log lines will be. This is why + # we stop before, and then have the process run in a sleep + # afterwards, so we get the log messages while the target + # process is "running" (sleeping). + child.sendline('breakpoint set -f %s -l %d' % (source_file, line)) + child.expect_exact(prompt) + + # Now run to the breakpoint that we just set. + child.sendline('run') + child.expect_exact(prompt) + + # Ensure we stopped at a breakpoint. + self.runCmd("thread list") + self.expect(re.compile(r"stop reason = breakpoint")) + + # Now we're ready to check if DarwinLog is available. + if not self.darwin_log_available(): + self.skipTest("DarwinLog not available") + + def runCmd(self, cmd): + self.child.sendline(cmd) + + def expect_prompt(self, exactly=True): + self.expect(self.child_prompt, exactly=exactly) + + 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) + + def darwin_log_available(self): + self.runCmd("plugin structured-data darwin-log status") + self.expect(re.compile(r"Availability: ([\S]+)")) + return self.child.match is not None and ( + self.child.match.group(1) == "available") + + def do_test(self, enable_options, expect_regexes=None, + settings_commands=None): + """Test that a single fall-through reject rule rejects all logging.""" + self.build(dictionary=self.d) + self.setTearDownCleanup(dictionary=self.d) + + # Build the darwin-log enable command. + enable_cmd = expand_darwinlog_command('enable') + if enable_options is not None and len(enable_options) > 0: + enable_cmd += ' ' + ' '.join(enable_options) + + exe = os.path.join(os.getcwd(), self.exe_name) + self.run_lldb_to_breakpoint(exe, self.source, self.line, + enable_command=enable_cmd, + settings_commands=settings_commands) + self.expect_prompt() + + # Now go. + self.runCmd("process continue") + self.expect(self.CONTINUE_REGEX) + + if expect_regexes is None: + # Expect matching a log line or program exit. + # Test methods determine which ones are valid. + expect_regexes = ( + [re.compile(r"source-log-([^-]+)-(\S+)"), + re.compile(r"exited with status") + ]) + self.expect(expect_regexes) + + +def remove_add_mode_entry(log_entries): + """libtrace creates an "Add Mode:..." message when logging is enabled. + Strip this out of results since our test subjects don't create it.""" + return [entry for entry in log_entries + if "message" in entry and + not entry["message"].startswith("Add Mode:")] + + +class DarwinLogEventBasedTestBase(lldbtest.TestBase): + """Base class for event-based DarwinLog tests.""" + NO_DEBUG_INFO_TESTCASE = True + + class EventListenerThread(threading.Thread): + + def __init__(self, listener, process, trace_on, max_entry_count): + super( + DarwinLogEventBasedTestBase.EventListenerThread, + self).__init__() + self.process = process + self.listener = listener + self.trace_on = trace_on + self.max_entry_count = max_entry_count + self.exception = None + self.structured_data_event_count = 0 + self.wait_seconds = 2 + self.max_timeout_count = 4 + self.log_entries = [] + + def handle_structured_data_event(self, event): + structured_data = SBProcess.GetStructuredDataFromEvent(event) + if not structured_data.IsValid(): + if self.trace_on: + print("invalid structured data") + return + + # Track that we received a valid structured data event. + self.structured_data_event_count += 1 + + # Grab the individual log entries from the JSON. + stream = lldb.SBStream() + structured_data.GetAsJSON(stream) + dict = json.loads(stream.GetData()) + self.log_entries.extend(dict["events"]) + if self.trace_on: + print("Structured data (raw):", stream.GetData()) + + # Print the pretty-printed version. + if self.trace_on: + stream.Clear() + structured_data.PrettyPrint(stream) + print("Structured data (pretty print):", + stream.GetData()) + + def done(self, timeout_count): + """Returns True when we're done listening for events.""" + # See if we should consider the number of events retrieved. + if self.max_entry_count is not None: + if len(self.log_entries) >= self.max_entry_count: + # We've received the max threshold of events expected, + # we can exit here. + if self.trace_on: + print("Event listener thread exiting due to max " + "expected log entry count being reached.") + return True + + # If our event timeout count has exceeded our maximum timeout count, + # we're done. + if timeout_count >= self.max_timeout_count: + if self.trace_on: + print("Event listener thread exiting due to max number of " + "WaitForEvent() timeouts being reached.") + return True + + # If our process is dead, we're done. + if not self.process.is_alive: + if self.trace_on: + print("Event listener thread exiting due to test inferior " + "exiting.") + return True + + # We're not done. + return False + + def run(self): + event = lldb.SBEvent() + try: + timeout_count = 0 + + # Wait up to 4 times for the event to arrive. + while not self.done(timeout_count): + if self.trace_on: + print("Calling wait for event...") + if self.listener.WaitForEvent(self.wait_seconds, event): + while event.IsValid(): + # Check if it's a process event. + if SBProcess.EventIsStructuredDataEvent(event): + self.handle_structured_data_event(event) + else: + if self.trace_on: + print("ignoring unexpected event:", + lldbutil.get_description(event)) + # Grab the next event, if there is one. + event.Clear() + if not self.listener.GetNextEvent(event): + if self.trace_on: + print("listener has no more events " + "available at this time") + else: + if self.trace_on: + print("timeout occurred waiting for event...") + timeout_count += 1 + self.listener.Clear() + except Exception as e: + self.exception = e + + def setUp(self): + # Call super's setUp(). + super(DarwinLogEventBasedTestBase, self).setUp() + + # Until other systems support this, exit + # early if we're not macOS version 10.12 + # or greater. + version = platform.mac_ver()[0].split('.') + if ((int(version[0]) == 10) and (int(version[1]) < 12) or + (int(version[0]) < 10)): + self.skipTest("DarwinLog tests currently require macOS 10.12+") + return + + # Source filename. + self.source = 'main.c' + + # Output filename. + self.exe_name = 'a.out' + self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name} + + # Locate breakpoint. + self.line = lldbtest.line_number(self.source, '// break here') + + # Enable debugserver logging of the darwin log collection + # mechanism. + self.runCmd("settings set target.process.extra-startup-command " + "QSetLogging:bitmask=LOG_DARWIN_LOG;") + + def darwin_log_available(self): + match = self.match("plugin structured-data darwin-log status", + patterns=[r"Availability: ([\S]+)"]) + return match is not None and (match.group(1) == "available") + + def do_test(self, enable_options, settings_commands=None, + run_enable_after_breakpoint=False, max_entry_count=None): + """Runs the test inferior, returning collected events. + + This method runs the test inferior to the first breakpoint hit. + It then adds a listener for structured data events, and collects + all events from that point forward until end of execution of the + test inferior. It then returns those events. + + @return + A list of structured data events received, in the order they + were received. + """ + self.build(dictionary=self.d) + self.setTearDownCleanup(dictionary=self.d) + + exe = os.path.join(os.getcwd(), self.exe_name) + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, lldbtest.VALID_TARGET) + + # Run the darwin-log settings commands. + if settings_commands is not None: + for setting_command in settings_commands: + self.runCmd( + expand_darwinlog_settings_set_command(setting_command)) + + # Build the darwin-log enable command. + enable_cmd = expand_darwinlog_command("enable") + if enable_options is not None and len(enable_options) > 0: + enable_cmd += ' ' + ' '.join(enable_options) + + # Run the darwin-log enable command now if we are not supposed + # to do it at the first breakpoint. This tests the start-up + # code, which has the benefit of being able to set os_log-related + # environment variables. + if not run_enable_after_breakpoint: + self.runCmd(enable_cmd) + + # Create the breakpoint. + breakpoint = target.BreakpointCreateByLocation(self.source, self.line) + self.assertIsNotNone(breakpoint) + self.assertTrue(breakpoint.IsValid()) + self.assertEqual(1, breakpoint.GetNumLocations(), + "Should have found one breakpoint") + + # Enable packet logging. + # self.runCmd("log enable -f /tmp/packets.log gdb-remote packets") + # self.runCmd("log enable lldb process") + + # Launch the process - doesn't stop at entry. + process = target.LaunchSimple(None, None, os.getcwd()) + self.assertIsNotNone(process, lldbtest.PROCESS_IS_VALID) + + # Keep track of whether we're tracing output. + trace_on = self.TraceOn() + + # Get the next thread that stops. + from lldbsuite.test.lldbutil import get_stopped_thread + thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + self.assertIsNotNone(thread, "There should be a thread stopped " + "due to breakpoint") + + # The process should be stopped at this point. + self.expect("process status", lldbtest.PROCESS_STOPPED, + patterns=['Process .* stopped']) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", lldbtest.STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', 'stop reason = breakpoint']) + + # And our one and only breakpoint should have been hit. + self.assertEquals(breakpoint.GetHitCount(), 1) + + # Check if DarwinLog is available. This check cannot be done + # until after the process has started, as the feature availability + # comes through the stub. The stub isn't running until + # the target process is running. So this is really the earliest + # we can check. + if not self.darwin_log_available(): + self.skipTest("DarwinLog not available") + + # Now setup the structured data listener. + # + # Grab the broadcaster for the process. We'll be attaching our + # listener to it. + broadcaster = process.GetBroadcaster() + self.assertIsNotNone(broadcaster) + + listener = lldb.SBListener("SBStructuredData listener") + self.assertIsNotNone(listener) + + rc = broadcaster.AddListener( + listener, lldb.SBProcess.eBroadcastBitStructuredData) + self.assertTrue(rc, "Successfully add listener to process broadcaster") + + # Start the listening thread to retrieve the events. + # Bump up max entry count for the potentially included Add Mode: + # entry. + if max_entry_count is not None: + max_entry_count += 1 + event_thread = self.EventListenerThread(listener, process, trace_on, + max_entry_count) + event_thread.start() + + # Continue the test inferior. We should get any events after this. + process.Continue() + + # Wait until the event thread terminates. + # print("main thread now waiting for event thread to receive events.") + event_thread.join() + + # If the process is still alive, we kill it here. + if process.is_alive: + process.Kill() + + # Fail on any exceptions that occurred during event execution. + if event_thread.exception is not None: + # Re-raise it here so it shows up as a test error. + raise event_thread + + # Return the collected logging events. + return remove_add_mode_entry(event_thread.log_entries) diff --git a/packages/Python/lldbsuite/test/decorators.py b/packages/Python/lldbsuite/test/decorators.py index 93e48272c5d3..866923607867 100644 --- a/packages/Python/lldbsuite/test/decorators.py +++ b/packages/Python/lldbsuite/test/decorators.py @@ -5,6 +5,7 @@ from __future__ import print_function from distutils.version import LooseVersion, StrictVersion from functools import wraps import os +import platform import re import sys import tempfile @@ -24,24 +25,33 @@ from lldbsuite.support import funcutils from lldbsuite.test import lldbplatform from lldbsuite.test import lldbplatformutil + class DecorateMode: Skip, Xfail = range(2) - + # You can use no_match to reverse the test of the conditional that is used to match keyword # arguments in the skip / xfail decorators. If oslist=["windows", "linux"] skips windows -# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows or linux. +# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows +# or linux. class no_match: + def __init__(self, item): self.item = item + def _check_expected_version(comparison, expected, actual): - def fn_leq(x,y): return x <= y - def fn_less(x,y): return x < y - def fn_geq(x,y): return x >= y - def fn_greater(x,y): return x > y - def fn_eq(x,y): return x == y - def fn_neq(x,y): return x != y + def fn_leq(x, y): return x <= y + + def fn_less(x, y): return x < y + + def fn_geq(x, y): return x >= y + + def fn_greater(x, y): return x > y + + def fn_eq(x, y): return x == y + + def fn_neq(x, y): return x != y op_lookup = { "==": fn_eq, @@ -52,11 +62,14 @@ def _check_expected_version(comparison, expected, actual): "<": fn_less, ">=": fn_geq, "<=": fn_leq - } + } expected_str = '.'.join([str(x) for x in expected]) actual_str = '.'.join([str(x) for x in actual]) - return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) + return op_lookup[comparison]( + LooseVersion(actual_str), + LooseVersion(expected_str)) + def _match_decorator_property(expected, actual): if actual is None or expected is None: @@ -64,17 +77,21 @@ def _match_decorator_property(expected, actual): if isinstance(expected, no_match): return not _match_decorator_property(expected.item, actual) - elif isinstance(expected, (re._pattern_type,)+six.string_types): + elif isinstance(expected, (re._pattern_type,) + six.string_types): return re.search(expected, actual) is not None elif hasattr(expected, "__iter__"): - return any([x is not None and _match_decorator_property(x, actual) for x in expected]) + return any([x is not None and _match_decorator_property(x, actual) + for x in expected]) else: return expected == actual + def expectedFailure(expected_fn, bugnumber=None): def expectedFailure_impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("Decorator can only be used to decorate a test method") + raise Exception( + "Decorator can only be used to decorate a test method") + @wraps(func) def wrapper(*args, **kwargs): self = args[0] @@ -102,10 +119,12 @@ def expectedFailure(expected_fn, bugnumber=None): else: return expectedFailure_impl + def skipTestIfFn(expected_fn, bugnumber=None): def skipTestIfFn_impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("@skipTestIfFn can only be used to decorate a test method") + raise Exception( + "@skipTestIfFn can only be used to decorate a test method") @wraps(func) def wrapper(*args, **kwargs): @@ -116,7 +135,7 @@ def skipTestIfFn(expected_fn, bugnumber=None): reason = expected_fn() if reason is not None: - self.skipTest(reason) + self.skipTest(reason) else: func(*args, **kwargs) return wrapper @@ -124,30 +143,56 @@ def skipTestIfFn(expected_fn, bugnumber=None): # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called # the first way, the first argument will be the actual function because decorators are - # weird like that. So this is basically a check that says "how was the decorator used" + # weird like that. So this is basically a check that says "how was the + # decorator used" if six.callable(bugnumber): return skipTestIfFn_impl(bugnumber) else: return skipTestIfFn_impl + def _decorateTest(mode, - bugnumber=None, oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - remote=None): + bugnumber=None, oslist=None, hostoslist=None, + compiler=None, compiler_version=None, + archs=None, triple=None, + debug_info=None, + swig_version=None, py_version=None, + macos_version=None, + remote=None): def fn(self): - skip_for_os = _match_decorator_property(lldbplatform.translate(oslist), self.getPlatform()) - skip_for_hostos = _match_decorator_property(lldbplatform.translate(hostoslist), lldbplatformutil.getHostPlatform()) - skip_for_compiler = _match_decorator_property(compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version) - skip_for_arch = _match_decorator_property(archs, self.getArchitecture()) - skip_for_debug_info = _match_decorator_property(debug_info, self.debug_info) - skip_for_triple = _match_decorator_property(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) - skip_for_remote = _match_decorator_property(remote, lldb.remote_platform is not None) - - skip_for_swig_version = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (_check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) - skip_for_py_version = (py_version is None) or _check_expected_version(py_version[0], py_version[1], sys.version_info) + skip_for_os = _match_decorator_property( + lldbplatform.translate(oslist), self.getPlatform()) + skip_for_hostos = _match_decorator_property( + lldbplatform.translate(hostoslist), + lldbplatformutil.getHostPlatform()) + skip_for_compiler = _match_decorator_property( + compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version) + skip_for_arch = _match_decorator_property( + archs, self.getArchitecture()) + skip_for_debug_info = _match_decorator_property( + debug_info, self.debug_info) + skip_for_triple = _match_decorator_property( + triple, lldb.DBG.GetSelectedPlatform().GetTriple()) + skip_for_remote = _match_decorator_property( + remote, lldb.remote_platform is not None) + + skip_for_swig_version = ( + swig_version is None) or ( + not hasattr( + lldb, + 'swig_version')) or ( + _check_expected_version( + swig_version[0], + swig_version[1], + lldb.swig_version)) + skip_for_py_version = ( + py_version is None) or _check_expected_version( + py_version[0], py_version[1], sys.version_info) + skip_for_macos_version = (macos_version is None) or ( + _check_expected_version( + macos_version[0], + macos_version[1], + platform.mac_ver()[0])) # For the test to be skipped, all specified (e.g. not None) parameters must be True. # An unspecified parameter means "any", so those are marked skip by default. And we skip @@ -160,6 +205,7 @@ def _decorateTest(mode, (triple, skip_for_triple, "target triple"), (swig_version, skip_for_swig_version, "swig version"), (py_version, skip_for_py_version, "python version"), + (macos_version, skip_for_macos_version, "macOS version"), (remote, skip_for_remote, "platform locality (remote/local)")] reasons = [] final_skip_result = True @@ -169,10 +215,13 @@ def _decorateTest(mode, reasons.append(this_condition[2]) reason_str = None if final_skip_result: - mode_str = {DecorateMode.Skip : "skipping", DecorateMode.Xfail : "xfailing"}[mode] + mode_str = { + DecorateMode.Skip: "skipping", + DecorateMode.Xfail: "xfailing"}[mode] if len(reasons) > 0: reason_str = ",".join(reasons) - reason_str = "{} due to the following parameter(s): {}".format(mode_str, reason_str) + reason_str = "{} due to the following parameter(s): {}".format( + mode_str, reason_str) else: reason_str = "{} unconditionally" if bugnumber is not None and not six.callable(bugnumber): @@ -192,21 +241,25 @@ def _decorateTest(mode, # @expectedFailureAll, xfail for all platform/compiler/arch, # @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture # @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 + + def expectedFailureAll(bugnumber=None, oslist=None, hostoslist=None, compiler=None, compiler_version=None, archs=None, triple=None, debug_info=None, swig_version=None, py_version=None, + macos_version=None, remote=None): return _decorateTest(DecorateMode.Xfail, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - remote=remote) + bugnumber=bugnumber, + oslist=oslist, hostoslist=hostoslist, + compiler=compiler, compiler_version=compiler_version, + archs=archs, triple=triple, + debug_info=debug_info, + swig_version=swig_version, py_version=py_version, + macos_version=None, + remote=remote) # provide a function to skip on defined oslist, compiler version, and archs @@ -221,28 +274,35 @@ def skipIf(bugnumber=None, archs=None, triple=None, debug_info=None, swig_version=None, py_version=None, + macos_version=None, remote=None): return _decorateTest(DecorateMode.Skip, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - remote=remote) + bugnumber=bugnumber, + oslist=oslist, hostoslist=hostoslist, + compiler=compiler, compiler_version=compiler_version, + archs=archs, triple=triple, + debug_info=debug_info, + swig_version=swig_version, py_version=py_version, + macos_version=macos_version, + remote=remote) + def _skip_for_android(reason, api_levels, archs): def impl(obj): - result = lldbplatformutil.match_android_device(obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels) + result = lldbplatformutil.match_android_device( + obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels) return reason if result else None return impl + def add_test_categories(cat): """Add test categories to a TestCase method""" cat = test_categories.validate(cat, True) + def impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("@add_test_categories can only be used to decorate a test method") + raise Exception( + "@add_test_categories can only be used to decorate a test method") if hasattr(func, "categories"): cat.extend(func.categories) func.categories = cat @@ -250,6 +310,7 @@ def add_test_categories(cat): return impl + def benchmarks_test(func): """Decorate the item as a benchmarks test.""" def should_skip_benchmarks_test(): @@ -260,11 +321,14 @@ def benchmarks_test(func): result.__benchmarks_test__ = True return result + def no_debug_info_test(func): """Decorate the item as a test what don't use any debug info. If this annotation is specified then the test runner won't generate a separate test for each debug info format. """ if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("@no_debug_info_test can only be used to decorate a test method") + raise Exception( + "@no_debug_info_test can only be used to decorate a test method") + @wraps(func) def wrapper(self, *args, **kwargs): return func(self, *args, **kwargs) @@ -273,30 +337,51 @@ def no_debug_info_test(func): wrapper.__no_debug_info_test__ = True return wrapper + def debugserver_test(func): """Decorate the item as a debugserver test.""" def should_skip_debugserver_test(): return "debugserver tests" if configuration.dont_do_debugserver_test else None return skipTestIfFn(should_skip_debugserver_test)(func) + def llgs_test(func): """Decorate the item as a lldb-server test.""" def should_skip_llgs_tests(): return "llgs tests" if configuration.dont_do_llgs_test else None return skipTestIfFn(should_skip_llgs_tests)(func) + def not_remote_testsuite_ready(func): """Decorate the item as a test which is not ready yet for remote testsuite.""" def is_remote(): return "Not ready for remote testsuite" if lldb.remote_platform else None return skipTestIfFn(is_remote)(func) -def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None): - return expectedFailureAll(oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, debug_info=debug_info) + +def expectedFailureOS( + oslist, + bugnumber=None, + compilers=None, + debug_info=None, + archs=None): + return expectedFailureAll( + oslist=oslist, + bugnumber=bugnumber, + compiler=compilers, + archs=archs, + debug_info=debug_info) + def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): - # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. - return expectedFailureOS(lldbplatform.darwin_all, bugnumber, compilers, debug_info=debug_info) + # For legacy reasons, we support both "darwin" and "macosx" as OS X + # triples. + return expectedFailureOS( + lldbplatform.darwin_all, + bugnumber, + compilers, + debug_info=debug_info) + def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): """ Mark a test as xfail for Android. @@ -308,10 +393,17 @@ def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): arch - A sequence of architecture names specifying the architectures for which a test is expected to fail. None means all architectures. """ - return expectedFailure(_skip_for_android("xfailing on android", api_levels, archs), bugnumber) + return expectedFailure( + _skip_for_android( + "xfailing on android", + api_levels, + archs), + bugnumber) # Flakey tests get two chances to run. If they fail the first time round, the result formatter # makes sure it is run one more time. + + def expectedFlakey(expected_fn, bugnumber=None): def expectedFailure_impl(func): @wraps(func) @@ -335,52 +427,76 @@ def expectedFlakey(expected_fn, bugnumber=None): else: return expectedFailure_impl + def expectedFlakeyDwarf(bugnumber=None): def fn(self): return self.debug_info == "dwarf" return expectedFlakey(fn, bugnumber) + def expectedFlakeyDsym(bugnumber=None): def fn(self): return self.debug_info == "dwarf" return expectedFlakey(fn, bugnumber) + def expectedFlakeyOS(oslist, bugnumber=None, compilers=None): def fn(self): return (self.getPlatform() in oslist and self.expectedCompiler(compilers)) return expectedFlakey(fn, bugnumber) + def expectedFlakeyDarwin(bugnumber=None, compilers=None): - # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. - return expectedFlakeyOS(lldbplatformutil.getDarwinOSTriples(), bugnumber, compilers) + # For legacy reasons, we support both "darwin" and "macosx" as OS X + # triples. + return expectedFlakeyOS( + lldbplatformutil.getDarwinOSTriples(), + bugnumber, + compilers) + def expectedFlakeyFreeBSD(bugnumber=None, compilers=None): return expectedFlakeyOS(['freebsd'], bugnumber, compilers) + def expectedFlakeyLinux(bugnumber=None, compilers=None): return expectedFlakeyOS(['linux'], bugnumber, compilers) + def expectedFlakeyNetBSD(bugnumber=None, compilers=None): return expectedFlakeyOS(['netbsd'], bugnumber, compilers) + def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None): if compiler_version is None: - compiler_version=['=', None] + compiler_version = ['=', None] + def fn(self): return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version) return expectedFlakey(fn, bugnumber) # @expectedFlakeyClang('bugnumber', ['<=', '3.4']) + + def expectedFlakeyClang(bugnumber=None, compiler_version=None): return expectedFlakeyCompiler('clang', compiler_version, bugnumber) # @expectedFlakeyGcc('bugnumber', ['<=', '3.4']) + + def expectedFlakeyGcc(bugnumber=None, compiler_version=None): return expectedFlakeyCompiler('gcc', compiler_version, bugnumber) + def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None): - return expectedFlakey(_skip_for_android("flakey on android", api_levels, archs), bugnumber) + return expectedFlakey( + _skip_for_android( + "flakey on android", + api_levels, + archs), + bugnumber) + def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" @@ -388,61 +504,88 @@ def skipIfRemote(func): return "skip on remote platform" if lldb.remote_platform else None return skipTestIfFn(is_remote)(func) + def skipIfRemoteDueToDeadlock(func): """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" def is_remote(): return "skip on remote platform (deadlocks)" if lldb.remote_platform else None return skipTestIfFn(is_remote)(func) + def skipIfNoSBHeaders(func): """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" def are_sb_headers_missing(): if lldbplatformutil.getHostPlatform() == 'darwin': - header = os.path.join(os.environ["LLDB_LIB_DIR"], 'LLDB.framework', 'Versions','Current','Headers','LLDB.h') - else: - header = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h") + header = os.path.join( + os.environ["LLDB_LIB_DIR"], + 'LLDB.framework', + 'Versions', + 'Current', + 'Headers', + 'LLDB.h') + if os.path.exists(header): + return None + + header = os.path.join( + os.environ["LLDB_SRC"], + "include", + "lldb", + "API", + "LLDB.h") if not os.path.exists(header): return "skip because LLDB.h header not found" return None return skipTestIfFn(are_sb_headers_missing)(func) + def skipIfiOSSimulator(func): """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" def is_ios_simulator(): return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None return skipTestIfFn(is_ios_simulator)(func) + def skipIfFreeBSD(func): """Decorate the item to skip tests that should be skipped on FreeBSD.""" return skipIfPlatform(["freebsd"])(func) + def skipIfNetBSD(func): """Decorate the item to skip tests that should be skipped on NetBSD.""" return skipIfPlatform(["netbsd"])(func) + def skipIfDarwin(func): """Decorate the item to skip tests that should be skipped on Darwin.""" - return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_all))(func) + return skipIfPlatform( + lldbplatform.translate( + lldbplatform.darwin_all))(func) + def skipIfLinux(func): """Decorate the item to skip tests that should be skipped on Linux.""" return skipIfPlatform(["linux"])(func) + def skipIfWindows(func): """Decorate the item to skip tests that should be skipped on Windows.""" return skipIfPlatform(["windows"])(func) + def skipUnlessWindows(func): """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" return skipUnlessPlatform(["windows"])(func) + def skipUnlessDarwin(func): """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func) + def skipUnlessGoInstalled(func): """Decorate the item to skip tests when no Go compiler is available.""" + def is_go_missing(self): compiler = self.getGoCompilerVersion() if not compiler: @@ -450,7 +593,8 @@ def skipUnlessGoInstalled(func): match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler) if not match_version: # Couldn't determine version. - return "skipping because go version could not be parsed out of {}".format(compiler) + return "skipping because go version could not be parsed out of {}".format( + compiler) else: min_strict_version = StrictVersion("1.4.0") compiler_strict_version = StrictVersion(match_version.group(1)) @@ -460,20 +604,28 @@ def skipUnlessGoInstalled(func): return None return skipTestIfFn(is_go_missing)(func) + def skipIfHostIncompatibleWithRemote(func): """Decorate the item to skip tests if binaries built on this host are incompatible.""" + def is_host_incompatible_with_remote(self): host_arch = self.getLldbArchitecture() host_platform = lldbplatformutil.getHostPlatform() target_arch = self.getArchitecture() target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() - if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch: - return "skipping because target %s is not compatible with host architecture %s" % (target_arch, host_arch) - elif target_platform != host_platform: - return "skipping because target is %s but host is %s" % (target_platform, host_platform) + if not (target_arch == 'x86_64' and host_arch == + 'i386') and host_arch != target_arch: + return "skipping because target %s is not compatible with host architecture %s" % ( + target_arch, host_arch) + if target_platform != host_platform: + return "skipping because target is %s but host is %s" % ( + target_platform, host_platform) + if lldbplatformutil.match_android_device(target_arch): + return "skipping because target is android" return None return skipTestIfFn(is_host_incompatible_with_remote)(func) + def skipIfPlatform(oslist): """Decorate the item to skip tests if running on one of the listed platforms.""" # This decorator cannot be ported to `skipIf` yet because it is used on entire @@ -481,12 +633,14 @@ def skipIfPlatform(oslist): return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist, "skip on %s" % (", ".join(oslist))) + def skipUnlessPlatform(oslist): """Decorate the item to skip tests unless running on one of the listed platforms.""" # This decorator cannot be ported to `skipIf` yet because it is used on entire # classes, which `skipIf` explicitly forbids. return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist, - "requires on of %s" % (", ".join(oslist))) + "requires one of %s" % (", ".join(oslist))) + def skipIfTargetAndroid(api_levels=None, archs=None): """Decorator to skip tests when the target is Android. @@ -497,28 +651,50 @@ def skipIfTargetAndroid(api_levels=None, archs=None): arch - A sequence of architecture names specifying the architectures for which a test is skipped. None means all architectures. """ - return skipTestIfFn(_skip_for_android("skipping for android", api_levels, archs)) + return skipTestIfFn( + _skip_for_android( + "skipping for android", + api_levels, + archs)) -def skipUnlessCompilerRt(func): - """Decorate the item to skip tests if testing remotely.""" - def is_compiler_rt_missing(): - compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt") - return "compiler-rt not found" if not os.path.exists(compilerRtPath) else None - return skipTestIfFn(is_compiler_rt_missing)(func) def skipUnlessThreadSanitizer(func): """Decorate the item to skip test unless Clang -fsanitize=thread is supported.""" + def is_compiler_clang_with_thread_sanitizer(self): compiler_path = self.getCompiler() compiler = os.path.basename(compiler_path) if not compiler.startswith("clang"): return "Test requires clang as compiler" + if lldbplatformutil.getPlatform() == 'windows': + return "TSAN tests not compatible with 'windows'" + # rdar://28659145 - TSAN tests don't look like they're supported on i386 + if self.getArchitecture() == 'i386' and platform.system() == 'Darwin': + return "TSAN tests not compatible with i386 targets" f = tempfile.NamedTemporaryFile() cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() != None: + if os.popen(cmd).close() is not None: return None # The compiler cannot compile at all, let's *not* skip the test cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() != None: + if os.popen(cmd).close() is not None: return "Compiler cannot compile with -fsanitize=thread" return None return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func) + +def skipUnlessAddressSanitizer(func): + """Decorate the item to skip test unless Clang -fsanitize=thread is supported.""" + + def is_compiler_with_address_sanitizer(self): + compiler_path = self.getCompiler() + compiler = os.path.basename(compiler_path) + f = tempfile.NamedTemporaryFile() + if lldbplatformutil.getPlatform() == 'windows': + return "ASAN tests not compatible with 'windows'" + cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) + if os.popen(cmd).close() is not None: + return None # The compiler cannot compile at all, let's *not* skip the test + cmd = "echo 'int main() {}' | %s -fsanitize=address -x c -o %s -" % (compiler_path, f.name) + if os.popen(cmd).close() is not None: + return "Compiler cannot compile with -fsanitize=address" + return None + return skipTestIfFn(is_compiler_with_address_sanitizer)(func) diff --git a/packages/Python/lldbsuite/test/dosep.py b/packages/Python/lldbsuite/test/dosep.py index 37ca91adb140..6e98beb90cca 100644 --- a/packages/Python/lldbsuite/test/dosep.py +++ b/packages/Python/lldbsuite/test/dosep.py @@ -46,6 +46,7 @@ import signal import sys import threading +from six import StringIO from six.moves import queue # Our packages and modules @@ -64,6 +65,8 @@ from .test_runner import process_control # Status codes for running command with timeout. eTimedOut, ePassed, eFailed = 124, 0, 1 +g_session_dir = None +g_runner_context = None output_lock = None test_counter = None total_tests = None @@ -104,6 +107,7 @@ def setup_global_variables( global GET_WORKER_INDEX GET_WORKER_INDEX = get_worker_index_use_pid + def report_test_failure(name, command, output, timeout): global output_lock with output_lock: @@ -152,14 +156,15 @@ def parse_test_results(output): result, re.MULTILINE) error_count = re.search("^RESULT:.*([0-9]+) errors", result, re.MULTILINE) - unexpected_success_count = re.search("^RESULT:.*([0-9]+) unexpected successes", - result, re.MULTILINE) + unexpected_success_count = re.search( + "^RESULT:.*([0-9]+) unexpected successes", result, re.MULTILINE) if pass_count is not None: passes = passes + int(pass_count.group(1)) if fail_count is not None: failures = failures + int(fail_count.group(1)) if unexpected_success_count is not None: - unexpected_successes = unexpected_successes + int(unexpected_success_count.group(1)) + unexpected_successes = unexpected_successes + \ + int(unexpected_success_count.group(1)) if error_count is not None: failures = failures + int(error_count.group(1)) return passes, failures, unexpected_successes @@ -167,6 +172,7 @@ def parse_test_results(output): class DoTestProcessDriver(process_control.ProcessDriver): """Drives the dotest.py inferior process and handles bookkeeping.""" + def __init__(self, output_file, output_file_lock, pid_events, file_name, soft_terminate_timeout): super(DoTestProcessDriver, self).__init__( @@ -210,7 +216,11 @@ class DoTestProcessDriver(process_control.ProcessDriver): # only stderr does. report_test_pass(self.file_name, output[1]) else: - report_test_failure(self.file_name, command, output[1], was_timeout) + report_test_failure( + self.file_name, + command, + output[1], + was_timeout) # Save off the results for the caller. self.results = ( @@ -220,6 +230,52 @@ class DoTestProcessDriver(process_control.ProcessDriver): failures, unexpected_successes) + def on_timeout_pre_kill(self): + # We're just about to have a timeout take effect. Here's our chance + # to do a pre-kill action. + + # For now, we look to see if the lldbsuite.pre_kill module has a + # runner for our platform. + module_name = "lldbsuite.pre_kill_hook." + platform.system().lower() + import importlib + try: + module = importlib.import_module(module_name) + except ImportError: + # We don't have one for this platform. Skip. + sys.stderr.write("\nwarning: no timeout handler module: " + + module_name + "\n") + return + + # Try to run the pre-kill-hook method. + try: + # Run the pre-kill command. + output_io = StringIO() + module.do_pre_kill(self.pid, g_runner_context, output_io) + + # Write the output to a filename associated with the test file and + # pid. + MAX_UNCOMPRESSED_BYTE_COUNT = 10 * 1024 + + content = output_io.getvalue() + compress_output = len(content) > MAX_UNCOMPRESSED_BYTE_COUNT + basename = "{}-{}.sample".format(self.file_name, self.pid) + sample_path = os.path.join(g_session_dir, basename) + + if compress_output: + # Write compressed output into a .zip file. + from zipfile import ZipFile, ZIP_DEFLATED + zipfile = sample_path + ".zip" + with ZipFile(zipfile, "w", ZIP_DEFLATED) as sample_zip: + sample_zip.writestr(basename, content) + else: + # Write raw output into a text file. + with open(sample_path, "w") as output_file: + output_file.write(content) + except Exception as e: + sys.stderr.write("caught exception while running " + "pre-kill action: {}\n".format(e)) + return + def is_exceptional_exit(self): """Returns whether the process returned a timeout. @@ -628,32 +684,52 @@ def find_test_files_in_dir_tree(dir_root, found_func): found_func(root, tests) -def initialize_global_vars_common(num_threads, test_work_items): - global total_tests, test_counter, test_name_len +def initialize_global_vars_common(num_threads, test_work_items, session_dir, + runner_context): + global g_session_dir, g_runner_context, total_tests, test_counter + global test_name_len total_tests = sum([len(item[1]) for item in test_work_items]) test_counter = multiprocessing.Value('i', 0) test_name_len = multiprocessing.Value('i', 0) + g_session_dir = session_dir + g_runner_context = runner_context if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()): - print("Testing: %d test suites, %d thread%s" % ( - total_tests, num_threads, (num_threads > 1) * "s"), file=sys.stderr) + print( + "Testing: %d test suites, %d thread%s" % + (total_tests, + num_threads, + (num_threads > 1) * + "s"), + file=sys.stderr) update_progress() -def initialize_global_vars_multiprocessing(num_threads, test_work_items): +def initialize_global_vars_multiprocessing(num_threads, test_work_items, + session_dir, runner_context): # Initialize the global state we'll use to communicate with the # rest of the flat module. global output_lock output_lock = multiprocessing.RLock() - initialize_global_vars_common(num_threads, test_work_items) + initialize_global_vars_common(num_threads, test_work_items, session_dir, + runner_context) -def initialize_global_vars_threading(num_threads, test_work_items): +def initialize_global_vars_threading(num_threads, test_work_items, session_dir, + runner_context): """Initializes global variables used in threading mode. + @param num_threads specifies the number of workers used. + @param test_work_items specifies all the work items that will be processed. + + @param session_dir the session directory where test-run-speciif files are + written. + + @param runner_context a dictionary of platform-related data that is passed + to the timeout pre-kill hook. """ # Initialize the global state we'll use to communicate with the # rest of the flat module. @@ -671,11 +747,11 @@ def initialize_global_vars_threading(num_threads, test_work_items): index_map[thread_id] = len(index_map) return index_map[thread_id] - global GET_WORKER_INDEX GET_WORKER_INDEX = get_worker_index_threading - initialize_global_vars_common(num_threads, test_work_items) + initialize_global_vars_common(num_threads, test_work_items, session_dir, + runner_context) def ctrl_c_loop(main_op_func, done_func, ctrl_c_handler): @@ -822,7 +898,8 @@ def workers_and_async_done(workers, async_map): return True -def multiprocessing_test_runner(num_threads, test_work_items): +def multiprocessing_test_runner(num_threads, test_work_items, session_dir, + runner_context): """Provides hand-wrapped pooling test runner adapter with Ctrl-C support. This concurrent test runner is based on the multiprocessing @@ -836,10 +913,17 @@ def multiprocessing_test_runner(num_threads, test_work_items): @param test_work_items the iterable of test work item tuples to run. + + @param session_dir the session directory where test-run-speciif files are + written. + + @param runner_context a dictionary of platform-related data that is passed + to the timeout pre-kill hook. """ # Initialize our global state. - initialize_global_vars_multiprocessing(num_threads, test_work_items) + initialize_global_vars_multiprocessing(num_threads, test_work_items, + session_dir, runner_context) # Create jobs. job_queue = multiprocessing.Queue(len(test_work_items)) @@ -944,9 +1028,11 @@ def map_async_run_loop(future, channel_map, listener_channel): return map_results -def multiprocessing_test_runner_pool(num_threads, test_work_items): +def multiprocessing_test_runner_pool(num_threads, test_work_items, session_dir, + runner_context): # Initialize our global state. - initialize_global_vars_multiprocessing(num_threads, test_work_items) + initialize_global_vars_multiprocessing(num_threads, test_work_items, + session_dir, runner_context) manager = multiprocessing.Manager() worker_index_map = manager.dict() @@ -964,7 +1050,8 @@ def multiprocessing_test_runner_pool(num_threads, test_work_items): map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL) -def threading_test_runner(num_threads, test_work_items): +def threading_test_runner(num_threads, test_work_items, session_dir, + runner_context): """Provides hand-wrapped pooling threading-based test runner adapter with Ctrl-C support. @@ -976,10 +1063,17 @@ def threading_test_runner(num_threads, test_work_items): @param test_work_items the iterable of test work item tuples to run. - """ + + @param session_dir the session directory where test-run-speciif files are + written. + + @param runner_context a dictionary of platform-related data that is passed + to the timeout pre-kill hook. + """ # Initialize our global state. - initialize_global_vars_threading(num_threads, test_work_items) + initialize_global_vars_threading(num_threads, test_work_items, session_dir, + runner_context) # Create jobs. job_queue = queue.Queue() @@ -1027,9 +1121,11 @@ def threading_test_runner(num_threads, test_work_items): return test_results -def threading_test_runner_pool(num_threads, test_work_items): +def threading_test_runner_pool(num_threads, test_work_items, session_dir, + runner_context): # Initialize our global state. - initialize_global_vars_threading(num_threads, test_work_items) + initialize_global_vars_threading(num_threads, test_work_items, session_dir, + runner_context) pool = multiprocessing.pool.ThreadPool(num_threads) map_future = pool.map_async( @@ -1049,13 +1145,17 @@ def asyncore_run_loop(channel_map): pass -def inprocess_exec_test_runner(test_work_items): +def inprocess_exec_test_runner(test_work_items, session_dir, runner_context): # Initialize our global state. - initialize_global_vars_multiprocessing(1, test_work_items) + initialize_global_vars_multiprocessing(1, test_work_items, session_dir, + runner_context) # We're always worker index 0 + def get_single_worker_index(): + return 0 + global GET_WORKER_INDEX - GET_WORKER_INDEX = lambda: 0 + GET_WORKER_INDEX = get_single_worker_index # Run the listener and related channel maps in a separate thread. # global RUNNER_PROCESS_ASYNC_MAP @@ -1079,6 +1179,7 @@ def inprocess_exec_test_runner(test_work_items): return test_results + def walk_and_invoke(test_files, dotest_argv, num_workers, test_runner_func): """Invokes the test runner on each test file specified by test_files. @@ -1193,12 +1294,20 @@ def find(pattern, path): return result -def get_test_runner_strategies(num_threads): +def get_test_runner_strategies(num_threads, session_dir, runner_context): """Returns the test runner strategies by name in a dictionary. @param num_threads specifies the number of threads/processes that will be used for concurrent test runners. + @param session_dir specifies the session dir to use for + auxiliary files. + + @param runner_context a dictionary of details on the architectures and + platform used to run the test suite. This is passed along verbatim to + the timeout pre-kill handler, allowing that decoupled component to do + process inspection in a platform-specific way. + @return dictionary with key as test runner strategy name and value set to a callable object that takes the test work item and returns a test result tuple. @@ -1208,32 +1317,34 @@ def get_test_runner_strategies(num_threads): # multiprocessing.Pool. "multiprocessing": (lambda work_items: multiprocessing_test_runner( - num_threads, work_items)), + num_threads, work_items, session_dir, runner_context)), # multiprocessing-pool uses multiprocessing.Pool but # does not support Ctrl-C. "multiprocessing-pool": (lambda work_items: multiprocessing_test_runner_pool( - num_threads, work_items)), + num_threads, work_items, session_dir, runner_context)), # threading uses a hand-rolled worker pool much # like multiprocessing, but instead uses in-process # worker threads. This one supports Ctrl-C. "threading": - (lambda work_items: threading_test_runner(num_threads, work_items)), + (lambda work_items: threading_test_runner( + num_threads, work_items, session_dir, runner_context)), # threading-pool uses threading for the workers (in-process) # and uses the multiprocessing.pool thread-enabled pool. # This does not properly support Ctrl-C. "threading-pool": (lambda work_items: threading_test_runner_pool( - num_threads, work_items)), + num_threads, work_items, session_dir, runner_context)), # serial uses the subprocess-based, single process # test runner. This provides process isolation but # no concurrent test execution. "serial": - inprocess_exec_test_runner + (lambda work_items: inprocess_exec_test_runner( + work_items, session_dir, runner_context)) } @@ -1278,7 +1389,7 @@ def _remove_option( removal_count = 2 else: removal_count = 1 - del args[index:index+removal_count] + del args[index:index + removal_count] return True except ValueError: # Thanks to argparse not handling options with known arguments @@ -1335,7 +1446,8 @@ def adjust_inferior_options(dotest_argv): # every dotest invocation from creating its own directory import datetime # The windows platforms don't like ':' in the pathname. - timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") + timestamp_started = (datetime.datetime.now() + .strftime("%Y-%m-%d-%H_%M_%S")) dotest_argv.append('-s') dotest_argv.append(timestamp_started) dotest_options.s = timestamp_started @@ -1413,7 +1525,8 @@ def default_test_runner_name(num_threads): return test_runner_name -def rerun_tests(test_subdir, tests_for_rerun, dotest_argv): +def rerun_tests(test_subdir, tests_for_rerun, dotest_argv, session_dir, + runner_context): # Build the list of test files to rerun. Some future time we'll # enable re-run by test method so we can constrain the rerun set # to just the method(s) that were in issued within a file. @@ -1453,7 +1566,8 @@ def rerun_tests(test_subdir, tests_for_rerun, dotest_argv): print("rerun will use the '{}' test runner strategy".format( rerun_runner_name)) - runner_strategies_by_name = get_test_runner_strategies(rerun_thread_count) + runner_strategies_by_name = get_test_runner_strategies( + rerun_thread_count, session_dir, runner_context) rerun_runner_func = runner_strategies_by_name[ rerun_runner_name] if rerun_runner_func is None: @@ -1515,6 +1629,10 @@ def main(num_threads, test_subdir, test_runner_name, results_formatter): test_directory = os.path.dirname(os.path.realpath(__file__)) if test_subdir and len(test_subdir) > 0: test_subdir = os.path.join(test_directory, test_subdir) + if not os.path.isdir(test_subdir): + print( + 'specified test subdirectory {} is not a valid directory\n' + .format(test_subdir)) else: test_subdir = test_directory @@ -1531,8 +1649,19 @@ def main(num_threads, test_subdir, test_runner_name, results_formatter): if results_formatter is not None: results_formatter.set_expected_timeouts_by_basename(expected_timeout) + # Setup the test runner context. This is a dictionary of information that + # will be passed along to the timeout pre-kill handler and allows for loose + # coupling of its implementation. + runner_context = { + "archs": configuration.archs, + "platform_name": configuration.lldb_platform_name, + "platform_url": configuration.lldb_platform_url, + "platform_working_dir": configuration.lldb_platform_working_dir, + } + # Figure out which testrunner strategy we'll use. - runner_strategies_by_name = get_test_runner_strategies(num_threads) + runner_strategies_by_name = get_test_runner_strategies( + num_threads, session_dir, runner_context) # If the user didn't specify a test runner strategy, determine # the default now based on number of threads and OS type. @@ -1572,6 +1701,12 @@ def main(num_threads, test_subdir, test_runner_name, results_formatter): print("\n{} test files marked for rerun\n".format( rerun_file_count)) + # Clear errors charged to any of the files of the tests that + # we are rerunning. + # https://llvm.org/bugs/show_bug.cgi?id=27423 + results_formatter.clear_file_level_issues(tests_for_rerun, + sys.stdout) + # Check if the number of files exceeds the max cutoff. If so, # we skip the rerun step. if rerun_file_count > configuration.rerun_max_file_threshold: @@ -1579,7 +1714,8 @@ def main(num_threads, test_subdir, test_runner_name, results_formatter): "exceeded".format( configuration.rerun_max_file_threshold)) else: - rerun_tests(test_subdir, tests_for_rerun, dotest_argv) + rerun_tests(test_subdir, tests_for_rerun, dotest_argv, + session_dir, runner_context) # The results formatter - if present - is done now. Tell it to # terminate. @@ -1660,7 +1796,9 @@ def main(num_threads, test_subdir, test_runner_name, results_formatter): unexpected_successes.sort() print("\nUnexpected Successes (%d)" % len(unexpected_successes)) for u in unexpected_successes: - print("UNEXPECTED SUCCESS: LLDB (suite) :: %s (%s)" % (u, system_info)) + print( + "UNEXPECTED SUCCESS: LLDB (suite) :: %s (%s)" % + (u, system_info)) sys.exit(exit_code) diff --git a/packages/Python/lldbsuite/test/dotest.py b/packages/Python/lldbsuite/test/dotest.py index 702e57e99871..6b6b2574e638 100644 --- a/packages/Python/lldbsuite/test/dotest.py +++ b/packages/Python/lldbsuite/test/dotest.py @@ -26,6 +26,7 @@ import atexit import os import errno import platform +import re import signal import socket import subprocess @@ -46,10 +47,12 @@ from . import test_result from lldbsuite.test_event.event_builder import EventBuilder from ..support import seven + def is_exe(fpath): """Returns true if fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def which(program): """Returns the full path to a program; None otherwise.""" fpath, fname = os.path.split(program) @@ -63,24 +66,28 @@ def which(program): return exe_file return None + class _WritelnDecorator(object): """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self,stream): + + def __init__(self, stream): self.stream = stream def __getattr__(self, attr): if attr in ('stream', '__getstate__'): raise AttributeError(attr) - return getattr(self.stream,attr) + return getattr(self.stream, attr) def writeln(self, arg=None): if arg: self.write(arg) - self.write('\n') # text-mode streams translate to \r\n if needed + self.write('\n') # text-mode streams translate to \r\n if needed # # Global variables: # + + def usage(parser): parser.print_help() if configuration.verbose > 0: @@ -195,6 +202,40 @@ o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the """) sys.exit(0) + +def parseExclusion(exclusion_file): + """Parse an exclusion file, of the following format, where + 'skip files', 'skip methods', 'xfail files', and 'xfail methods' + are the possible list heading values: + + skip files + <file name> + <file name> + + xfail methods + <method name> + """ + excl_type = None + + with open(exclusion_file) as f: + for line in f: + line = line.strip() + if not excl_type: + excl_type = line + continue + + if not line: + excl_type = None + elif excl_type == 'skip': + if not configuration.skip_tests: + configuration.skip_tests = [] + configuration.skip_tests.append(line) + elif excl_type == 'xfail': + if not configuration.xfail_tests: + configuration.xfail_tests = [] + configuration.xfail_tests.append(line) + + def parseOptionsAndInitTestdirs(): """Initialize the list of directories containing our unittest scripts. @@ -213,9 +254,10 @@ def parseOptionsAndInitTestdirs(): for env_var in args.unset_env_varnames: if env_var in os.environ: # From Python Doc: When unsetenv() is supported, deletion of items in os.environ - # is automatically translated into a corresponding call to unsetenv(). + # is automatically translated into a corresponding call to + # unsetenv(). del os.environ[env_var] - #os.unsetenv(env_var) + # os.unsetenv(env_var) if args.set_env_vars: for env_var in args.set_env_vars: @@ -235,9 +277,13 @@ def parseOptionsAndInitTestdirs(): if args.compilers: configuration.compilers = args.compilers else: - # Use a compiler appropriate appropriate for the Apple SDK if one was specified + # Use a compiler appropriate appropriate for the Apple SDK if one was + # specified if platform_system == 'Darwin' and args.apple_sdk: - configuration.compilers = [seven.get_command_output('xcrun -sdk "%s" -find clang 2> /dev/null' % (args.apple_sdk))] + configuration.compilers = [ + seven.get_command_output( + 'xcrun -sdk "%s" -find clang 2> /dev/null' % + (args.apple_sdk))] else: # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first candidateCompilers = ['clang-3.5', 'clang', 'gcc'] @@ -254,33 +300,43 @@ def parseOptionsAndInitTestdirs(): # Set SDKROOT if we are using an Apple SDK if platform_system == 'Darwin' and args.apple_sdk: - os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % (args.apple_sdk)) + os.environ['SDKROOT'] = seven.get_command_output( + 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % + (args.apple_sdk)) if args.archs: configuration.archs = args.archs for arch in configuration.archs: - if arch.startswith('arm') and platform_system == 'Darwin' and not args.apple_sdk: - os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null') + if arch.startswith( + 'arm') and platform_system == 'Darwin' and not args.apple_sdk: + os.environ['SDKROOT'] = seven.get_command_output( + 'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null') if not os.path.exists(os.environ['SDKROOT']): - os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk iphoneos --show-sdk-path 2> /dev/null') + os.environ['SDKROOT'] = seven.get_command_output( + 'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null') else: configuration.archs = [platform_machine] if args.categoriesList: - configuration.categoriesList = set(test_categories.validate(args.categoriesList, False)) + configuration.categoriesList = set( + test_categories.validate( + args.categoriesList, False)) configuration.useCategories = True else: configuration.categoriesList = [] if args.skipCategories: - configuration.skipCategories = test_categories.validate(args.skipCategories, False) + configuration.skipCategories = test_categories.validate( + args.skipCategories, False) if args.E: cflags_extras = args.E os.environ['CFLAGS_EXTRAS'] = cflags_extras if args.d: - sys.stdout.write("Suspending the process %d to wait for debugger to attach...\n" % os.getpid()) + sys.stdout.write( + "Suspending the process %d to wait for debugger to attach...\n" % + os.getpid()) sys.stdout.flush() os.kill(os.getpid(), signal.SIGSTOP) @@ -309,6 +365,10 @@ def parseOptionsAndInitTestdirs(): if args.executable: lldbtest_config.lldbExec = os.path.realpath(args.executable) + if args.excluded: + for excl_file in args.excluded: + parseExclusion(excl_file) + if args.p: if args.p.startswith('-'): usage(parser) @@ -334,10 +394,11 @@ def parseOptionsAndInitTestdirs(): configuration.count = args.sharp if sys.platform.startswith('win32'): - os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(args.disable_crash_dialog) + os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( + args.disable_crash_dialog) os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) - if do_help == True: + if do_help: usage(parser) if args.no_multiprocess: @@ -415,12 +476,16 @@ def parseOptionsAndInitTestdirs(): # Gather all the dirs passed on the command line. if len(args.args) > 0: - configuration.testdirs = list(map(lambda x: os.path.realpath(os.path.abspath(x)), args.args)) + configuration.testdirs = list( + map(lambda x: os.path.realpath(os.path.abspath(x)), args.args)) # Shut off multiprocessing mode when test directories are specified. configuration.no_multiprocess_test_runner = True + lldbtest_config.codesign_identity = args.codesign_identity + #print("testdirs:", testdirs) + def getXcodeOutputPaths(lldbRootDirectory): result = [] @@ -428,11 +493,16 @@ def getXcodeOutputPaths(lldbRootDirectory): xcode3_build_dir = ['build'] xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] - configurations = [['Debug'], ['DebugClang'], ['Release'], ['BuildAndIntegration']] + configurations = [ + ['Debug'], + ['DebugClang'], + ['Release'], + ['BuildAndIntegration']] xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir] for configuration in configurations: for xcode_build_dir in xcode_build_dirs: - outputPath = os.path.join(lldbRootDirectory, *(xcode_build_dir+configuration) ) + outputPath = os.path.join( + lldbRootDirectory, *(xcode_build_dir + configuration)) result.append(outputPath) return result @@ -499,17 +569,24 @@ def getOutputPaths(lldbRootDirectory): # cmake builds? look for build or build/host folder next to llvm directory # lldb is located in llvm/tools/lldb so we need to go up three levels - llvmParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir, os.pardir, os.pardir)) + llvmParentDir = os.path.abspath( + os.path.join( + lldbRootDirectory, + os.pardir, + os.pardir, + os.pardir)) result.append(os.path.join(llvmParentDir, 'build', 'bin')) result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin')) - # some cmake developers keep their build directory beside their lldb directory + # some cmake developers keep their build directory beside their lldb + # directory lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir)) result.append(os.path.join(lldbParentDir, 'build', 'bin')) result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin')) return result + def setupSysPath(): """ Add LLDB.framework/Resources/Python to the search paths for modules. @@ -535,12 +612,15 @@ def setupSysPath(): toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi') toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') - # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the sys.path. + # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the + # sys.path. sys.path.insert(0, pluginPath) - sys.path.insert(0, toolsLLDBMIPath) # Adding test/tools/lldb-mi to the path makes it easy - # to "import lldbmi_testcase" from the MI tests - sys.path.insert(0, toolsLLDBServerPath) # Adding test/tools/lldb-server to the path makes it easy - # to "import lldbgdbserverutils" from the lldb-server tests + # 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-server to the path makes it easy + sys.path.insert(0, toolsLLDBServerPath) + # to "import lldbgdbserverutils" from the lldb-server tests # This is the root of the lldb git/svn checkout # When this changes over to a package instead of a standalone script, this @@ -572,16 +652,22 @@ def setupSysPath(): lldbtest_config.lldbExec = which('lldb') if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): - print("'{}' is not a path to a valid executable".format(lldbtest_config.lldbExec)) + print( + "'{}' is not a path to a valid executable".format( + lldbtest_config.lldbExec)) lldbtest_config.lldbExec = None if not lldbtest_config.lldbExec: print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") sys.exit(-1) - lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) # confusingly, this is the "bin" directory + # confusingly, this is the "bin" directory + lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) os.environ["LLDB_LIB_DIR"] = lldbLibDir - lldbImpLibDir = os.path.join(lldbLibDir, '..', 'lib') if sys.platform.startswith('win32') else lldbLibDir + lldbImpLibDir = os.path.join( + lldbLibDir, + '..', + 'lib') if sys.platform.startswith('win32') else lldbLibDir os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) @@ -589,32 +675,41 @@ def setupSysPath(): # Assume lldb-mi is in same place as lldb # If not found, disable the lldb-mi tests - lldbMiExec = None - if lldbtest_config.lldbExec and is_exe(lldbtest_config.lldbExec + "-mi"): - lldbMiExec = lldbtest_config.lldbExec + "-mi" - if not lldbMiExec: + # 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) + 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.") + print( + "The 'lldb-mi' executable cannot be located. The lldb-mi tests can not be run as a result.") configuration.skipCategories.append("lldb-mi") - else: - os.environ["LLDBMI_EXEC"] = lldbMiExec - lldbPythonDir = None # The directory that contains 'lldb/__init__.py' + lldbPythonDir = None # The directory that contains 'lldb/__init__.py' + if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): + configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework") if configuration.lldbFrameworkPath: - candidatePath = os.path.join(configuration.lldbFrameworkPath, 'Resources', 'Python') + lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath + candidatePath = os.path.join( + configuration.lldbFrameworkPath, 'Resources', 'Python') if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): lldbPythonDir = candidatePath if not lldbPythonDir: - print('Resources/Python/lldb/__init__.py was not found in ' + configuration.lldbFrameworkPath) + print( + 'Resources/Python/lldb/__init__.py was not found in ' + + configuration.lldbFrameworkPath) sys.exit(-1) else: # If our lldb supports the -P option, use it to find the python path: init_in_python_dir = os.path.join('lldb', '__init__.py') - lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) + lldb_dash_p_result = subprocess.check_output( + [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) - if lldb_dash_p_result and not lldb_dash_p_result.startswith(("<", "lldb: invalid option:")) \ - and not lldb_dash_p_result.startswith("Traceback"): + if lldb_dash_p_result and not lldb_dash_p_result.startswith( + ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): lines = lldb_dash_p_result.splitlines() # Workaround for readline vs libedit issue on FreeBSD. If stdout @@ -625,66 +720,88 @@ def setupSysPath(): # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ # around the call. See http://bugs.python.org/issue19884 for more # information. For now we just discard the warning output. - if len(lines) >= 1 and lines[0].startswith("bind: Invalid command"): + if len(lines) >= 1 and lines[0].startswith( + "bind: Invalid command"): lines.pop(0) # Taking the last line because lldb outputs # 'Cannot read termcap database;\nusing dumb terminal settings.\n' # before the path - if len(lines) >= 1 and os.path.isfile(os.path.join(lines[-1], init_in_python_dir)): + if len(lines) >= 1 and os.path.isfile( + os.path.join(lines[-1], init_in_python_dir)): lldbPythonDir = lines[-1] if "freebsd" in sys.platform or "linux" in sys.platform: - os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') - + os.environ['LLDB_LIB_DIR'] = os.path.join( + lldbPythonDir, '..', '..') + if not lldbPythonDir: if platform.system() == "Darwin": python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] outputPaths = getXcodeOutputPaths(lldbRootDirectory) for outputPath in outputPaths: - candidatePath = os.path.join(outputPath, *python_resource_dir) - if os.path.isfile(os.path.join(candidatePath, init_in_python_dir)): + candidatePath = os.path.join( + outputPath, *python_resource_dir) + if os.path.isfile( + os.path.join( + candidatePath, + init_in_python_dir)): lldbPythonDir = candidatePath break if not lldbPythonDir: print("lldb.py is not found, some tests may fail.") else: - print("Unable to load lldb extension module. Possible reasons for this include:") + print( + "Unable to load lldb extension module. Possible reasons for this include:") print(" 1) LLDB was built with LLDB_DISABLE_PYTHON=1") - print(" 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") - print(" the version of Python that LLDB built and linked against, and PYTHONPATH") - print(" should contain the Lib directory for the same python distro, as well as the") + print( + " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") + print( + " the version of Python that LLDB built and linked against, and PYTHONPATH") + print( + " should contain the Lib directory for the same python distro, as well as the") print(" location of LLDB\'s site-packages folder.") - print(" 3) A different version of Python than that which was built against is exported in") + print( + " 3) A different version of Python than that which was built against is exported in") print(" the system\'s PATH environment variable, causing conflicts.") - print(" 4) The executable '%s' could not be found. Please check " % lldbtest_config.lldbExec) + print( + " 4) The executable '%s' could not be found. Please check " % + lldbtest_config.lldbExec) print(" that it exists and is executable.") if lldbPythonDir: lldbPythonDir = os.path.normpath(lldbPythonDir) - # Some of the code that uses this path assumes it hasn't resolved the Versions... link. - # If the path we've constructed looks like that, then we'll strip out the Versions/A part. - (before, frameWithVersion, after) = lldbPythonDir.rpartition("LLDB.framework/Versions/A") - if frameWithVersion != "" : + # Some of the code that uses this path assumes it hasn't resolved the Versions... link. + # If the path we've constructed looks like that, then we'll strip out + # the Versions/A part. + (before, frameWithVersion, after) = lldbPythonDir.rpartition( + "LLDB.framework/Versions/A") + if frameWithVersion != "": lldbPythonDir = before + "LLDB.framework" + after lldbPythonDir = os.path.abspath(lldbPythonDir) # If tests need to find LLDB_FRAMEWORK, now they can do it - os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPythonDir)) + os.environ["LLDB_FRAMEWORK"] = os.path.dirname( + os.path.dirname(lldbPythonDir)) - # This is to locate the lldb.py module. Insert it right after sys.path[0]. + # This is to locate the lldb.py module. Insert it right after + # sys.path[0]. sys.path[1:1] = [lldbPythonDir] def visit_file(dir, name): # Try to match the regexp pattern, if specified. if configuration.regexp: - import re if not re.search(configuration.regexp, name): # We didn't match the regex, we're done. return + if configuration.skip_tests: + for file_regexp in configuration.skip_tests: + if re.search(file_regexp, name): + return + # We found a match for our test. Add it to the suite. # Update the sys.path first. @@ -713,7 +830,8 @@ def visit_file(dir, name): if filtered: # print("adding filter spec %s to module %s" % (filterspec, module)) configuration.suite.addTests( - unittest2.defaultTestLoader.loadTestsFromName(filterspec, module)) + unittest2.defaultTestLoader.loadTestsFromName( + filterspec, module)) continue # Forgo this module if the (base, filterspec) combo is invalid @@ -724,7 +842,8 @@ def visit_file(dir, name): # Add the entire file's worth of tests since we're not filtered. # Also the fail-over case when the filterspec branch # (base, filterspec) combo doesn't make sense. - configuration.suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base)) + configuration.suite.addTests( + unittest2.defaultTestLoader.loadTestsFromName(base)) def visit(prefix, dir, names): @@ -774,10 +893,14 @@ def disabledynamics(): import lldb ci = lldb.DBG.GetCommandInterpreter() res = lldb.SBCommandReturnObject() - ci.HandleCommand("setting set target.prefer-dynamic-value no-dynamic-values", res, False) + ci.HandleCommand( + "setting set target.prefer-dynamic-value no-dynamic-values", + res, + False) if not res.Succeeded(): raise Exception('disabling dynamic type support failed') + def lldbLoggings(): import lldb """Check and do lldb loggings if necessary.""" @@ -793,7 +916,10 @@ def lldbLoggings(): else: lldb_log_option = "event process expr state api" ci.HandleCommand( - "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option, + "log enable -n -f " + + os.environ["LLDB_LOG"] + + " lldb " + + lldb_log_option, res) if not res.Succeeded(): raise Exception('log enable failed (check LLDB_LOG env variable)') @@ -805,11 +931,15 @@ def lldbLoggings(): else: lldb_log_option = "event process expr state api" ci.HandleCommand( - "log enable -n -f " + os.environ["LLDB_LINUX_LOG"] + " linux " + lldb_log_option, + "log enable -n -f " + + os.environ["LLDB_LINUX_LOG"] + + " linux " + + lldb_log_option, res) if not res.Succeeded(): - raise Exception('log enable failed (check LLDB_LINUX_LOG env variable)') - + raise Exception( + 'log enable failed (check LLDB_LINUX_LOG env variable)') + # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined. # Use ${GDB_REMOTE_LOG} to specify the log file. if ("GDB_REMOTE_LOG" in os.environ): @@ -822,7 +952,9 @@ def lldbLoggings(): + gdb_remote_log_option, res) if not res.Succeeded(): - raise Exception('log enable failed (check GDB_REMOTE_LOG env variable)') + raise Exception( + 'log enable failed (check GDB_REMOTE_LOG env variable)') + def getMyCommandLine(): return ' '.join(sys.argv) @@ -833,18 +965,24 @@ def getMyCommandLine(): # # # ======================================== # + def checkDsymForUUIDIsNotOn(): cmd = ["defaults", "read", "com.apple.DebugSymbols"] - pipe = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) + pipe = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) cmd_output = pipe.stdout.read() if cmd_output and "DBGFileMappedPaths = " in cmd_output: print("%s =>" % ' '.join(cmd)) print(cmd_output) - print("Disable automatic lookup and caching of dSYMs before running the test suite!") + print( + "Disable automatic lookup and caching of dSYMs before running the test suite!") print("Exiting...") sys.exit(0) -def exitTestSuite(exitCode = None): + +def exitTestSuite(exitCode=None): import lldb lldb.SBDebugger.Terminate() if exitCode: @@ -856,7 +994,9 @@ def isMultiprocessTestRunner(): # the inferior (as specified by the multiprocess test # runner) OR we've been told to skip using the multiprocess # test runner - return not (configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner) + return not ( + configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner) + def getVersionForSDK(sdk): sdk = str.lower(sdk) @@ -867,19 +1007,24 @@ def getVersionForSDK(sdk): ver = basename.replace(sdk, '') return ver + def getPathForSDK(sdk): sdk = str.lower(sdk) full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) - if os.path.exists(full_path): return full_path + if os.path.exists(full_path): + return full_path return None + def setDefaultTripleForPlatform(): if configuration.lldb_platform_name == 'ios-simulator': - triple_str = 'x86_64-apple-ios%s' % (getVersionForSDK('iphonesimulator')) + triple_str = 'x86_64-apple-ios%s' % ( + getVersionForSDK('iphonesimulator')) os.environ['TRIPLE'] = triple_str - return {'TRIPLE':triple_str} + return {'TRIPLE': triple_str} return {} + def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults # does not exist before proceeding to running the test suite. @@ -900,8 +1045,11 @@ def run_suite(): # multiprocess test runner here. if isMultiprocessTestRunner(): from . import dosep - dosep.main(configuration.num_threads, configuration.multiprocess_test_subdir, - configuration.test_runner_name, configuration.results_formatter_object) + dosep.main( + configuration.num_threads, + configuration.multiprocess_test_subdir, + configuration.test_runner_name, + configuration.results_formatter_object) raise Exception("should never get here") elif configuration.is_inferior_test_runner: # Shut off Ctrl-C processing in inferiors. The parallel @@ -924,20 +1072,29 @@ def run_suite(): lldb.DBG = lldb.SBDebugger.Create() if configuration.lldb_platform_name: - print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) - lldb.remote_platform = lldb.SBPlatform(configuration.lldb_platform_name) + print("Setting up remote platform '%s'" % + (configuration.lldb_platform_name)) + lldb.remote_platform = lldb.SBPlatform( + configuration.lldb_platform_name) if not lldb.remote_platform.IsValid(): - print("error: unable to create the LLDB platform named '%s'." % (configuration.lldb_platform_name)) + print( + "error: unable to create the LLDB platform named '%s'." % + (configuration.lldb_platform_name)) exitTestSuite(1) if configuration.lldb_platform_url: - # We must connect to a remote platform if a LLDB platform URL was specified - print("Connecting to remote platform '%s' at '%s'..." % (configuration.lldb_platform_name, configuration.lldb_platform_url)) - platform_connect_options = lldb.SBPlatformConnectOptions(configuration.lldb_platform_url) + # We must connect to a remote platform if a LLDB platform URL was + # specified + print( + "Connecting to remote platform '%s' at '%s'..." % + (configuration.lldb_platform_name, configuration.lldb_platform_url)) + platform_connect_options = lldb.SBPlatformConnectOptions( + configuration.lldb_platform_url) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") else: - print("error: failed to connect to remote platform using URL '%s': %s" % (configuration.lldb_platform_url, err)) + print("error: failed to connect to remote platform using URL '%s': %s" % ( + configuration.lldb_platform_url, err)) exitTestSuite(1) else: configuration.lldb_platform_url = None @@ -948,11 +1105,13 @@ def run_suite(): if first: print("Environment variables setup for platform support:") first = False - print("%s = %s" % (key,platform_changes[key])) + print("%s = %s" % (key, platform_changes[key])) if configuration.lldb_platform_working_dir: - print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) - lldb.remote_platform.SetWorkingDirectory(configuration.lldb_platform_working_dir) + print("Setting remote platform working directory to '%s'..." % + (configuration.lldb_platform_working_dir)) + lldb.remote_platform.SetWorkingDirectory( + configuration.lldb_platform_working_dir) lldb.DBG.SetSelectedPlatform(lldb.remote_platform) else: lldb.remote_platform = None @@ -998,10 +1157,13 @@ def run_suite(): timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") if not configuration.sdir_name: configuration.sdir_name = timestamp_started - os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), configuration.sdir_name) + os.environ["LLDB_SESSION_DIRNAME"] = os.path.join( + os.getcwd(), configuration.sdir_name) - sys.stderr.write("\nSession logs for test failures/errors/unexpected successes" - " will go into directory '%s'\n" % configuration.sdir_name) + sys.stderr.write( + "\nSession logs for test failures/errors/unexpected successes" + " will go into directory '%s'\n" % + configuration.sdir_name) sys.stderr.write("Command invoked: %s\n" % getMyCommandLine()) if not os.path.isdir(configuration.sdir_name): @@ -1024,14 +1186,16 @@ def run_suite(): # # Add some intervention here to sanity check that the compilers requested are sane. - # If found not to be an executable program, the invalid one is dropped from the list. + # If found not to be an executable program, the invalid one is dropped + # from the list. for i in range(len(configuration.compilers)): c = configuration.compilers[i] if which(c): continue else: if sys.platform.startswith("darwin"): - pipe = subprocess.Popen(['xcrun', '-find', c], stdout = subprocess.PIPE, stderr = subprocess.STDOUT) + pipe = subprocess.Popen( + ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) cmd_output = pipe.stdout.read() if cmd_output: if "not found" in cmd_output: @@ -1039,7 +1203,9 @@ def run_suite(): configuration.compilers.remove(i) else: configuration.compilers[i] = cmd_output.split('\n')[0] - print("'xcrun -find %s' returning %s" % (c, configuration.compilers[i])) + print( + "'xcrun -find %s' returning %s" % + (c, configuration.compilers[i])) if not configuration.parsable: print("compilers=%s" % str(configuration.compilers)) @@ -1048,10 +1214,14 @@ def run_suite(): print("No eligible compiler found, exiting.") exitTestSuite(1) - if isinstance(configuration.compilers, list) and len(configuration.compilers) >= 1: + if isinstance( + configuration.compilers, + list) and len( + configuration.compilers) >= 1: iterCompilers = True - # If we iterate on archs or compilers, there is a chance we want to split stderr/stdout. + # If we iterate on archs or compilers, there is a chance we want to split + # stderr/stdout. if iterArchs or iterCompilers: old_stderr = sys.stderr old_stdout = sys.stdout @@ -1067,7 +1237,8 @@ def run_suite(): for ic in range(len(configuration.compilers) if iterCompilers else 1): if iterCompilers: os.environ["CC"] = configuration.compilers[ic] - configString = "%s compiler=%s" % (archConfig, configuration.compilers[ic]) + configString = "%s compiler=%s" % ( + archConfig, configuration.compilers[ic]) else: configString = archConfig @@ -1090,9 +1261,10 @@ def run_suite(): # First, write out the number of collected test cases. if not configuration.parsable: sys.stderr.write(configuration.separator + "\n") - sys.stderr.write("Collected %d test%s\n\n" - % (configuration.suite.countTestCases(), - configuration.suite.countTestCases() != 1 and "s" or "")) + sys.stderr.write( + "Collected %d test%s\n\n" % + (configuration.suite.countTestCases(), + configuration.suite.countTestCases() != 1 and "s" or "")) if configuration.parsable: v = 0 @@ -1101,30 +1273,39 @@ def run_suite(): # Invoke the test runner. if configuration.count == 1: - result = unittest2.TextTestRunner(stream=sys.stderr, - verbosity=v, - resultclass=test_result.LLDBTestResult).run(configuration.suite) + result = unittest2.TextTestRunner( + stream=sys.stderr, + verbosity=v, + resultclass=test_result.LLDBTestResult).run( + configuration.suite) else: # We are invoking the same test suite more than once. In this case, # mark __ignore_singleton__ flag as True so the signleton pattern is # not enforced. test_result.LLDBTestResult.__ignore_singleton__ = True for i in range(configuration.count): - - result = unittest2.TextTestRunner(stream=sys.stderr, - verbosity=v, - resultclass=test_result.LLDBTestResult).run(configuration.suite) + + result = unittest2.TextTestRunner( + stream=sys.stderr, + verbosity=v, + resultclass=test_result.LLDBTestResult).run( + configuration.suite) configuration.failed = configuration.failed or not result.wasSuccessful() if configuration.sdir_has_content and not configuration.parsable: - sys.stderr.write("Session logs for test failures/errors/unexpected successes" - " can be found in directory '%s'\n" % configuration.sdir_name) + sys.stderr.write( + "Session logs for test failures/errors/unexpected successes" + " can be found in directory '%s'\n" % + configuration.sdir_name) - if configuration.useCategories and len(configuration.failuresPerCategory) > 0: + if configuration.useCategories and len( + configuration.failuresPerCategory) > 0: sys.stderr.write("Failures per category:\n") for category in configuration.failuresPerCategory: - sys.stderr.write("%s - %d\n" % (category, configuration.failuresPerCategory[category])) + sys.stderr.write( + "%s - %d\n" % + (category, configuration.failuresPerCategory[category])) # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined. # This should not be necessary now. @@ -1136,5 +1317,7 @@ def run_suite(): exitTestSuite(configuration.failed) if __name__ == "__main__": - print(__file__ + " is for use as a module only. It should not be run as a standalone script.") + print( + __file__ + + " is for use as a module only. It should not be run as a standalone script.") sys.exit(-1) diff --git a/packages/Python/lldbsuite/test/dotest_args.py b/packages/Python/lldbsuite/test/dotest_args.py index 8bbc29c98f00..fc896d53c0be 100644 --- a/packages/Python/lldbsuite/test/dotest_args.py +++ b/packages/Python/lldbsuite/test/dotest_args.py @@ -13,9 +13,11 @@ import textwrap # LLDB modules from . import configuration + class ArgParseNamespace(object): pass + def parse_args(parser, argv): """ Returns an argument object. LLDB_TEST_ARGUMENTS environment variable can be used to pass additional arguments. @@ -23,8 +25,11 @@ def parse_args(parser, argv): args = ArgParseNamespace() if ('LLDB_TEST_ARGUMENTS' in os.environ): - print("Arguments passed through environment: '%s'" % os.environ['LLDB_TEST_ARGUMENTS']) - args = parser.parse_args([sys.argv[0]].__add__(os.environ['LLDB_TEST_ARGUMENTS'].split()),namespace=args) + print( + "Arguments passed through environment: '%s'" % + os.environ['LLDB_TEST_ARGUMENTS']) + args = parser.parse_args([sys.argv[0]].__add__( + os.environ['LLDB_TEST_ARGUMENTS'].split()), namespace=args) return parser.parse_args(args=argv, namespace=args) @@ -39,59 +44,160 @@ def default_thread_count(): def create_parser(): - parser = argparse.ArgumentParser(description='description', prefix_chars='+-', add_help=False) + parser = argparse.ArgumentParser( + description='description', + prefix_chars='+-', + add_help=False) group = None - # Helper function for boolean options (group will point to the current group when executing X) - X = lambda optstr, helpstr, **kwargs: group.add_argument(optstr, help=helpstr, action='store_true', **kwargs) + # Helper function for boolean options (group will point to the current + # group when executing X) + X = lambda optstr, helpstr, **kwargs: group.add_argument( + optstr, help=helpstr, action='store_true', **kwargs) group = parser.add_argument_group('Help') - group.add_argument('-h', '--help', dest='h', action='store_true', help="Print this help message and exit. Add '-v' for more detailed help.") + group.add_argument( + '-h', + '--help', + dest='h', + action='store_true', + help="Print this help message and exit. Add '-v' for more detailed help.") # C and Python toolchain options group = parser.add_argument_group('Toolchain options') - group.add_argument('-A', '--arch', metavar='arch', action='append', dest='archs', help=textwrap.dedent('''Specify the architecture(s) to test. This option can be specified more than once''')) - group.add_argument('-C', '--compiler', metavar='compiler', dest='compilers', action='append', help=textwrap.dedent('''Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.''')) + group.add_argument( + '-A', + '--arch', + metavar='arch', + action='append', + dest='archs', + help=textwrap.dedent('''Specify the architecture(s) to test. This option can be specified more than once''')) + group.add_argument('-C', '--compiler', metavar='compiler', dest='compilers', action='append', help=textwrap.dedent( + '''Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.''')) if sys.platform == 'darwin': - group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', help=textwrap.dedent('''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.''')) + group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', default="macosx", help=textwrap.dedent( + '''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.''')) # FIXME? This won't work for different extra flags according to each arch. - group.add_argument('-E', metavar='extra-flags', help=textwrap.dedent('''Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged + group.add_argument( + '-E', + metavar='extra-flags', + help=textwrap.dedent('''Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures''')) # Test filtering options group = parser.add_argument_group('Test filtering options') - group.add_argument('-f', metavar='filterspec', action='append', help='Specify a filter, which consists of the test class name, a dot, followed by the test method, to only admit such test into the test suite') # FIXME: Example? + group.add_argument( + '-f', + metavar='filterspec', + action='append', + help='Specify a filter, which consists of the test class name, a dot, followed by the test method, to only admit such test into the test suite') # FIXME: Example? X('-l', "Don't skip long running tests") - group.add_argument('-p', metavar='pattern', help='Specify a regexp filename pattern for inclusion in the test suite') - group.add_argument('-G', '--category', metavar='category', action='append', dest='categoriesList', help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.''')) - group.add_argument('--skip-category', metavar='category', action='append', dest='skipCategories', help=textwrap.dedent('''Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.''')) + group.add_argument( + '-p', + metavar='pattern', + help='Specify a regexp filename pattern for inclusion in the test suite') + group.add_argument('--excluded', metavar='exclusion-file', action='append', help=textwrap.dedent( + '''Specify a file for tests to exclude. File should contain lists of regular expressions for test files or methods, + with each list under a matching header (xfail files, xfail methods, skip files, skip methods)''')) + group.add_argument( + '-G', + '--category', + metavar='category', + action='append', + dest='categoriesList', + help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.''')) + group.add_argument( + '--skip-category', + metavar='category', + action='append', + dest='skipCategories', + help=textwrap.dedent('''Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.''')) # Configuration options group = parser.add_argument_group('Configuration options') - group.add_argument('--framework', metavar='framework-path', help='The path to LLDB.framework') - group.add_argument('--executable', metavar='executable-path', help='The path to the lldb executable') - group.add_argument('-s', metavar='name', help='Specify the name of the dir created to store the session files of tests with errored or failed status. If not specified, the test driver uses the timestamp as the session dir name') - group.add_argument('-S', '--session-file-format', default=configuration.session_file_format, metavar='format', help='Specify session file name format. See configuration.py for a description.') - group.add_argument('-y', type=int, metavar='count', help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.") - group.add_argument('-#', type=int, metavar='sharp', dest='sharp', help='Repeat the test suite for a specified number of times') - group.add_argument('--channel', metavar='channel', dest='channels', action='append', help=textwrap.dedent("Specify the log channels (and optional categories) e.g. 'lldb all' or 'gdb-remote packets' if no categories are specified, 'default' is used")) - group.add_argument('--log-success', dest='log_success', action='store_true', help="Leave logs/traces even for successful test runs (useful for creating reference log files during debugging.)") + group.add_argument( + '--framework', + metavar='framework-path', + help='The path to LLDB.framework') + group.add_argument( + '--executable', + metavar='executable-path', + help='The path to the lldb executable') + group.add_argument( + '-s', + metavar='name', + help='Specify the name of the dir created to store the session files of tests with errored or failed status. If not specified, the test driver uses the timestamp as the session dir name') + group.add_argument( + '-S', + '--session-file-format', + default=configuration.session_file_format, + metavar='format', + help='Specify session file name format. See configuration.py for a description.') + group.add_argument( + '-y', + type=int, + metavar='count', + help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.") + group.add_argument( + '-#', + type=int, + metavar='sharp', + dest='sharp', + help='Repeat the test suite for a specified number of times') + group.add_argument('--channel', metavar='channel', dest='channels', action='append', help=textwrap.dedent( + "Specify the log channels (and optional categories) e.g. 'lldb all' or 'gdb-remote packets' if no categories are specified, 'default' is used")) + group.add_argument( + '--log-success', + dest='log_success', + action='store_true', + help="Leave logs/traces even for successful test runs (useful for creating reference log files during debugging.)") + group.add_argument( + '--codesign-identity', + metavar='Codesigning identity', + default='lldb_codesign', + help='The codesigning identity to use') # Configuration options group = parser.add_argument_group('Remote platform options') - group.add_argument('--platform-name', dest='lldb_platform_name', metavar='platform-name', help='The name of a remote platform to use') - group.add_argument('--platform-url', dest='lldb_platform_url', metavar='platform-url', help='A LLDB platform URL to use when connecting to a remote platform to run the test suite') - group.add_argument('--platform-working-dir', dest='lldb_platform_working_dir', metavar='platform-working-dir', help='The directory to use on the remote platform.') + group.add_argument( + '--platform-name', + dest='lldb_platform_name', + metavar='platform-name', + help='The name of a remote platform to use') + group.add_argument( + '--platform-url', + dest='lldb_platform_url', + metavar='platform-url', + help='A LLDB platform URL to use when connecting to a remote platform to run the test suite') + group.add_argument( + '--platform-working-dir', + dest='lldb_platform_working_dir', + metavar='platform-working-dir', + help='The directory to use on the remote platform.') # Test-suite behaviour group = parser.add_argument_group('Runtime behaviour options') X('-d', 'Suspend the process after launch to wait indefinitely for a debugger to attach') X('-q', "Don't print extra output from this script.") X('-t', 'Turn on tracing of lldb command and other detailed test executions') - group.add_argument('-u', dest='unset_env_varnames', metavar='variable', action='append', help='Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble') - group.add_argument('--env', dest='set_env_vars', metavar='variable', action='append', help='Specify an environment variable to set to the given value before running the test cases e.g.: --env CXXFLAGS=-O3 --env DYLD_INSERT_LIBRARIES') + group.add_argument( + '-u', + dest='unset_env_varnames', + metavar='variable', + action='append', + help='Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble') + group.add_argument( + '--env', + dest='set_env_vars', + metavar='variable', + action='append', + help='Specify an environment variable to set to the given value before running the test cases e.g.: --env CXXFLAGS=-O3 --env DYLD_INSERT_LIBRARIES') X('-v', 'Do verbose mode of unittest framework (print out each test case invocation)') - group.add_argument('--enable-crash-dialog', dest='disable_crash_dialog', action='store_false', help='(Windows only) When LLDB crashes, display the Windows crash dialog.') + group.add_argument( + '--enable-crash-dialog', + dest='disable_crash_dialog', + action='store_false', + help='(Windows only) When LLDB crashes, display the Windows crash dialog.') group.set_defaults(disable_crash_dialog=True) group = parser.add_argument_group('Parallel execution options') @@ -185,6 +291,10 @@ def create_parser(): del X group = parser.add_argument_group('Test directories') - group.add_argument('args', metavar='test-dir', nargs='*', help='Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.') + group.add_argument( + 'args', + metavar='test-dir', + nargs='*', + help='Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.') return parser diff --git a/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py b/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py index 6713a5a764e4..8699b31f9929 100644 --- a/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py +++ b/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py @@ -5,13 +5,14 @@ Test that the lldb driver's batch mode works correctly. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class DriverBatchModeTest (TestBase): mydir = TestBase.compute_mydir(__file__) @@ -23,21 +24,23 @@ class DriverBatchModeTest (TestBase): self.source = 'main.c' self.victim = None - def expect_string (self, string): + def expect_string(self, string): import pexpect """This expects for "string", with timeout & EOF being test fails.""" try: self.child.expect_exact(string) except pexpect.EOF: - self.fail ("Got EOF waiting for '%s'"%(string)) + self.fail("Got EOF waiting for '%s'" % (string)) except pexpect.TIMEOUT: - self.fail ("Timed out waiting for '%s'"%(string)) + self.fail("Timed out waiting for '%s'" % (string)) - @skipIfRemote # test not remote-ready llvm.org/pr24813 + @skipIfRemote # test not remote-ready llvm.org/pr24813 @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") @expectedFlakeyLinux("llvm.org/pr25172") - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") - def test_batch_mode_run_crash (self): + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_run_crash(self): """Test that the lldb driver's batch mode works correctly.""" self.build() self.setTearDownCleanup() @@ -48,33 +51,36 @@ class DriverBatchModeTest (TestBase): # Pass CRASH so the process will crash and stop in batch mode. run_commands = ' -b -o "break set -n main" -o "run" -o "continue" -k "frame var touch_me_not"' - self.child = pexpect.spawn('%s %s %s %s -- CRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + self.child = pexpect.spawn( + '%s %s %s %s -- CRASH' % + (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) child = self.child # Turn on logging for what the child sends back. if self.TraceOn(): child.logfile_read = sys.stdout # We should see the "run": - self.expect_string ("run") + self.expect_string("run") # We should have hit the breakpoint & continued: - self.expect_string ("continue") + self.expect_string("continue") # The App should have crashed: self.expect_string("About to crash") # The -k option should have printed the frame variable once: - self.expect_string ('(char *) touch_me_not') + self.expect_string('(char *) touch_me_not') # Then we should have a live prompt: - self.expect_string (prompt) + self.expect_string(prompt) self.child.sendline("frame variable touch_me_not") - self.expect_string ('(char *) touch_me_not') - - self.deletePexpectChild() + self.expect_string('(char *) touch_me_not') + self.deletePexpectChild() - @skipIfRemote # test not remote-ready llvm.org/pr24813 + @skipIfRemote # test not remote-ready llvm.org/pr24813 @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") @expectedFlakeyLinux("llvm.org/pr25172") - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") - def test_batch_mode_run_exit (self): + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_run_exit(self): """Test that the lldb driver's batch mode works correctly.""" self.build() self.setTearDownCleanup() @@ -85,66 +91,78 @@ class DriverBatchModeTest (TestBase): # Now do it again, and make sure if we don't crash, we quit: run_commands = ' -b -o "break set -n main" -o "run" -o "continue" ' - self.child = pexpect.spawn('%s %s %s %s -- NOCRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + self.child = pexpect.spawn( + '%s %s %s %s -- NOCRASH' % + (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) child = self.child # Turn on logging for what the child sends back. if self.TraceOn(): child.logfile_read = sys.stdout # We should see the "run": - self.expect_string ("run") + self.expect_string("run") # We should have hit the breakpoint & continued: - self.expect_string ("continue") + self.expect_string("continue") # The App should have not have crashed: self.expect_string("Got there on time and it did not crash.") # Then we should have a live prompt: - self.expect_string ("exited") + self.expect_string("exited") index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) - self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") + self.assertTrue( + index == 0, + "lldb didn't close on successful batch completion.") def closeVictim(self): - if self.victim != None: + if self.victim is not None: self.victim.close() self.victim = None - @skipIfRemote # test not remote-ready llvm.org/pr24813 + @skipIfRemote # test not remote-ready llvm.org/pr24813 @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") @expectedFlakeyLinux("llvm.org/pr25172") - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") - def test_batch_mode_attach_exit (self): + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_attach_exit(self): """Test that the lldb driver's batch mode works correctly.""" self.build() self.setTearDownCleanup() - + import pexpect exe = os.path.join(os.getcwd(), "a.out") prompt = "(lldb) " # Finally, start up the process by hand, attach to it, and wait for its completion. - # Attach is funny, since it looks like it stops with a signal on most Unixen so + # Attach is funny, since it looks like it stops with a signal on most Unixen so # care must be taken not to treat that as a reason to exit batch mode. - + # Start up the process by hand and wait for it to get to the wait loop. - self.victim = pexpect.spawn('%s WAIT' %(exe)) - if self.victim == None: + self.victim = pexpect.spawn('%s WAIT' % (exe)) + if self.victim is None: self.fail("Could not spawn ", exe, ".") - self.addTearDownHook (self.closeVictim) + self.addTearDownHook(self.closeVictim) if self.TraceOn(): self.victim.logfile_read = sys.stdout self.victim.expect("PID: ([0-9]+) END") - if self.victim.match == None: + if self.victim.match is None: self.fail("Couldn't get the target PID.") victim_pid = int(self.victim.match.group(1)) - + self.victim.expect("Waiting") - run_commands = ' -b -o "process attach -p %d" -o "breakpoint set --file %s -p \'Stop here to unset keep_waiting\' -N keep_waiting" -o "continue" -o "break delete keep_waiting" -o "expr keep_waiting = 0" -o "continue" ' % (victim_pid, self.source) - self.child = pexpect.spawn('%s %s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + run_commands = ' -b -o "process attach -p %d" -o "breakpoint set --file %s -p \'Stop here to unset keep_waiting\' -N keep_waiting" -o "continue" -o "break delete keep_waiting" -o "expr keep_waiting = 0" -o "continue" ' % ( + victim_pid, self.source) + self.child = pexpect.spawn( + '%s %s %s %s' % + (lldbtest_config.lldbExec, + self.lldbOption, + run_commands, + exe)) child = self.child # Turn on logging for what the child sends back. @@ -152,19 +170,19 @@ class DriverBatchModeTest (TestBase): child.logfile_read = sys.stdout # We should see the "run": - self.expect_string ("attach") + self.expect_string("attach") self.expect_string(prompt + "continue") self.expect_string(prompt + "continue") # Then we should see the process exit: - self.expect_string ("Process %d exited with status"%(victim_pid)) - + self.expect_string("Process %d exited with status" % (victim_pid)) + victim_index = self.victim.expect([pexpect.EOF, pexpect.TIMEOUT]) self.assertTrue(victim_index == 0, "Victim didn't really exit.") index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) - self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") - - + self.assertTrue( + index == 0, + "lldb didn't close on successful batch completion.") diff --git a/packages/Python/lldbsuite/test/example/TestSequenceFunctions.py b/packages/Python/lldbsuite/test/example/TestSequenceFunctions.py index a08529300646..8c5fedf58abc 100644 --- a/packages/Python/lldbsuite/test/example/TestSequenceFunctions.py +++ b/packages/Python/lldbsuite/test/example/TestSequenceFunctions.py @@ -4,14 +4,15 @@ import random import unittest import traceback + class SequenceFunctionsTestCase(unittest.TestCase): def setUp(self): - #traceback.print_stack() + # traceback.print_stack() self.seq = list(range(10)) def tearDown(self): - #traceback.print_stack() + # traceback.print_stack() pass def test_shuffle(self): diff --git a/packages/Python/lldbsuite/test/expression_command/anonymous-struct/TestCallUserAnonTypedef.py b/packages/Python/lldbsuite/test/expression_command/anonymous-struct/TestCallUserAnonTypedef.py index e1a53305a0d0..2d4504f7ba42 100644 --- a/packages/Python/lldbsuite/test/expression_command/anonymous-struct/TestCallUserAnonTypedef.py +++ b/packages/Python/lldbsuite/test/expression_command/anonymous-struct/TestCallUserAnonTypedef.py @@ -24,7 +24,10 @@ class TestExprLookupAnonStructTypedef(TestBase): self.line = line_number('main.cpp', '// lldb testsuite break') @expectedFailureAll(oslist=["windows"]) - @expectedFailureAll(oslist=['linux'], archs=['arm'], bugnumber="llvm.org/pr27868") + @expectedFailureAll( + oslist=['linux'], + archs=['arm'], + bugnumber="llvm.org/pr27868") def test(self): """Test typedeffed untagged struct arguments for function call expressions""" self.build() diff --git a/packages/Python/lldbsuite/test/expression_command/calculator_mode/TestCalculatorMode.py b/packages/Python/lldbsuite/test/expression_command/calculator_mode/TestCalculatorMode.py new file mode 100644 index 000000000000..46ea111bf031 --- /dev/null +++ b/packages/Python/lldbsuite/test/expression_command/calculator_mode/TestCalculatorMode.py @@ -0,0 +1,27 @@ +""" +Test calling an expression without a target. +""" + +from __future__ import print_function + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestCalculatorMode(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def test__calculator_mode(self): + """Test calling expressions in the dummy target.""" + self.expect("expression 11 + 22", "11 + 22 didn't get the expected result", substrs=["33"]) + # Now try it with a specific language: + self.expect("expression -l c -- 11 + 22", "11 + 22 didn't get the expected result", substrs=["33"]) + diff --git a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStdStringFunction.py b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStdStringFunction.py index 61702ee88033..6645692f93ee 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStdStringFunction.py +++ b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStdStringFunction.py @@ -5,12 +5,12 @@ Test calling std::String member functions. from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandCallFunctionTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -19,26 +19,33 @@ class ExprCommandCallFunctionTestCase(TestBase): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break for main.c. - self.line = line_number('main.cpp', - '// Please test these expressions while stopped at this line:') - - @expectedFailureAll(compiler="icc", bugnumber="llvm.org/pr14437, fails with ICC 13.1") - @expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr17807 Fails on FreeBSD buildbot') + self.line = line_number( + 'main.cpp', + '// Please test these expressions while stopped at this line:') + + @expectedFailureAll( + compiler="icc", + bugnumber="llvm.org/pr14437, fails with ICC 13.1") + @expectedFailureAll( + oslist=['freebsd'], + bugnumber='llvm.org/pr17807 Fails on FreeBSD buildbot') @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") def test_with(self): """Test calling std::String member function.""" self.build() self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - # Some versions of GCC encode two locations for the 'return' statement in main.cpp - lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) + # Some versions of GCC encode two locations for the 'return' statement + # in main.cpp + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) self.expect("print str", - substrs = ['Hello world']) + substrs=['Hello world']) # Calling this function now succeeds, but we follow the typedef return type through to # const char *, and thus don't invoke the Summary formatter. self.expect("print str.c_str()", - substrs = ['Hello world']) + substrs=['Hello world']) diff --git a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStopAndContinue.py b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStopAndContinue.py index 4d18cfc980f2..a48a38aaf92c 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStopAndContinue.py +++ b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallStopAndContinue.py @@ -5,12 +5,12 @@ Test calling a function, stopping in the call, continue and gather the result on from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandCallStopContinueTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -19,29 +19,40 @@ class ExprCommandCallStopContinueTestCase(TestBase): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break for main.c. - self.line = line_number('main.cpp', - '// Please test these expressions while stopped at this line:') - self.func_line = line_number ('main.cpp', - '{ 5, "five" }') + self.line = line_number( + 'main.cpp', + '// Please test these expressions while stopped at this line:') + self.func_line = line_number('main.cpp', '{5, "five"}') @expectedFlakeyDarwin("llvm.org/pr20274") - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24489: Name lookup not working correctly on Windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr24489: Name lookup not working correctly on Windows") def test(self): """Test gathering result from interrupted function call.""" self.build() self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - # Some versions of GCC encode two locations for the 'return' statement in main.cpp - lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) + # Some versions of GCC encode two locations for the 'return' statement + # in main.cpp + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) - lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.func_line, num_expected_locations=-1, loc_exact=True) - + lldbutil.run_break_set_by_file_and_line( + self, + "main.cpp", + self.func_line, + num_expected_locations=-1, + loc_exact=True) + self.expect("expr -i false -- returnsFive()", error=True, - substrs = ['Execution was interrupted, reason: breakpoint']) + substrs=['Execution was interrupted, reason: breakpoint']) self.runCmd("continue", "Continue completed") - self.expect ("thread list", - substrs = ['stop reason = User Expression thread plan', - r'Completed expression: (Five) $0 = (number = 5, name = "five")']) + self.expect( + "thread list", + substrs=[ + 'stop reason = User Expression thread plan', + r'Completed expression: (Five) $0 = (number = 5, name = "five")']) diff --git a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallUserDefinedFunction.py b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallUserDefinedFunction.py index c0727a84fc02..fda81ae8c365 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-function/TestCallUserDefinedFunction.py +++ b/packages/Python/lldbsuite/test/expression_command/call-function/TestCallUserDefinedFunction.py @@ -10,12 +10,12 @@ Note: from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandCallUserDefinedFunction(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -24,30 +24,39 @@ class ExprCommandCallUserDefinedFunction(TestBase): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break for main.c. - self.line = line_number('main.cpp', - '// Please test these expressions while stopped at this line:') + self.line = line_number( + 'main.cpp', + '// Please test these expressions while stopped at this line:') + @expectedFlakeyDsym("llvm.org/pr20274") - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24489: Name lookup not working correctly on Windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr24489: Name lookup not working correctly on Windows") def test(self): """Test return values of user defined function calls.""" self.build() # Set breakpoint in main and run exe self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) # Test recursive function call. - self.expect("expr fib(5)", substrs = ['$0 = 5']) + self.expect("expr fib(5)", substrs=['$0 = 5']) # Test function with more than one paramter - self.expect("expr add(4,8)", substrs = ['$1 = 12']) + self.expect("expr add(4,8)", substrs=['$1 = 12']) # Test nesting function calls in function paramters - self.expect("expr add(add(5,2),add(3,4))", substrs = ['$2 = 14']) - self.expect("expr add(add(5,2),fib(5))", substrs = ['$3 = 12']) + self.expect("expr add(add(5,2),add(3,4))", substrs=['$2 = 14']) + self.expect("expr add(add(5,2),fib(5))", substrs=['$3 = 12']) # Test function with pointer paramter - self.expect("exp stringCompare((const char*) \"Hello world\")", substrs = ['$4 = true']) - self.expect("exp stringCompare((const char*) \"Hellworld\")", substrs = ['$5 = false']) + self.expect( + "exp stringCompare((const char*) \"Hello world\")", + substrs=['$4 = true']) + self.expect( + "exp stringCompare((const char*) \"Hellworld\")", + substrs=['$5 = false']) diff --git a/packages/Python/lldbsuite/test/expression_command/call-function/main.cpp b/packages/Python/lldbsuite/test/expression_command/call-function/main.cpp index 9b494c712bcc..cc5f52dbf567 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-function/main.cpp +++ b/packages/Python/lldbsuite/test/expression_command/call-function/main.cpp @@ -11,7 +11,7 @@ struct Five Five returnsFive() { - Five my_five = { 5, "five" }; + Five my_five = {5, "five"}; return my_five; } diff --git a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py index 6b754a76878b..bef4be1eb5f8 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py +++ b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py @@ -5,12 +5,12 @@ Test calling a function that hits a signal set to auto-restart, make sure the ca from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandThatRestartsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -20,24 +20,30 @@ class ExprCommandThatRestartsTestCase(TestBase): TestBase.setUp(self) self.main_source = "lotta-signals.c" - self.main_source_spec = lldb.SBFileSpec (self.main_source) + self.main_source_spec = lldb.SBFileSpec(self.main_source) - @skipIfFreeBSD # llvm.org/pr19246: intermittent failure - @skipIfDarwin # llvm.org/pr19246: intermittent failure - @skipIfWindows # Test relies on signals, unsupported on Windows + @skipIfFreeBSD # llvm.org/pr19246: intermittent failure + @skipIfDarwin # llvm.org/pr19246: intermittent failure + @skipIfWindows # Test relies on signals, unsupported on Windows def test(self): """Test calling function that hits a signal and restarts.""" self.build() self.call_function() - def check_after_call (self, num_sigchld): + def check_after_call(self, num_sigchld): after_call = self.sigchld_no.GetValueAsSigned(-1) - self.assertTrue (after_call - self.start_sigchld_no == num_sigchld, "Really got %d SIGCHLD signals through the call."%(num_sigchld)) + self.assertTrue( + after_call - + self.start_sigchld_no == num_sigchld, + "Really got %d SIGCHLD signals through the call." % + (num_sigchld)) self.start_sigchld_no = after_call # Check that we are back where we were before: frame = self.thread.GetFrameAtIndex(0) - self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly") + self.assertTrue( + self.orig_frame_pc == frame.GetPC(), + "Restored the zeroth frame correctly") def call_function(self): exe_name = "a.out" @@ -46,95 +52,133 @@ class ExprCommandThatRestartsTestCase(TestBase): target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) empty = lldb.SBFileSpec() - breakpoint = target.BreakpointCreateBySourceRegex('Stop here in main.',self.main_source_spec) + breakpoint = target.BreakpointCreateBySourceRegex( + 'Stop here in main.', self.main_source_spec) self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple (None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) - + threads = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) + self.assertTrue(len(threads) == 1) self.thread = threads[0] - + # Make sure the SIGCHLD behavior is pass/no-stop/no-notify: return_obj = lldb.SBCommandReturnObject() - self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 0", return_obj) - self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop") + self.dbg.GetCommandInterpreter().HandleCommand( + "process handle SIGCHLD -s 0 -p 1 -n 0", return_obj) + self.assertTrue(return_obj.Succeeded(), "Set SIGCHLD to pass, no-stop") # The sigchld_no variable should be 0 at this point. self.sigchld_no = target.FindFirstGlobalVariable("sigchld_no") - self.assertTrue (self.sigchld_no.IsValid(), "Got a value for sigchld_no") + self.assertTrue( + self.sigchld_no.IsValid(), + "Got a value for sigchld_no") - self.start_sigchld_no = self.sigchld_no.GetValueAsSigned (-1) - self.assertTrue (self.start_sigchld_no != -1, "Got an actual value for sigchld_no") + self.start_sigchld_no = self.sigchld_no.GetValueAsSigned(-1) + self.assertTrue( + self.start_sigchld_no != -1, + "Got an actual value for sigchld_no") options = lldb.SBExpressionOptions() - # processing 30 signals takes a while, increase the expression timeout a bit - options.SetTimeoutInMicroSeconds(3000000) # 3s + # processing 30 signals takes a while, increase the expression timeout + # a bit + options.SetTimeoutInMicroSeconds(3000000) # 3s options.SetUnwindOnError(True) frame = self.thread.GetFrameAtIndex(0) - # Store away the PC to check that the functions unwind to the right place after calls + # Store away the PC to check that the functions unwind to the right + # place after calls self.orig_frame_pc = frame.GetPC() num_sigchld = 30 - value = frame.EvaluateExpression ("call_me (%d)"%(num_sigchld), options) - self.assertTrue (value.IsValid()) - self.assertTrue (value.GetError().Success() == True) - self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld) + value = frame.EvaluateExpression( + "call_me (%d)" % + (num_sigchld), options) + self.assertTrue(value.IsValid()) + self.assertTrue(value.GetError().Success()) + self.assertTrue(value.GetValueAsSigned(-1) == num_sigchld) self.check_after_call(num_sigchld) # Okay, now try with a breakpoint in the called code in the case where # we are ignoring breakpoint hits. - handler_bkpt = target.BreakpointCreateBySourceRegex("Got sigchld %d.", self.main_source_spec) - self.assertTrue (handler_bkpt.GetNumLocations() > 0) + handler_bkpt = target.BreakpointCreateBySourceRegex( + "Got sigchld %d.", self.main_source_spec) + self.assertTrue(handler_bkpt.GetNumLocations() > 0) options.SetIgnoreBreakpoints(True) options.SetUnwindOnError(True) - value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options) + value = frame.EvaluateExpression( + "call_me (%d)" % + (num_sigchld), options) - self.assertTrue (value.IsValid() and value.GetError().Success() == True) - self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld) + self.assertTrue(value.IsValid() and value.GetError().Success()) + self.assertTrue(value.GetValueAsSigned(-1) == num_sigchld) self.check_after_call(num_sigchld) - # Now set the signal to print but not stop and make sure that calling still works: - self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj) - self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify") + # Now set the signal to print but not stop and make sure that calling + # still works: + self.dbg.GetCommandInterpreter().HandleCommand( + "process handle SIGCHLD -s 0 -p 1 -n 1", return_obj) + self.assertTrue( + return_obj.Succeeded(), + "Set SIGCHLD to pass, no-stop, notify") - value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options) + value = frame.EvaluateExpression( + "call_me (%d)" % + (num_sigchld), options) - self.assertTrue (value.IsValid() and value.GetError().Success() == True) - self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld) + self.assertTrue(value.IsValid() and value.GetError().Success()) + self.assertTrue(value.GetValueAsSigned(-1) == num_sigchld) self.check_after_call(num_sigchld) - # Now set this unwind on error to false, and make sure that we still complete the call: + # Now set this unwind on error to false, and make sure that we still + # complete the call: options.SetUnwindOnError(False) - value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options) + value = frame.EvaluateExpression( + "call_me (%d)" % + (num_sigchld), options) - self.assertTrue (value.IsValid() and value.GetError().Success() == True) - self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld) + self.assertTrue(value.IsValid() and value.GetError().Success()) + self.assertTrue(value.GetValueAsSigned(-1) == num_sigchld) self.check_after_call(num_sigchld) # Okay, now set UnwindOnError to true, and then make the signal behavior to stop # and see that now we do stop at the signal point: - - self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 1 -p 1 -n 1", return_obj) - self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, stop, notify") - - value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options) - self.assertTrue (value.IsValid() and value.GetError().Success() == False) - - # Set signal handling back to no-stop, and continue and we should end up back in out starting frame: - self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj) - self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify") + + self.dbg.GetCommandInterpreter().HandleCommand( + "process handle SIGCHLD -s 1 -p 1 -n 1", return_obj) + self.assertTrue( + return_obj.Succeeded(), + "Set SIGCHLD to pass, stop, notify") + + value = frame.EvaluateExpression( + "call_me (%d)" % + (num_sigchld), options) + self.assertTrue( + value.IsValid() and value.GetError().Success() == False) + + # Set signal handling back to no-stop, and continue and we should end + # up back in out starting frame: + self.dbg.GetCommandInterpreter().HandleCommand( + "process handle SIGCHLD -s 0 -p 1 -n 1", return_obj) + self.assertTrue( + return_obj.Succeeded(), + "Set SIGCHLD to pass, no-stop, notify") error = process.Continue() - self.assertTrue (error.Success(), "Continuing after stopping for signal succeeds.") - + self.assertTrue( + error.Success(), + "Continuing after stopping for signal succeeds.") + frame = self.thread.GetFrameAtIndex(0) - self.assertTrue (frame.GetPC() == self.orig_frame_pc, "Continuing returned to the place we started.") + self.assertTrue( + frame.GetPC() == self.orig_frame_pc, + "Continuing returned to the place we started.") diff --git a/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py b/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py index a6eb1bddc005..e5162609dfa6 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py +++ b/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py @@ -5,12 +5,12 @@ Test calling a function that throws an ObjC exception, make sure that it doesn't from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandWithThrowTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -20,7 +20,7 @@ class ExprCommandWithThrowTestCase(TestBase): TestBase.setUp(self) self.main_source = "call-throws.m" - self.main_source_spec = lldb.SBFileSpec (self.main_source) + self.main_source_spec = lldb.SBFileSpec(self.main_source) @skipUnlessDarwin def test(self): @@ -28,12 +28,13 @@ class ExprCommandWithThrowTestCase(TestBase): self.build() self.call_function() - def check_after_call (self): + def check_after_call(self): # Check that we are back where we were before: frame = self.thread.GetFrameAtIndex(0) - self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly") + self.assertTrue( + self.orig_frame_pc == frame.GetPC(), + "Restored the zeroth frame correctly") - def call_function(self): """Test calling function that throws.""" exe_name = "a.out" @@ -42,72 +43,82 @@ class ExprCommandWithThrowTestCase(TestBase): target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) - breakpoint = target.BreakpointCreateBySourceRegex('I am about to throw.',self.main_source_spec) + breakpoint = target.BreakpointCreateBySourceRegex( + 'I am about to throw.', self.main_source_spec) self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple (None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) - + threads = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) + self.assertTrue(len(threads) == 1) self.thread = threads[0] - + options = lldb.SBExpressionOptions() options.SetUnwindOnError(True) frame = self.thread.GetFrameAtIndex(0) - # Store away the PC to check that the functions unwind to the right place after calls + # Store away the PC to check that the functions unwind to the right + # place after calls self.orig_frame_pc = frame.GetPC() - value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) - self.assertTrue (value.IsValid()) - self.assertTrue (value.GetError().Success() == False) + value = frame.EvaluateExpression("[my_class callMeIThrow]", options) + self.assertTrue(value.IsValid()) + self.assertTrue(value.GetError().Success() == False) self.check_after_call() # Okay, now try with a breakpoint in the called code in the case where # we are ignoring breakpoint hits. - handler_bkpt = target.BreakpointCreateBySourceRegex("I felt like it", self.main_source_spec) - self.assertTrue (handler_bkpt.GetNumLocations() > 0) + handler_bkpt = target.BreakpointCreateBySourceRegex( + "I felt like it", self.main_source_spec) + self.assertTrue(handler_bkpt.GetNumLocations() > 0) options.SetIgnoreBreakpoints(True) options.SetUnwindOnError(True) - value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) + value = frame.EvaluateExpression("[my_class callMeIThrow]", options) - self.assertTrue (value.IsValid() and value.GetError().Success() == False) + self.assertTrue( + value.IsValid() and value.GetError().Success() == False) self.check_after_call() - # Now set the ObjC language breakpoint and make sure that doesn't interfere with the call: - exception_bkpt = target.BreakpointCreateForException (lldb.eLanguageTypeObjC, False, True) + # Now set the ObjC language breakpoint and make sure that doesn't + # interfere with the call: + exception_bkpt = target.BreakpointCreateForException( + lldb.eLanguageTypeObjC, False, True) self.assertTrue(exception_bkpt.GetNumLocations() > 0) options.SetIgnoreBreakpoints(True) options.SetUnwindOnError(True) - value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) + value = frame.EvaluateExpression("[my_class callMeIThrow]", options) - self.assertTrue (value.IsValid() and value.GetError().Success() == False) + self.assertTrue( + value.IsValid() and value.GetError().Success() == False) self.check_after_call() - # Now turn off exception trapping, and call a function that catches the exceptions, - # and make sure the function actually completes, and we get the right value: + # and make sure the function actually completes, and we get the right + # value: options.SetTrapExceptions(False) - value = frame.EvaluateExpression ("[my_class iCatchMyself]", options) - self.assertTrue (value.IsValid()) - self.assertTrue (value.GetError().Success() == True) - self.assertTrue (value.GetValueAsUnsigned() == 57) + value = frame.EvaluateExpression("[my_class iCatchMyself]", options) + self.assertTrue(value.IsValid()) + self.assertTrue(value.GetError().Success()) + self.assertTrue(value.GetValueAsUnsigned() == 57) self.check_after_call() options.SetTrapExceptions(True) - # Now set this unwind on error to false, and make sure that we stop where the exception was thrown + # Now set this unwind on error to false, and make sure that we stop + # where the exception was thrown options.SetUnwindOnError(False) - value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) - + value = frame.EvaluateExpression("[my_class callMeIThrow]", options) - self.assertTrue (value.IsValid() and value.GetError().Success() == False) + self.assertTrue( + value.IsValid() and value.GetError().Success() == False) self.check_after_call() diff --git a/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py b/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py index 66fa69cdfff2..a771e7004c94 100644 --- a/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py +++ b/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py @@ -1,12 +1,12 @@ from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCharTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -16,24 +16,27 @@ class ExprCharTestCase(TestBase): TestBase.setUp(self) self.main_source = "main.cpp" - self.main_source_spec = lldb.SBFileSpec (self.main_source) + self.main_source_spec = lldb.SBFileSpec(self.main_source) self.exe = os.path.join(os.getcwd(), "a.out") def do_test(self, dictionary=None): """These basic expression commands should work as expected.""" - self.build(dictionary = dictionary) + self.build(dictionary=dictionary) target = self.dbg.CreateTarget(self.exe) self.assertTrue(target) - breakpoint = target.BreakpointCreateBySourceRegex('// Break here', self.main_source_spec) + breakpoint = target.BreakpointCreateBySourceRegex( + '// Break here', self.main_source_spec) self.assertTrue(breakpoint) # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process) - threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint) + threads = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) self.assertEqual(len(threads), 1) frame = threads[0].GetFrameAtIndex(0) @@ -57,13 +60,22 @@ class ExprCharTestCase(TestBase): def test_default_char(self): self.do_test() - @expectedFailureAll(archs=["arm", "aarch64", "s390x"], bugnumber="llvm.org/pr23069") + @expectedFailureAll( + archs=[ + "arm", + "aarch64", + "s390x"], + bugnumber="llvm.org/pr23069") @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") def test_signed_char(self): self.do_test(dictionary={'CFLAGS_EXTRAS': '-fsigned-char'}) - @expectedFailureAll(archs=["i[3-6]86", "x86_64"], bugnumber="llvm.org/pr23069") + @expectedFailureAll( + archs=[ + "i[3-6]86", + "x86_64"], + bugnumber="llvm.org/pr23069, <rdar://problem/28721938>") @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") - @expectedFailureAll(triple = 'mips*', bugnumber="llvm.org/pr23069") + @expectedFailureAll(triple='mips*', bugnumber="llvm.org/pr23069") def test_unsigned_char(self): self.do_test(dictionary={'CFLAGS_EXTRAS': '-funsigned-char'}) diff --git a/packages/Python/lldbsuite/test/expression_command/expr-in-syscall/TestExpressionInSyscall.py b/packages/Python/lldbsuite/test/expression_command/expr-in-syscall/TestExpressionInSyscall.py index a715ee31e5fa..dcfb648ada50 100644 --- a/packages/Python/lldbsuite/test/expression_command/expr-in-syscall/TestExpressionInSyscall.py +++ b/packages/Python/lldbsuite/test/expression_command/expr-in-syscall/TestExpressionInSyscall.py @@ -3,7 +3,6 @@ from __future__ import print_function - import os import lldb from lldbsuite.test.decorators import * @@ -15,7 +14,9 @@ class ExprSyscallTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765, getpid() does not exist on Windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr21765, getpid() does not exist on Windows") def test_setpgid(self): self.build() self.expr_syscall() @@ -32,16 +33,16 @@ class ExprSyscallTestCase(TestBase): # launch the inferior and don't wait for it to stop self.dbg.SetAsync(True) error = lldb.SBError() - process = target.Launch (listener, - None, # argv - None, # envp - None, # stdin_path - None, # stdout_path - None, # stderr_path - None, # working directory - 0, # launch flags - False, # Stop at entry - error) # error + process = target.Launch(listener, + None, # argv + None, # envp + None, # stdin_path + None, # stdout_path + None, # stderr_path + None, # working directory + 0, # launch flags + False, # Stop at entry + error) # error self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) @@ -54,7 +55,10 @@ class ExprSyscallTestCase(TestBase): pass # now the process should be running (blocked in the syscall) - self.assertEqual(process.GetState(), lldb.eStateRunning, "Process is running") + self.assertEqual( + process.GetState(), + lldb.eStateRunning, + "Process is running") # send the process a signal process.SendAsyncInterrupt() @@ -62,13 +66,18 @@ class ExprSyscallTestCase(TestBase): pass # as a result the process should stop - # in all likelihood we have stopped in the middle of the sleep() syscall - self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + # in all likelihood we have stopped in the middle of the sleep() + # syscall + self.assertEqual( + process.GetState(), + lldb.eStateStopped, + PROCESS_STOPPED) thread = process.GetSelectedThread() # try evaluating a couple of expressions in this state - self.expect("expr release_flag = 1", substrs = [" = 1"]) - self.expect("print (int)getpid()", substrs = [str(process.GetProcessID())]) + self.expect("expr release_flag = 1", substrs=[" = 1"]) + self.expect("print (int)getpid()", + substrs=[str(process.GetProcessID())]) # and run the process to completion process.Continue() diff --git a/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py b/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py index 7e11f2b201f2..418c5325ad08 100644 --- a/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py +++ b/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py @@ -5,12 +5,12 @@ Test calling an expression with errors that a FixIt can fix. from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprCommandWithFixits(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -20,14 +20,21 @@ class ExprCommandWithFixits(TestBase): TestBase.setUp(self) self.main_source = "main.cpp" - self.main_source_spec = lldb.SBFileSpec (self.main_source) + self.main_source_spec = lldb.SBFileSpec(self.main_source) @skipUnlessDarwin - def test(self): - """Test calling a function that throws and ObjC exception.""" + def test_with_target(self): + """Test calling expressions with errors that can be fixed by the FixIts.""" self.build() self.try_expressions() + def test_with_dummy_target(self): + """Test calling expressions in the dummy target with errors that can be fixed by the FixIts.""" + ret_val = lldb.SBCommandReturnObject() + result = self.dbg.GetCommandInterpreter().HandleCommand("expression ((1 << 16) - 1))", ret_val) + self.assertEqual(result, lldb.eReturnStatusSuccessFinishResult, "The expression was successful.") + self.assertTrue("Fix-it applied" in ret_val.GetError(), "Found the applied FixIt.") + def try_expressions(self): """Test calling expressions with errors that can be fixed by the FixIts.""" exe_name = "a.out" @@ -36,20 +43,23 @@ class ExprCommandWithFixits(TestBase): target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) - breakpoint = target.BreakpointCreateBySourceRegex('Stop here to evaluate expressions',self.main_source_spec) + breakpoint = target.BreakpointCreateBySourceRegex( + 'Stop here to evaluate expressions', self.main_source_spec) self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple (None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) - + threads = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) + self.assertTrue(len(threads) == 1) self.thread = threads[0] - + options = lldb.SBExpressionOptions() options.SetAutoApplyFixIts(True) @@ -60,7 +70,7 @@ class ExprCommandWithFixits(TestBase): self.assertTrue(value.IsValid()) self.assertTrue(value.GetError().Success()) self.assertTrue(value.GetValueAsUnsigned() == 10) - + # Try with two errors: two_error_expression = "my_pointer.second->a" value = frame.EvaluateExpression(two_error_expression, options) @@ -74,8 +84,9 @@ class ExprCommandWithFixits(TestBase): self.assertTrue(value.IsValid()) self.assertTrue(value.GetError().Fail()) error_string = value.GetError().GetCString() - self.assertTrue(error_string.find("fixed expression suggested:") != -1, "Fix was suggested") - self.assertTrue(error_string.find("my_pointer->second.a") != -1, "Fix was right") - - - + self.assertTrue( + error_string.find("fixed expression suggested:") != -1, + "Fix was suggested") + self.assertTrue( + error_string.find("my_pointer->second.a") != -1, + "Fix was right") diff --git a/packages/Python/lldbsuite/test/expression_command/formatters/TestFormatters.py b/packages/Python/lldbsuite/test/expression_command/formatters/TestFormatters.py index 4a99dc479019..c4126a329686 100644 --- a/packages/Python/lldbsuite/test/expression_command/formatters/TestFormatters.py +++ b/packages/Python/lldbsuite/test/expression_command/formatters/TestFormatters.py @@ -5,12 +5,12 @@ Test using LLDB data formatters with frozen objects coming from the expression p from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class ExprFormattersTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -22,11 +22,13 @@ class ExprFormattersTestCase(TestBase): self.line = line_number('main.cpp', '// Stop here') - @skipIfFreeBSD # llvm.org/pr24691 skipping to avoid crashing the test runner - @expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr19011 Newer Clang omits C1 complete object constructor') + @skipIfFreeBSD # llvm.org/pr24691 skipping to avoid crashing the test runner + @expectedFailureAll( + oslist=['freebsd'], + bugnumber='llvm.org/pr19011 Newer Clang omits C1 complete object constructor') @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") - @skipIfTargetAndroid() # skipping to avoid crashing the test runner - @expectedFailureAndroid('llvm.org/pr24691') # we hit an assertion in clang + @skipIfTargetAndroid() # skipping to avoid crashing the test runner + @expectedFailureAndroid('llvm.org/pr24691') # we hit an assertion in clang def test(self): """Test expr + formatters for good interoperability.""" self.build() @@ -36,64 +38,117 @@ class ExprFormattersTestCase(TestBase): def cleanup(): self.runCmd('type summary clear', check=False) self.runCmd('type synthetic clear', check=False) - + # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) """Test expr + formatters for good interoperability.""" self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, loc_exact=True) + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) self.runCmd("command script import formatters.py") self.runCmd("command script import foosynth.py") - + if self.TraceOn(): self.runCmd("frame variable foo1 --show-types") self.runCmd("frame variable foo1.b --show-types") self.runCmd("frame variable foo1.b.b_ref --show-types") - self.expect("expression --show-types -- *(new foo(47))", - substrs = ['(int) a = 47', '(bar) b = {', '(int) i = 94', '(baz) b = {', '(int) k = 99']) + self.expect( + "expression --show-types -- *(new foo(47))", + substrs=[ + '(int) a = 47', + '(bar) b = {', + '(int) i = 94', + '(baz) b = {', + '(int) k = 99']) self.runCmd("type summary add -F formatters.foo_SummaryProvider foo") self.expect("expression new int(12)", - substrs = ['(int *) $', ' = 0x']) + substrs=['(int *) $', ' = 0x']) - self.runCmd("type summary add -s \"${var%pointer} -> ${*var%decimal}\" \"int *\"") + self.runCmd( + "type summary add -s \"${var%pointer} -> ${*var%decimal}\" \"int *\"") self.expect("expression new int(12)", - substrs = ['(int *) $', '= 0x', ' -> 12']) + substrs=['(int *) $', '= 0x', ' -> 12']) self.expect("expression foo1.a_ptr", - substrs = ['(int *) $', '= 0x', ' -> 13']) - - self.expect("expression foo1", - substrs = ['(foo) $', ' a = 12', 'a_ptr = ', ' -> 13','i = 24','i_ptr = ', ' -> 25']) - - self.expect("expression --ptr-depth=1 -- new foo(47)", - substrs = ['(foo *) $', 'a = 47','a_ptr = ', ' -> 48','i = 94','i_ptr = ', ' -> 95']) - - self.expect("expression foo2", - substrs = ['(foo) $', 'a = 121','a_ptr = ', ' -> 122','i = 242','i_ptr = ', ' -> 243']) + substrs=['(int *) $', '= 0x', ' -> 13']) + + self.expect( + "expression foo1", + substrs=[ + '(foo) $', + ' a = 12', + 'a_ptr = ', + ' -> 13', + 'i = 24', + 'i_ptr = ', + ' -> 25']) + + self.expect( + "expression --ptr-depth=1 -- new foo(47)", + substrs=[ + '(foo *) $', + 'a = 47', + 'a_ptr = ', + ' -> 48', + 'i = 94', + 'i_ptr = ', + ' -> 95']) + + self.expect( + "expression foo2", + substrs=[ + '(foo) $', + 'a = 121', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 243']) object_name = self.res.GetOutput() object_name = object_name[7:] object_name = object_name[0:object_name.find(' =')] - self.expect("frame variable foo2", - substrs = ['(foo)', 'foo2', 'a = 121','a_ptr = ', ' -> 122','i = 242','i_ptr = ', ' -> 243']) - - self.expect("expression $" + object_name, - substrs = ['(foo) $', 'a = 121','a_ptr = ', ' -> 122','i = 242','i_ptr = ', ' -> 243', 'h = 245','k = 247']) + self.expect( + "frame variable foo2", + substrs=[ + '(foo)', + 'foo2', + 'a = 121', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 243']) + + self.expect( + "expression $" + + object_name, + substrs=[ + '(foo) $', + 'a = 121', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 243', + 'h = 245', + 'k = 247']) self.runCmd("type summary delete foo") - self.runCmd("type synthetic add --python-class foosynth.FooSyntheticProvider foo") + self.runCmd( + "type synthetic add --python-class foosynth.FooSyntheticProvider foo") self.expect("expression --show-types -- $" + object_name, - substrs = ['(foo) $', ' = {', '(int) *i_ptr = 243']) + substrs=['(foo) $', ' = {', '(int) *i_ptr = 243']) self.runCmd("n") self.runCmd("n") @@ -101,31 +156,61 @@ class ExprFormattersTestCase(TestBase): self.runCmd("type synthetic delete foo") self.runCmd("type summary add -F formatters.foo_SummaryProvider foo") - self.expect("expression foo2", - substrs = ['(foo) $', 'a = 7777','a_ptr = ', ' -> 122','i = 242','i_ptr = ', ' -> 8888']) + self.expect( + "expression foo2", + substrs=[ + '(foo) $', + 'a = 7777', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 8888']) self.expect("expression $" + object_name + '.a', - substrs = ['7777']) + substrs=['7777']) self.expect("expression *$" + object_name + '.b.i_ptr', - substrs = ['8888']) - - self.expect("expression $" + object_name, - substrs = ['(foo) $', 'a = 121', 'a_ptr = ', ' -> 122', 'i = 242', 'i_ptr = ', ' -> 8888', 'h = 245','k = 247']) + substrs=['8888']) + + self.expect( + "expression $" + + object_name, + substrs=[ + '(foo) $', + 'a = 121', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 8888', + 'h = 245', + 'k = 247']) self.runCmd("type summary delete foo") - self.runCmd("type synthetic add --python-class foosynth.FooSyntheticProvider foo") + self.runCmd( + "type synthetic add --python-class foosynth.FooSyntheticProvider foo") self.expect("expression --show-types -- $" + object_name, - substrs = ['(foo) $', ' = {', '(int) *i_ptr = 8888']) + substrs=['(foo) $', ' = {', '(int) *i_ptr = 8888']) self.runCmd("n") self.runCmd("type synthetic delete foo") self.runCmd("type summary add -F formatters.foo_SummaryProvider foo") - self.expect("expression $" + object_name, - substrs = ['(foo) $', 'a = 121','a_ptr = ', ' -> 122','i = 242', 'i_ptr = ', ' -> 8888','k = 247']) + self.expect( + "expression $" + + object_name, + substrs=[ + '(foo) $', + 'a = 121', + 'a_ptr = ', + ' -> 122', + 'i = 242', + 'i_ptr = ', + ' -> 8888', + 'k = 247']) process = self.dbg.GetSelectedTarget().GetProcess() thread = process.GetThreadAtIndex(0) @@ -136,32 +221,78 @@ class ExprFormattersTestCase(TestBase): a_data = frozen.GetPointeeData() error = lldb.SBError() - self.assertTrue(a_data.GetUnsignedInt32(error, 0) == 122, '*a_ptr = 122') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 0) == 122, + '*a_ptr = 122') - self.runCmd("n");self.runCmd("n");self.runCmd("n"); + self.runCmd("n") + self.runCmd("n") + self.runCmd("n") self.expect("frame variable numbers", - substrs = ['1','2','3','4','5']) + substrs=['1', '2', '3', '4', '5']) self.expect("expression numbers", - substrs = ['1','2','3','4','5']) + substrs=['1', '2', '3', '4', '5']) frozen = frame.EvaluateExpression("&numbers") a_data = frozen.GetPointeeData(0, 1) - self.assertTrue(a_data.GetUnsignedInt32(error, 0) == 1, 'numbers[0] == 1') - self.assertTrue(a_data.GetUnsignedInt32(error, 4) == 2, 'numbers[1] == 2') - self.assertTrue(a_data.GetUnsignedInt32(error, 8) == 3, 'numbers[2] == 3') - self.assertTrue(a_data.GetUnsignedInt32(error, 12) == 4, 'numbers[3] == 4') - self.assertTrue(a_data.GetUnsignedInt32(error, 16) == 5, 'numbers[4] == 5') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 0) == 1, + 'numbers[0] == 1') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 4) == 2, + 'numbers[1] == 2') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 8) == 3, + 'numbers[2] == 3') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 12) == 4, + 'numbers[3] == 4') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 16) == 5, + 'numbers[4] == 5') frozen = frame.EvaluateExpression("numbers") a_data = frozen.GetData() - self.assertTrue(a_data.GetUnsignedInt32(error, 0) == 1, 'numbers[0] == 1') - self.assertTrue(a_data.GetUnsignedInt32(error, 4) == 2, 'numbers[1] == 2') - self.assertTrue(a_data.GetUnsignedInt32(error, 8) == 3, 'numbers[2] == 3') - self.assertTrue(a_data.GetUnsignedInt32(error, 12) == 4, 'numbers[3] == 4') - self.assertTrue(a_data.GetUnsignedInt32(error, 16) == 5, 'numbers[4] == 5') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 0) == 1, + 'numbers[0] == 1') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 4) == 2, + 'numbers[1] == 2') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 8) == 3, + 'numbers[2] == 3') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 12) == 4, + 'numbers[3] == 4') + self.assertTrue( + a_data.GetUnsignedInt32( + error, + 16) == 5, + 'numbers[4] == 5') diff --git a/packages/Python/lldbsuite/test/expression_command/formatters/foosynth.py b/packages/Python/lldbsuite/test/expression_command/formatters/foosynth.py index 91c4d4a84c62..7b1284d2a769 100644 --- a/packages/Python/lldbsuite/test/expression_command/formatters/foosynth.py +++ b/packages/Python/lldbsuite/test/expression_command/formatters/foosynth.py @@ -1,29 +1,33 @@ import lldb + class FooSyntheticProvider: - def __init__(self,valobj,dict): - self.valobj = valobj; - self.update(); - - def update(self): - self.adjust_for_architecture() - - def num_children(self): - return 1; - - def get_child_at_index(self,index): - if index != 0: - return None; - return self.i_ptr.Dereference(); - - def get_child_index(self,name): - if name == "*i_ptr": - return 0; - return None; - - def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) - self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) - self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() - self.bar = self.valobj.GetChildMemberWithName('b'); - self.i_ptr = self.bar.GetChildMemberWithName('i_ptr');
\ No newline at end of file + + def __init__(self, valobj, dict): + self.valobj = valobj + self.update() + + def update(self): + self.adjust_for_architecture() + + def num_children(self): + return 1 + + def get_child_at_index(self, index): + if index != 0: + return None + return self.i_ptr.Dereference() + + def get_child_index(self, name): + if name == "*i_ptr": + return 0 + return None + + def adjust_for_architecture(self): + self.lp64 = ( + self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_little = (self.valobj.GetTarget().GetProcess( + ).GetByteOrder() == lldb.eByteOrderLittle) + self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() + self.bar = self.valobj.GetChildMemberWithName('b') + self.i_ptr = self.bar.GetChildMemberWithName('i_ptr') diff --git a/packages/Python/lldbsuite/test/expression_command/formatters/formatters.py b/packages/Python/lldbsuite/test/expression_command/formatters/formatters.py index ce922a8f911d..dae84988af9e 100644 --- a/packages/Python/lldbsuite/test/expression_command/formatters/formatters.py +++ b/packages/Python/lldbsuite/test/expression_command/formatters/formatters.py @@ -1,17 +1,17 @@ -def foo_SummaryProvider (valobj,dict): - a = valobj.GetChildMemberWithName('a'); - a_ptr = valobj.GetChildMemberWithName('a_ptr'); - bar = valobj.GetChildMemberWithName('b'); - i = bar.GetChildMemberWithName('i'); - i_ptr = bar.GetChildMemberWithName('i_ptr'); - b_ref = bar.GetChildMemberWithName('b_ref'); - b_ref_ptr = b_ref.AddressOf() - b_ref = b_ref_ptr.Dereference() - h = b_ref.GetChildMemberWithName('h'); - k = b_ref.GetChildMemberWithName('k'); - return 'a = ' + str(a.GetValueAsUnsigned(0)) + ', a_ptr = ' + \ - str(a_ptr.GetValueAsUnsigned(0)) + ' -> ' + str(a_ptr.Dereference().GetValueAsUnsigned(0)) + \ - ', i = ' + str(i.GetValueAsUnsigned(0)) + \ - ', i_ptr = ' + str(i_ptr.GetValueAsUnsigned(0)) + ' -> ' + str(i_ptr.Dereference().GetValueAsUnsigned(0)) + \ - ', b_ref = ' + str(b_ref.GetValueAsUnsigned(0)) + \ - ', h = ' + str(h.GetValueAsUnsigned(0)) + ' , k = ' + str(k.GetValueAsUnsigned(0))
\ No newline at end of file +def foo_SummaryProvider(valobj, dict): + a = valobj.GetChildMemberWithName('a') + a_ptr = valobj.GetChildMemberWithName('a_ptr') + bar = valobj.GetChildMemberWithName('b') + i = bar.GetChildMemberWithName('i') + i_ptr = bar.GetChildMemberWithName('i_ptr') + b_ref = bar.GetChildMemberWithName('b_ref') + b_ref_ptr = b_ref.AddressOf() + b_ref = b_ref_ptr.Dereference() + h = b_ref.GetChildMemberWithName('h') + k = b_ref.GetChildMemberWithName('k') + return 'a = ' + str(a.GetValueAsUnsigned(0)) + ', a_ptr = ' + \ + str(a_ptr.GetValueAsUnsigned(0)) + ' -> ' + str(a_ptr.Dereference().GetValueAsUnsigned(0)) + \ + ', i = ' + str(i.GetValueAsUnsigned(0)) + \ + ', i_ptr = ' + str(i_ptr.GetValueAsUnsigned(0)) + ' -> ' + str(i_ptr.Dereference().GetValueAsUnsigned(0)) + \ + ', b_ref = ' + str(b_ref.GetValueAsUnsigned(0)) + \ + ', h = ' + str(h.GetValueAsUnsigned(0)) + ' , k = ' + str(k.GetValueAsUnsigned(0)) diff --git a/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py b/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py index c4f176703225..894d0bfaa86e 100644 --- a/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py +++ b/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py @@ -2,38 +2,41 @@ Test PHI nodes work in the IR interpreter. """ -import os, os.path +import os +import os.path import lldb from lldbsuite.test.lldbtest import * import lldbsuite.test.lldbutil as lldbutil + class IRInterpreterPHINodesTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) def test_phi_node_support(self): """Test support for PHI nodes in the IR interpreter.""" - + self.build() exe = os.path.join(os.getcwd(), 'a.out') self.runCmd('file ' + exe, CURRENT_EXECUTABLE_SET) - + # Break on the first assignment to i line = line_number('main.cpp', 'i = 5') - lldbutil.run_break_set_by_file_and_line(self, 'main.cpp', line, num_expected_locations=1, loc_exact=True) - + lldbutil.run_break_set_by_file_and_line( + self, 'main.cpp', line, num_expected_locations=1, loc_exact=True) + self.runCmd('run', RUN_SUCCEEDED) - + # The stop reason of the thread should be breakpoint self.expect('thread list', STOPPED_DUE_TO_BREAKPOINT, - substrs = ['stopped', 'stop reason = breakpoint']) - + substrs=['stopped', 'stop reason = breakpoint']) + self.runCmd('s') - + # The logical 'or' causes a PHI node to be generated. Execute without JIT # to test that the interpreter can handle this self.expect('expr -j 0 -- i == 3 || i == 5', substrs=['true']) - + self.runCmd('s') self.expect('expr -j 0 -- i == 3 || i == 5', substrs=['false']) self.runCmd('s') diff --git a/packages/Python/lldbsuite/test/expression_command/ir-interpreter/TestIRInterpreter.py b/packages/Python/lldbsuite/test/expression_command/ir-interpreter/TestIRInterpreter.py index 2a21d0473715..5c5110b69945 100644 --- a/packages/Python/lldbsuite/test/expression_command/ir-interpreter/TestIRInterpreter.py +++ b/packages/Python/lldbsuite/test/expression_command/ir-interpreter/TestIRInterpreter.py @@ -6,12 +6,14 @@ from __future__ import print_function import unittest2 -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class IRInterpreterTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -25,7 +27,8 @@ class IRInterpreterTestCase(TestBase): # Disable confirmation prompt to avoid infinite wait self.runCmd("settings set auto-confirm true") - self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm")) + self.addTearDownHook( + lambda: self.runCmd("settings clear auto-confirm")) def build_and_run(self): """Test the IR interpreter""" @@ -33,13 +36,20 @@ class IRInterpreterTestCase(TestBase): self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=False) + lldbutil.run_break_set_by_file_and_line( + self, "main.c", self.line, num_expected_locations=1, loc_exact=False) self.runCmd("run", RUN_SUCCEEDED) @add_test_categories(['pyapi']) - @expectedFailureAll(oslist=['windows'], bugnumber="http://llvm.org/pr21765") # getpid() is POSIX, among other problems, see bug - @expectedFailureAll(oslist=['linux'], archs=['arm'], bugnumber="llvm.org/pr27868") + # getpid() is POSIX, among other problems, see bug + @expectedFailureAll( + oslist=['windows'], + bugnumber="http://llvm.org/pr21765") + @expectedFailureAll( + oslist=['linux'], + archs=['arm'], + bugnumber="llvm.org/pr27868") def test_ir_interpreter(self): self.build_and_run() @@ -62,11 +72,16 @@ class IRInterpreterTestCase(TestBase): self.frame().EvaluateExpression(expression, options) for expression in expressions: - interp_expression = expression - jit_expression = "(int)getpid(); " + expression - - interp_result = self.frame().EvaluateExpression(interp_expression, options).GetValueAsSigned() - jit_result = self.frame().EvaluateExpression(jit_expression, options).GetValueAsSigned() - - self.assertEqual(interp_result, jit_result, "While evaluating " + expression) - + interp_expression = expression + jit_expression = "(int)getpid(); " + expression + + interp_result = self.frame().EvaluateExpression( + interp_expression, options).GetValueAsSigned() + jit_result = self.frame().EvaluateExpression( + jit_expression, options).GetValueAsSigned() + + self.assertEqual( + interp_result, + jit_result, + "While evaluating " + + expression) diff --git a/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py b/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py index 2d0b23b4e5ba..afb497e04b5b 100644 --- a/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py +++ b/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py @@ -7,13 +7,14 @@ expected in a SyntheticChildrenProvider from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class Issue11581TestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -25,54 +26,61 @@ class Issue11581TestCase(TestBase): def cleanup(): self.runCmd('type synthetic clear', check=False) - # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) """valobj.AddressOf() should return correct values.""" self.build() - + exe = os.path.join(os.getcwd(), "a.out") - + target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) - breakpoint = target.BreakpointCreateBySourceRegex('Set breakpoint here.',lldb.SBFileSpec ("main.cpp", False)) - - process = target.LaunchSimple (None, None, self.get_process_working_directory()) - self.assertTrue (process, "Created a process.") - self.assertTrue (process.GetState() == lldb.eStateStopped, "Stopped it too.") + breakpoint = target.BreakpointCreateBySourceRegex( + 'Set breakpoint here.', lldb.SBFileSpec("main.cpp", False)) + + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertTrue(process, "Created a process.") + self.assertTrue( + process.GetState() == lldb.eStateStopped, + "Stopped it too.") - thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) - self.assertTrue (len(thread_list) == 1) + thread_list = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) + self.assertTrue(len(thread_list) == 1) thread = thread_list[0] self.runCmd("command script import --allow-reload s11588.py") - self.runCmd("type synthetic add --python-class s11588.Issue11581SyntheticProvider StgClosure") + self.runCmd( + "type synthetic add --python-class s11588.Issue11581SyntheticProvider StgClosure") self.expect("expr --show-types -- *((StgClosure*)(r14-1))", - substrs = ["(StgClosure) $", - "(StgClosure *) &$","0x", - "addr = ", - "load_address = "]) + substrs=["(StgClosure) $", + "(StgClosure *) &$", "0x", + "addr = ", + "load_address = "]) # register r14 is an x86_64 extension let's skip this part of the test # if we are on a different architecture if self.getArchitecture() == 'x86_64': - target = lldb.debugger.GetSelectedTarget() - process = target.GetProcess() - frame = process.GetSelectedThread().GetSelectedFrame() - pointer = frame.FindVariable("r14") - addr = pointer.GetValueAsUnsigned(0) - self.assertTrue(addr != 0, "could not read pointer to StgClosure") - addr = addr - 1 - self.runCmd("register write r14 %d" % addr) - self.expect("register read r14", - substrs = ["0x",hex(addr)[2:].rstrip("L")]) # Remove trailing 'L' if it exists - self.expect("expr --show-types -- *(StgClosure*)$r14", - substrs = ["(StgClosure) $", - "(StgClosure *) &$","0x", - "addr = ", - "load_address = ", - hex(addr)[2:].rstrip("L"), - str(addr)]) + target = lldb.debugger.GetSelectedTarget() + process = target.GetProcess() + frame = process.GetSelectedThread().GetSelectedFrame() + pointer = frame.FindVariable("r14") + addr = pointer.GetValueAsUnsigned(0) + self.assertTrue(addr != 0, "could not read pointer to StgClosure") + addr = addr - 1 + self.runCmd("register write r14 %d" % addr) + self.expect( + "register read r14", substrs=[ + "0x", hex(addr)[ + 2:].rstrip("L")]) # Remove trailing 'L' if it exists + self.expect("expr --show-types -- *(StgClosure*)$r14", + substrs=["(StgClosure) $", + "(StgClosure *) &$", "0x", + "addr = ", + "load_address = ", + hex(addr)[2:].rstrip("L"), + str(addr)]) diff --git a/packages/Python/lldbsuite/test/expression_command/issue_11588/s11588.py b/packages/Python/lldbsuite/test/expression_command/issue_11588/s11588.py index 01bb09a1b0d6..51c20423ed36 100644 --- a/packages/Python/lldbsuite/test/expression_command/issue_11588/s11588.py +++ b/packages/Python/lldbsuite/test/expression_command/issue_11588/s11588.py @@ -1,26 +1,28 @@ class Issue11581SyntheticProvider(object): - def __init__(self, valobj, dict): - self.valobj = valobj - self.addrOf = valobj.AddressOf() - self.addr = valobj.GetAddress() - self.load_address = valobj.GetLoadAddress() - def num_children(self): - return 3; + def __init__(self, valobj, dict): + self.valobj = valobj + self.addrOf = valobj.AddressOf() + self.addr = valobj.GetAddress() + self.load_address = valobj.GetLoadAddress() - def get_child_at_index(self, index): - if index == 0: - return self.addrOf - if index == 1: - return self.valobj.CreateValueFromExpression("addr", str(self.addr)) - if index == 2: - return self.valobj.CreateValueFromExpression("load_address", str(self.load_address)) + def num_children(self): + return 3 - def get_child_index(self, name): - if name == "addrOf": - return 0 - if name == "addr": - return 1 - if name == "load_address": - return 2 + def get_child_at_index(self, index): + if index == 0: + return self.addrOf + if index == 1: + return self.valobj.CreateValueFromExpression( + "addr", str(self.addr)) + if index == 2: + return self.valobj.CreateValueFromExpression( + "load_address", str(self.load_address)) + def get_child_index(self, name): + if name == "addrOf": + return 0 + if name == "addr": + return 1 + if name == "load_address": + return 2 diff --git a/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py b/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py index 939d2e45d7d5..70b862bf4867 100644 --- a/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py +++ b/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py @@ -6,13 +6,21 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class TestMacros(TestBase): mydir = TestBase.compute_mydir(__file__) - @expectedFailureAll(compiler="clang", bugnumber="clang does not emit .debug_macro[.dwo] sections.") - @expectedFailureAll(debug_info="dwo", bugnumber="GCC produces multiple .debug_macro.dwo sections and the spec is unclear as to what it means") - @expectedFailureAll(hostoslist=["windows"], compiler="gcc", triple='.*-android') + @expectedFailureAll( + compiler="clang", + bugnumber="clang does not emit .debug_macro[.dwo] sections.") + @expectedFailureAll( + debug_info="dwo", + bugnumber="GCC produces multiple .debug_macro.dwo sections and the spec is unclear as to what it means") + @expectedFailureAll( + hostoslist=["windows"], + compiler="gcc", + triple='.*-android') def test_expr_with_macros(self): self.build() @@ -25,7 +33,7 @@ class TestMacros(TestBase): # Get the path of the executable cwd = os.getcwd() exe_file = "a.out" - exe_path = os.path.join(cwd, exe_file) + exe_path = os.path.join(cwd, exe_file) # Load the executable target = self.dbg.CreateTarget(exe_path) @@ -33,51 +41,78 @@ class TestMacros(TestBase): # Set breakpoints bp1 = target.BreakpointCreateBySourceRegex("Break here", src_file_spec) - self.assertTrue(bp1.IsValid() and bp1.GetNumLocations() >= 1, VALID_BREAKPOINT) + self.assertTrue( + bp1.IsValid() and bp1.GetNumLocations() >= 1, + VALID_BREAKPOINT) # Launch the process - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process.IsValid(), PROCESS_IS_VALID) # Get the thread of the process - self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) - thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertTrue( + process.GetState() == lldb.eStateStopped, + PROCESS_STOPPED) + thread = lldbutil.get_stopped_thread( + process, lldb.eStopReasonBreakpoint) # Get frame for current thread frame = thread.GetSelectedFrame() result = frame.EvaluateExpression("MACRO_1") - self.assertTrue(result.IsValid() and result.GetValue() == "100", "MACRO_1 = 100") + self.assertTrue( + result.IsValid() and result.GetValue() == "100", + "MACRO_1 = 100") result = frame.EvaluateExpression("MACRO_2") - self.assertTrue(result.IsValid() and result.GetValue() == "200", "MACRO_2 = 200") + self.assertTrue( + result.IsValid() and result.GetValue() == "200", + "MACRO_2 = 200") result = frame.EvaluateExpression("ONE") - self.assertTrue(result.IsValid() and result.GetValue() == "1", "ONE = 1") + self.assertTrue( + result.IsValid() and result.GetValue() == "1", + "ONE = 1") result = frame.EvaluateExpression("TWO") - self.assertTrue(result.IsValid() and result.GetValue() == "2", "TWO = 2") + self.assertTrue( + result.IsValid() and result.GetValue() == "2", + "TWO = 2") result = frame.EvaluateExpression("THREE") - self.assertTrue(result.IsValid() and result.GetValue() == "3", "THREE = 3") + self.assertTrue( + result.IsValid() and result.GetValue() == "3", + "THREE = 3") result = frame.EvaluateExpression("FOUR") - self.assertTrue(result.IsValid() and result.GetValue() == "4", "FOUR = 4") + self.assertTrue( + result.IsValid() and result.GetValue() == "4", + "FOUR = 4") result = frame.EvaluateExpression("HUNDRED") - self.assertTrue(result.IsValid() and result.GetValue() == "100", "HUNDRED = 100") + self.assertTrue( + result.IsValid() and result.GetValue() == "100", + "HUNDRED = 100") result = frame.EvaluateExpression("THOUSAND") - self.assertTrue(result.IsValid() and result.GetValue() == "1000", "THOUSAND = 1000") + self.assertTrue( + result.IsValid() and result.GetValue() == "1000", + "THOUSAND = 1000") result = frame.EvaluateExpression("MILLION") - self.assertTrue(result.IsValid() and result.GetValue() == "1000000", "MILLION = 1000000") + self.assertTrue(result.IsValid() and result.GetValue() + == "1000000", "MILLION = 1000000") result = frame.EvaluateExpression("MAX(ONE, TWO)") - self.assertTrue(result.IsValid() and result.GetValue() == "2", "MAX(ONE, TWO) = 2") + self.assertTrue( + result.IsValid() and result.GetValue() == "2", + "MAX(ONE, TWO) = 2") result = frame.EvaluateExpression("MAX(THREE, TWO)") - self.assertTrue(result.IsValid() and result.GetValue() == "3", "MAX(THREE, TWO) = 3") + self.assertTrue( + result.IsValid() and result.GetValue() == "3", + "MAX(THREE, TWO) = 3") # Get the thread of the process thread.StepOver() @@ -86,10 +121,14 @@ class TestMacros(TestBase): frame = thread.GetSelectedFrame() result = frame.EvaluateExpression("MACRO_2") - self.assertTrue(result.GetError().Fail(), "Printing MACRO_2 fails in the mail file") + self.assertTrue( + result.GetError().Fail(), + "Printing MACRO_2 fails in the mail file") result = frame.EvaluateExpression("FOUR") - self.assertTrue(result.GetError().Fail(), "Printing FOUR fails in the main file") + self.assertTrue( + result.GetError().Fail(), + "Printing FOUR fails in the main file") thread.StepInto() @@ -97,14 +136,20 @@ class TestMacros(TestBase): frame = thread.GetSelectedFrame() result = frame.EvaluateExpression("ONE") - self.assertTrue(result.IsValid() and result.GetValue() == "1", "ONE = 1") + self.assertTrue( + result.IsValid() and result.GetValue() == "1", + "ONE = 1") result = frame.EvaluateExpression("MAX(ONE, TWO)") - self.assertTrue(result.IsValid() and result.GetValue() == "2", "MAX(ONE, TWO) = 2") + self.assertTrue( + result.IsValid() and result.GetValue() == "2", + "MAX(ONE, TWO) = 2") # This time, MACRO_1 and MACRO_2 are not visible. result = frame.EvaluateExpression("MACRO_1") - self.assertTrue(result.GetError().Fail(), "Printing MACRO_1 fails in the header file") + self.assertTrue(result.GetError().Fail(), + "Printing MACRO_1 fails in the header file") result = frame.EvaluateExpression("MACRO_2") - self.assertTrue(result.GetError().Fail(), "Printing MACRO_2 fails in the header file") + self.assertTrue(result.GetError().Fail(), + "Printing MACRO_2 fails in the header file") diff --git a/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py b/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py index 0691a866743b..b1b5cbe677c4 100644 --- a/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py +++ b/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py @@ -8,6 +8,7 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class MultilineExpressionsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -19,7 +20,9 @@ class MultilineExpressionsTestCase(TestBase): self.line = line_number('main.c', 'break') @skipIfRemote - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") def test_with_run_commands(self): """Test that multiline expressions work correctly""" self.build() @@ -28,7 +31,9 @@ class MultilineExpressionsTestCase(TestBase): prompt = "(lldb) " # So that the child gets torn down after the test. - self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, exe)) + self.child = pexpect.spawn( + '%s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, exe)) child = self.child # Turn on logging for what the child sends back. if self.TraceOn(): @@ -54,4 +59,4 @@ class MultilineExpressionsTestCase(TestBase): child.sendline('') child.expect_exact(prompt) self.expect(child.before, exe=False, - patterns = ['= 5']) + patterns=['= 5']) diff --git a/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py b/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py index 00c34820eef3..0d1a17352a3f 100644 --- a/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py +++ b/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py @@ -10,12 +10,13 @@ o test_expr_options: from __future__ import print_function - -import os, time +import os +import time import lldb import lldbsuite.test.lldbutil as lldbutil from lldbsuite.test.lldbtest import * + class ExprOptionsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -25,7 +26,7 @@ class ExprOptionsTestCase(TestBase): TestBase.setUp(self) self.main_source = "main.cpp" - self.main_source_spec = lldb.SBFileSpec (self.main_source) + self.main_source_spec = lldb.SBFileSpec(self.main_source) self.line = line_number('main.cpp', '// breakpoint_in_main') self.exe = os.path.join(os.getcwd(), "a.out") @@ -41,14 +42,17 @@ class ExprOptionsTestCase(TestBase): self.assertTrue(target, VALID_TARGET) # Set breakpoints inside main. - breakpoint = target.BreakpointCreateBySourceRegex('// breakpoint_in_main', self.main_source_spec) + breakpoint = target.BreakpointCreateBySourceRegex( + '// breakpoint_in_main', self.main_source_spec) self.assertTrue(breakpoint) # Now launch the process, and do not stop at entry point. - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) - threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint) + threads = lldbutil.get_threads_stopped_at_breakpoint( + process, breakpoint) self.assertEqual(len(threads), 1) frame = threads[0].GetFrameAtIndex(0) diff --git a/packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py b/packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py index d3ce10d8f2ab..b99fb727e8a5 100644 --- a/packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py +++ b/packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py @@ -5,12 +5,12 @@ Test that we can p *objcObject from __future__ import print_function - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class PersistObjCPointeeType(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -19,12 +19,13 @@ class PersistObjCPointeeType(TestBase): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break for main.cpp. - self.line = line_number('main.m','// break here') + self.line = line_number('main.m', '// break here') @skipUnlessDarwin @expectedFailureAll( bugnumber='http://llvm.org/pr23504', oslist=['macosx'], compiler='clang', compiler_version=['<', '7.0.0']) + @skipIf(archs=["i386", "i686"]) def test_with(self): """Test that we can p *objcObject""" self.build() @@ -37,15 +38,16 @@ class PersistObjCPointeeType(TestBase): self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - lldbutil.run_break_set_by_file_and_line (self, "main.m", self.line, loc_exact=True) + lldbutil.run_break_set_by_file_and_line( + self, "main.m", self.line, loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) - + self.expect("p *self", substrs=['_sc_name = nil', - '_sc_name2 = nil', - '_sc_name3 = nil', - '_sc_name4 = nil', - '_sc_name5 = nil', - '_sc_name6 = nil', - '_sc_name7 = nil', - '_sc_name8 = nil']) + '_sc_name2 = nil', + '_sc_name3 = nil', + '_sc_name4 = nil', + '_sc_name5 = nil', + '_sc_name6 = nil', + '_sc_name7 = nil', + '_sc_name8 = nil']) diff --git a/packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py b/packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py index 9d7359fb2d45..118b9f32c4bd 100644 --- a/packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py +++ b/packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py @@ -5,11 +5,11 @@ Test that we can have persistent pointer variables from __future__ import print_function - import lldb import lldbsuite.test.lldbutil as lldbutil from lldbsuite.test.lldbtest import * + class PersistentPtrUpdateTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -24,18 +24,18 @@ class PersistentPtrUpdateTestCase(TestBase): def cleanup(): pass - + # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) - + self.runCmd('break set -p here') self.runCmd("run", RUN_SUCCEEDED) - + self.runCmd("expr void* $foo = 0") - + self.runCmd("continue") - - self.expect("expr $foo", substrs=['$foo','0x0']) + + self.expect("expr $foo", substrs=['$foo', '0x0']) diff --git a/packages/Python/lldbsuite/test/expression_command/persistent_types/TestNestedPersistentTypes.py b/packages/Python/lldbsuite/test/expression_command/persistent_types/TestNestedPersistentTypes.py index 9099ae1806e3..12452a963772 100644 --- a/packages/Python/lldbsuite/test/expression_command/persistent_types/TestNestedPersistentTypes.py +++ b/packages/Python/lldbsuite/test/expression_command/persistent_types/TestNestedPersistentTypes.py @@ -5,13 +5,14 @@ Test that nested persistent types work. from __future__ import print_function - -import os, time +import os +import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class NestedPersistentTypesTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -29,15 +30,16 @@ class NestedPersistentTypesTestCase(TestBase): self.runCmd("expression struct $foo { int a; int b; };") - self.runCmd("expression struct $bar { struct $foo start; struct $foo end; };") + self.runCmd( |