1061da546Spatrick""" 2061da546SpatrickLLDB module which provides the abstract base class of lldb test case. 3061da546Spatrick 4dda28197SpatrickThe concrete subclass can override lldbtest.TestBase in order to inherit the 5061da546Spatrickcommon behavior for unitest.TestCase.setUp/tearDown implemented in this file. 6061da546Spatrick 7061da546Spatrick./dotest.py provides a test driver which sets up the environment to run the 8061da546Spatrickentire of part of the test suite . Example: 9061da546Spatrick 10061da546Spatrick# Exercises the test suite in the types directory.... 11061da546Spatrick/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 types 12061da546Spatrick... 13061da546Spatrick 14061da546SpatrickSession logs for test failures/errors/unexpected successes will go into directory '2012-05-16-13_35_42' 15061da546SpatrickCommand invoked: python ./dotest.py -A x86_64 types 16061da546Spatrickcompilers=['clang'] 17061da546Spatrick 18061da546SpatrickConfiguration: arch=x86_64 compiler=clang 19061da546Spatrick---------------------------------------------------------------------- 20061da546SpatrickCollected 72 tests 21061da546Spatrick 22061da546Spatrick........................................................................ 23061da546Spatrick---------------------------------------------------------------------- 24061da546SpatrickRan 72 tests in 135.468s 25061da546Spatrick 26061da546SpatrickOK 27061da546Spatrick$ 28061da546Spatrick""" 29061da546Spatrick 30061da546Spatrickfrom __future__ import absolute_import 31061da546Spatrickfrom __future__ import print_function 32061da546Spatrick 33061da546Spatrick# System modules 34061da546Spatrickimport abc 35061da546Spatrickfrom distutils.version import LooseVersion 36061da546Spatrickfrom functools import wraps 37061da546Spatrickimport gc 38061da546Spatrickimport glob 39061da546Spatrickimport io 40*f6aab3d8Srobertimport json 41061da546Spatrickimport os.path 42061da546Spatrickimport re 43061da546Spatrickimport shutil 44061da546Spatrickimport signal 45061da546Spatrickfrom subprocess import * 46061da546Spatrickimport sys 47061da546Spatrickimport time 48061da546Spatrickimport traceback 49061da546Spatrick 50061da546Spatrick# Third-party modules 51061da546Spatrickimport unittest2 52061da546Spatrick 53061da546Spatrick# LLDB modules 54061da546Spatrickimport lldb 55061da546Spatrickfrom . import configuration 56061da546Spatrickfrom . import decorators 57061da546Spatrickfrom . import lldbplatformutil 58061da546Spatrickfrom . import lldbtest_config 59061da546Spatrickfrom . import lldbutil 60061da546Spatrickfrom . import test_categories 61061da546Spatrickfrom lldbsuite.support import encoded_file 62061da546Spatrickfrom lldbsuite.support import funcutils 63*f6aab3d8Srobertfrom lldbsuite.support import seven 64be691f3bSpatrickfrom lldbsuite.test.builders import get_builder 65*f6aab3d8Srobertfrom lldbsuite.test_event import build_exception 66061da546Spatrick 67061da546Spatrick# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables 68061da546Spatrick# LLDB_COMMAND_TRACE is set from '-t' option. 69061da546Spatrick 70061da546Spatrick# By default, traceAlways is False. 71061da546Spatrickif "LLDB_COMMAND_TRACE" in os.environ and os.environ[ 72061da546Spatrick "LLDB_COMMAND_TRACE"] == "YES": 73061da546Spatrick traceAlways = True 74061da546Spatrickelse: 75061da546Spatrick traceAlways = False 76061da546Spatrick 77061da546Spatrick# By default, doCleanup is True. 78061da546Spatrickif "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"] == "NO": 79061da546Spatrick doCleanup = False 80061da546Spatrickelse: 81061da546Spatrick doCleanup = True 82061da546Spatrick 83061da546Spatrick 84061da546Spatrick# 85061da546Spatrick# Some commonly used assert messages. 86061da546Spatrick# 87061da546Spatrick 88061da546SpatrickCOMMAND_FAILED_AS_EXPECTED = "Command has failed as expected" 89061da546Spatrick 90061da546SpatrickCURRENT_EXECUTABLE_SET = "Current executable set successfully" 91061da546Spatrick 92061da546SpatrickPROCESS_IS_VALID = "Process is valid" 93061da546Spatrick 94061da546SpatrickPROCESS_KILLED = "Process is killed successfully" 95061da546Spatrick 96061da546SpatrickPROCESS_EXITED = "Process exited successfully" 97061da546Spatrick 98061da546SpatrickPROCESS_STOPPED = "Process status should be stopped" 99061da546Spatrick 100061da546SpatrickRUN_SUCCEEDED = "Process is launched successfully" 101061da546Spatrick 102061da546SpatrickRUN_COMPLETED = "Process exited successfully" 103061da546Spatrick 104061da546SpatrickBACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly" 105061da546Spatrick 106061da546SpatrickBREAKPOINT_CREATED = "Breakpoint created successfully" 107061da546Spatrick 108061da546SpatrickBREAKPOINT_STATE_CORRECT = "Breakpoint state is correct" 109061da546Spatrick 110061da546SpatrickBREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully" 111061da546Spatrick 112061da546SpatrickBREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit count = 1" 113061da546Spatrick 114061da546SpatrickBREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit count = 2" 115061da546Spatrick 116061da546SpatrickBREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit count = 3" 117061da546Spatrick 118061da546SpatrickMISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable." 119061da546Spatrick 120061da546SpatrickOBJECT_PRINTED_CORRECTLY = "Object printed correctly" 121061da546Spatrick 122061da546SpatrickSOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly" 123061da546Spatrick 124be691f3bSpatrickSTEP_IN_SUCCEEDED = "Thread step-in succeeded" 125be691f3bSpatrick 126061da546SpatrickSTEP_OUT_SUCCEEDED = "Thread step-out succeeded" 127061da546Spatrick 128061da546SpatrickSTOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception" 129061da546Spatrick 130061da546SpatrickSTOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion" 131061da546Spatrick 132061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint" 133061da546Spatrick 134061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % ( 135061da546Spatrick STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'") 136061da546Spatrick 137061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition" 138061da546Spatrick 139061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count" 140061da546Spatrick 141061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_JITTED_CONDITION = "Stopped due to breakpoint jitted condition" 142061da546Spatrick 143061da546SpatrickSTOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal" 144061da546Spatrick 145061da546SpatrickSTOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in" 146061da546Spatrick 147061da546SpatrickSTOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint" 148061da546Spatrick 149061da546SpatrickDATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly" 150061da546Spatrick 151061da546SpatrickVALID_BREAKPOINT = "Got a valid breakpoint" 152061da546Spatrick 153061da546SpatrickVALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location" 154061da546Spatrick 155061da546SpatrickVALID_COMMAND_INTERPRETER = "Got a valid command interpreter" 156061da546Spatrick 157061da546SpatrickVALID_FILESPEC = "Got a valid filespec" 158061da546Spatrick 159061da546SpatrickVALID_MODULE = "Got a valid module" 160061da546Spatrick 161061da546SpatrickVALID_PROCESS = "Got a valid process" 162061da546Spatrick 163061da546SpatrickVALID_SYMBOL = "Got a valid symbol" 164061da546Spatrick 165061da546SpatrickVALID_TARGET = "Got a valid target" 166061da546Spatrick 167061da546SpatrickVALID_PLATFORM = "Got a valid platform" 168061da546Spatrick 169061da546SpatrickVALID_TYPE = "Got a valid type" 170061da546Spatrick 171061da546SpatrickVALID_VARIABLE = "Got a valid variable" 172061da546Spatrick 173061da546SpatrickVARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly" 174061da546Spatrick 175061da546SpatrickWATCHPOINT_CREATED = "Watchpoint created successfully" 176061da546Spatrick 177061da546Spatrick 178061da546Spatrickdef CMD_MSG(str): 179be691f3bSpatrick '''A generic "Command '%s' did not return successfully" message generator.''' 180be691f3bSpatrick return "Command '%s' did not return successfully" % str 181061da546Spatrick 182061da546Spatrick 183061da546Spatrickdef COMPLETION_MSG(str_before, str_after, completions): 184be691f3bSpatrick '''A generic assertion failed message generator for the completion mechanism.''' 185061da546Spatrick return ("'%s' successfully completes to '%s', but completions were:\n%s" 186061da546Spatrick % (str_before, str_after, "\n".join(completions))) 187061da546Spatrick 188061da546Spatrick 189061da546Spatrickdef EXP_MSG(str, actual, exe): 190be691f3bSpatrick '''A generic "'%s' returned unexpected result" message generator if exe. 191be691f3bSpatrick Otherwise, it generates "'%s' does not match expected result" message.''' 192061da546Spatrick 193be691f3bSpatrick return "'%s' %s result, got '%s'" % ( 194be691f3bSpatrick str, 'returned unexpected' if exe else 'does not match expected', actual.strip()) 195061da546Spatrick 196061da546Spatrick 197061da546Spatrickdef SETTING_MSG(setting): 198be691f3bSpatrick '''A generic "Value of setting '%s' is not correct" message generator.''' 199be691f3bSpatrick return "Value of setting '%s' is not correct" % setting 200061da546Spatrick 201061da546Spatrick 202061da546Spatrickdef line_number(filename, string_to_match): 203061da546Spatrick """Helper function to return the line number of the first matched string.""" 204061da546Spatrick with io.open(filename, mode='r', encoding="utf-8") as f: 205061da546Spatrick for i, line in enumerate(f): 206061da546Spatrick if line.find(string_to_match) != -1: 207061da546Spatrick # Found our match. 208061da546Spatrick return i + 1 209061da546Spatrick raise Exception( 210061da546Spatrick "Unable to find '%s' within file %s" % 211061da546Spatrick (string_to_match, filename)) 212061da546Spatrick 213061da546Spatrickdef get_line(filename, line_number): 214061da546Spatrick """Return the text of the line at the 1-based line number.""" 215061da546Spatrick with io.open(filename, mode='r', encoding="utf-8") as f: 216061da546Spatrick return f.readlines()[line_number - 1] 217061da546Spatrick 218061da546Spatrickdef pointer_size(): 219061da546Spatrick """Return the pointer size of the host system.""" 220061da546Spatrick import ctypes 221061da546Spatrick a_pointer = ctypes.c_void_p(0xffff) 222061da546Spatrick return 8 * ctypes.sizeof(a_pointer) 223061da546Spatrick 224061da546Spatrick 225061da546Spatrickdef is_exe(fpath): 226061da546Spatrick """Returns true if fpath is an executable.""" 227*f6aab3d8Srobert if fpath == None: 228*f6aab3d8Srobert return False 229*f6aab3d8Srobert if sys.platform == 'win32': 230*f6aab3d8Srobert if not fpath.endswith(".exe"): 231*f6aab3d8Srobert fpath += ".exe" 232061da546Spatrick return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 233061da546Spatrick 234061da546Spatrick 235061da546Spatrickdef which(program): 236061da546Spatrick """Returns the full path to a program; None otherwise.""" 237061da546Spatrick fpath, fname = os.path.split(program) 238061da546Spatrick if fpath: 239061da546Spatrick if is_exe(program): 240061da546Spatrick return program 241061da546Spatrick else: 242061da546Spatrick for path in os.environ["PATH"].split(os.pathsep): 243061da546Spatrick exe_file = os.path.join(path, program) 244061da546Spatrick if is_exe(exe_file): 245061da546Spatrick return exe_file 246061da546Spatrick return None 247061da546Spatrick 248be691f3bSpatrickclass ValueCheck: 249be691f3bSpatrick def __init__(self, name=None, value=None, type=None, summary=None, 250*f6aab3d8Srobert children=None, dereference=None): 251be691f3bSpatrick """ 252be691f3bSpatrick :param name: The name that the SBValue should have. None if the summary 253be691f3bSpatrick should not be checked. 254be691f3bSpatrick :param summary: The summary that the SBValue should have. None if the 255be691f3bSpatrick summary should not be checked. 256be691f3bSpatrick :param value: The value that the SBValue should have. None if the value 257be691f3bSpatrick should not be checked. 258be691f3bSpatrick :param type: The type that the SBValue result should have. None if the 259be691f3bSpatrick type should not be checked. 260be691f3bSpatrick :param children: A list of ValueChecks that need to match the children 261be691f3bSpatrick of this SBValue. None if children shouldn't be checked. 262be691f3bSpatrick The order of checks is the order of the checks in the 263be691f3bSpatrick list. The number of checks has to match the number of 264be691f3bSpatrick children. 265*f6aab3d8Srobert :param dereference: A ValueCheck for the SBValue returned by the 266*f6aab3d8Srobert `Dereference` function. 267be691f3bSpatrick """ 268be691f3bSpatrick self.expect_name = name 269be691f3bSpatrick self.expect_value = value 270be691f3bSpatrick self.expect_type = type 271be691f3bSpatrick self.expect_summary = summary 272be691f3bSpatrick self.children = children 273*f6aab3d8Srobert self.dereference = dereference 274be691f3bSpatrick 275be691f3bSpatrick def check_value(self, test_base, val, error_msg=None): 276be691f3bSpatrick """ 277be691f3bSpatrick Checks that the given value matches the currently set properties 278be691f3bSpatrick of this ValueCheck. If a match failed, the given TestBase will 279be691f3bSpatrick be used to emit an error. A custom error message can be specified 280be691f3bSpatrick that will be used to describe failed check for this SBValue (but 281be691f3bSpatrick not errors in the child values). 282be691f3bSpatrick """ 283be691f3bSpatrick 284be691f3bSpatrick this_error_msg = error_msg if error_msg else "" 285be691f3bSpatrick this_error_msg += "\nChecking SBValue: " + str(val) 286be691f3bSpatrick 287be691f3bSpatrick test_base.assertSuccess(val.GetError()) 288be691f3bSpatrick 289*f6aab3d8Srobert # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type. 290*f6aab3d8Srobert pattern_type = type(re.compile('')) 291*f6aab3d8Srobert 292be691f3bSpatrick if self.expect_name: 293be691f3bSpatrick test_base.assertEqual(self.expect_name, val.GetName(), 294be691f3bSpatrick this_error_msg) 295be691f3bSpatrick if self.expect_value: 296*f6aab3d8Srobert if isinstance(self.expect_value, pattern_type): 297*f6aab3d8Srobert test_base.assertRegex(val.GetValue(), self.expect_value, 298*f6aab3d8Srobert this_error_msg) 299*f6aab3d8Srobert else: 300be691f3bSpatrick test_base.assertEqual(self.expect_value, val.GetValue(), 301be691f3bSpatrick this_error_msg) 302be691f3bSpatrick if self.expect_type: 303be691f3bSpatrick test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(), 304be691f3bSpatrick this_error_msg) 305be691f3bSpatrick if self.expect_summary: 306*f6aab3d8Srobert if isinstance(self.expect_summary, pattern_type): 307*f6aab3d8Srobert test_base.assertRegex(val.GetSummary(), self.expect_summary, 308*f6aab3d8Srobert this_error_msg) 309*f6aab3d8Srobert else: 310be691f3bSpatrick test_base.assertEqual(self.expect_summary, val.GetSummary(), 311be691f3bSpatrick this_error_msg) 312be691f3bSpatrick if self.children is not None: 313be691f3bSpatrick self.check_value_children(test_base, val, error_msg) 314be691f3bSpatrick 315*f6aab3d8Srobert if self.dereference is not None: 316*f6aab3d8Srobert self.dereference.check_value(test_base, val.Dereference(), error_msg) 317*f6aab3d8Srobert 318be691f3bSpatrick def check_value_children(self, test_base, val, error_msg=None): 319be691f3bSpatrick """ 320be691f3bSpatrick Checks that the children of a SBValue match a certain structure and 321be691f3bSpatrick have certain properties. 322be691f3bSpatrick 323be691f3bSpatrick :param test_base: The current test's TestBase object. 324be691f3bSpatrick :param val: The SBValue to check. 325be691f3bSpatrick """ 326be691f3bSpatrick 327be691f3bSpatrick this_error_msg = error_msg if error_msg else "" 328be691f3bSpatrick this_error_msg += "\nChecking SBValue: " + str(val) 329be691f3bSpatrick 330be691f3bSpatrick test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg) 331be691f3bSpatrick 332be691f3bSpatrick for i in range(0, val.GetNumChildren()): 333be691f3bSpatrick expected_child = self.children[i] 334be691f3bSpatrick actual_child = val.GetChildAtIndex(i) 335*f6aab3d8Srobert child_error = "Checking child with index " + str(i) + ":\n" + error_msg 336*f6aab3d8Srobert expected_child.check_value(test_base, actual_child, child_error) 337061da546Spatrick 338*f6aab3d8Srobertclass recording(io.StringIO): 339061da546Spatrick """ 340061da546Spatrick A nice little context manager for recording the debugger interactions into 341061da546Spatrick our session object. If trace flag is ON, it also emits the interactions 342061da546Spatrick into the stderr. 343061da546Spatrick """ 344061da546Spatrick 345061da546Spatrick def __init__(self, test, trace): 346*f6aab3d8Srobert """Create a io.StringIO instance; record the session obj and trace flag.""" 347*f6aab3d8Srobert io.StringIO.__init__(self) 348061da546Spatrick # The test might not have undergone the 'setUp(self)' phase yet, so that 349061da546Spatrick # the attribute 'session' might not even exist yet. 350061da546Spatrick self.session = getattr(test, "session", None) if test else None 351061da546Spatrick self.trace = trace 352061da546Spatrick 353061da546Spatrick def __enter__(self): 354061da546Spatrick """ 355061da546Spatrick Context management protocol on entry to the body of the with statement. 356*f6aab3d8Srobert Just return the io.StringIO object. 357061da546Spatrick """ 358061da546Spatrick return self 359061da546Spatrick 360061da546Spatrick def __exit__(self, type, value, tb): 361061da546Spatrick """ 362061da546Spatrick Context management protocol on exit from the body of the with statement. 363061da546Spatrick If trace is ON, it emits the recordings into stderr. Always add the 364*f6aab3d8Srobert recordings to our session object. And close the io.StringIO object, too. 365061da546Spatrick """ 366061da546Spatrick if self.trace: 367061da546Spatrick print(self.getvalue(), file=sys.stderr) 368061da546Spatrick if self.session: 369061da546Spatrick print(self.getvalue(), file=self.session) 370061da546Spatrick self.close() 371061da546Spatrick 372061da546Spatrick 373*f6aab3d8Srobertclass _BaseProcess(object, metaclass=abc.ABCMeta): 374061da546Spatrick 375061da546Spatrick @abc.abstractproperty 376061da546Spatrick def pid(self): 377061da546Spatrick """Returns process PID if has been launched already.""" 378061da546Spatrick 379061da546Spatrick @abc.abstractmethod 380*f6aab3d8Srobert def launch(self, executable, args, extra_env): 381061da546Spatrick """Launches new process with given executable and args.""" 382061da546Spatrick 383061da546Spatrick @abc.abstractmethod 384061da546Spatrick def terminate(self): 385061da546Spatrick """Terminates previously launched process..""" 386061da546Spatrick 387061da546Spatrick 388061da546Spatrickclass _LocalProcess(_BaseProcess): 389061da546Spatrick 390061da546Spatrick def __init__(self, trace_on): 391061da546Spatrick self._proc = None 392061da546Spatrick self._trace_on = trace_on 393061da546Spatrick self._delayafterterminate = 0.1 394061da546Spatrick 395061da546Spatrick @property 396061da546Spatrick def pid(self): 397061da546Spatrick return self._proc.pid 398061da546Spatrick 399*f6aab3d8Srobert def launch(self, executable, args, extra_env): 400*f6aab3d8Srobert env=None 401*f6aab3d8Srobert if extra_env: 402*f6aab3d8Srobert env = dict(os.environ) 403*f6aab3d8Srobert env.update([kv.split("=", 1) for kv in extra_env]) 404*f6aab3d8Srobert 405061da546Spatrick self._proc = Popen( 406061da546Spatrick [executable] + args, 407061da546Spatrick stdout=open( 408061da546Spatrick os.devnull) if not self._trace_on else None, 409be691f3bSpatrick stdin=PIPE, 410*f6aab3d8Srobert env=env) 411061da546Spatrick 412061da546Spatrick def terminate(self): 413061da546Spatrick if self._proc.poll() is None: 414061da546Spatrick # Terminate _proc like it does the pexpect 415061da546Spatrick signals_to_try = [ 416061da546Spatrick sig for sig in [ 417061da546Spatrick 'SIGHUP', 418061da546Spatrick 'SIGCONT', 419061da546Spatrick 'SIGINT'] if sig in dir(signal)] 420061da546Spatrick for sig in signals_to_try: 421061da546Spatrick try: 422061da546Spatrick self._proc.send_signal(getattr(signal, sig)) 423061da546Spatrick time.sleep(self._delayafterterminate) 424061da546Spatrick if self._proc.poll() is not None: 425061da546Spatrick return 426061da546Spatrick except ValueError: 427061da546Spatrick pass # Windows says SIGINT is not a valid signal to send 428061da546Spatrick self._proc.terminate() 429061da546Spatrick time.sleep(self._delayafterterminate) 430061da546Spatrick if self._proc.poll() is not None: 431061da546Spatrick return 432061da546Spatrick self._proc.kill() 433061da546Spatrick time.sleep(self._delayafterterminate) 434061da546Spatrick 435061da546Spatrick def poll(self): 436061da546Spatrick return self._proc.poll() 437061da546Spatrick 438*f6aab3d8Srobert def wait(self, timeout=None): 439*f6aab3d8Srobert return self._proc.wait(timeout) 440*f6aab3d8Srobert 441061da546Spatrick 442061da546Spatrickclass _RemoteProcess(_BaseProcess): 443061da546Spatrick 444061da546Spatrick def __init__(self, install_remote): 445061da546Spatrick self._pid = None 446061da546Spatrick self._install_remote = install_remote 447061da546Spatrick 448061da546Spatrick @property 449061da546Spatrick def pid(self): 450061da546Spatrick return self._pid 451061da546Spatrick 452*f6aab3d8Srobert def launch(self, executable, args, extra_env): 453061da546Spatrick if self._install_remote: 454061da546Spatrick src_path = executable 455061da546Spatrick dst_path = lldbutil.join_remote_paths( 456061da546Spatrick lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable)) 457061da546Spatrick 458061da546Spatrick dst_file_spec = lldb.SBFileSpec(dst_path, False) 459061da546Spatrick err = lldb.remote_platform.Install( 460061da546Spatrick lldb.SBFileSpec(src_path, True), dst_file_spec) 461061da546Spatrick if err.Fail(): 462061da546Spatrick raise Exception( 463061da546Spatrick "remote_platform.Install('%s', '%s') failed: %s" % 464061da546Spatrick (src_path, dst_path, err)) 465061da546Spatrick else: 466061da546Spatrick dst_path = executable 467061da546Spatrick dst_file_spec = lldb.SBFileSpec(executable, False) 468061da546Spatrick 469061da546Spatrick launch_info = lldb.SBLaunchInfo(args) 470061da546Spatrick launch_info.SetExecutableFile(dst_file_spec, True) 471061da546Spatrick launch_info.SetWorkingDirectory( 472061da546Spatrick lldb.remote_platform.GetWorkingDirectory()) 473061da546Spatrick 474061da546Spatrick # Redirect stdout and stderr to /dev/null 475061da546Spatrick launch_info.AddSuppressFileAction(1, False, True) 476061da546Spatrick launch_info.AddSuppressFileAction(2, False, True) 477061da546Spatrick 478*f6aab3d8Srobert if extra_env: 479*f6aab3d8Srobert launch_info.SetEnvironmentEntries(extra_env, True) 480*f6aab3d8Srobert 481061da546Spatrick err = lldb.remote_platform.Launch(launch_info) 482061da546Spatrick if err.Fail(): 483061da546Spatrick raise Exception( 484061da546Spatrick "remote_platform.Launch('%s', '%s') failed: %s" % 485061da546Spatrick (dst_path, args, err)) 486061da546Spatrick self._pid = launch_info.GetProcessID() 487061da546Spatrick 488061da546Spatrick def terminate(self): 489061da546Spatrick lldb.remote_platform.Kill(self._pid) 490061da546Spatrick 491061da546Spatrickdef getsource_if_available(obj): 492061da546Spatrick """ 493061da546Spatrick Return the text of the source code for an object if available. Otherwise, 494061da546Spatrick a print representation is returned. 495061da546Spatrick """ 496061da546Spatrick import inspect 497061da546Spatrick try: 498061da546Spatrick return inspect.getsource(obj) 499061da546Spatrick except: 500061da546Spatrick return repr(obj) 501061da546Spatrick 502061da546Spatrick 503061da546Spatrickdef builder_module(): 504be691f3bSpatrick return get_builder(sys.platform) 505061da546Spatrick 506061da546Spatrick 507061da546Spatrickclass Base(unittest2.TestCase): 508061da546Spatrick """ 509061da546Spatrick Abstract base for performing lldb (see TestBase) or other generic tests (see 510061da546Spatrick BenchBase for one example). lldbtest.Base works with the test driver to 511061da546Spatrick accomplish things. 512061da546Spatrick 513061da546Spatrick """ 514061da546Spatrick 515061da546Spatrick # The concrete subclass should override this attribute. 516061da546Spatrick mydir = None 517061da546Spatrick 518061da546Spatrick # Keep track of the old current working directory. 519061da546Spatrick oldcwd = None 520061da546Spatrick 521061da546Spatrick @staticmethod 522061da546Spatrick def compute_mydir(test_file): 523061da546Spatrick '''Subclasses should call this function to correctly calculate the 524061da546Spatrick required "mydir" attribute as follows: 525061da546Spatrick 526061da546Spatrick mydir = TestBase.compute_mydir(__file__) 527061da546Spatrick ''' 528061da546Spatrick # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir 529be691f3bSpatrick lldb_test_src = configuration.test_src_root 530be691f3bSpatrick if not test_file.startswith(lldb_test_src): 531be691f3bSpatrick raise Exception( 532be691f3bSpatrick "Test file '%s' must reside within lldb_test_src " 533be691f3bSpatrick "(which is '%s')." % (test_file, lldb_test_src)) 534be691f3bSpatrick return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src)) 535061da546Spatrick 536061da546Spatrick def TraceOn(self): 537061da546Spatrick """Returns True if we are in trace mode (tracing detailed test execution).""" 538061da546Spatrick return traceAlways 539061da546Spatrick 540dda28197Spatrick def trace(self, *args,**kwargs): 541dda28197Spatrick with recording(self, self.TraceOn()) as sbuf: 542dda28197Spatrick print(*args, file=sbuf, **kwargs) 543dda28197Spatrick 544061da546Spatrick @classmethod 545061da546Spatrick def setUpClass(cls): 546061da546Spatrick """ 547061da546Spatrick Python unittest framework class setup fixture. 548061da546Spatrick Do current directory manipulation. 549061da546Spatrick """ 550061da546Spatrick # Fail fast if 'mydir' attribute is not overridden. 551*f6aab3d8Srobert if not cls.mydir: 552*f6aab3d8Srobert cls.mydir = Base.compute_mydir(sys.modules[cls.__module__].__file__) 553*f6aab3d8Srobert if not cls.mydir: 554061da546Spatrick raise Exception("Subclasses must override the 'mydir' attribute.") 555061da546Spatrick 556061da546Spatrick # Save old working directory. 557061da546Spatrick cls.oldcwd = os.getcwd() 558061da546Spatrick 559be691f3bSpatrick full_dir = os.path.join(configuration.test_src_root, cls.mydir) 560061da546Spatrick if traceAlways: 561061da546Spatrick print("Change dir to:", full_dir, file=sys.stderr) 562061da546Spatrick os.chdir(full_dir) 563dda28197Spatrick lldb.SBReproducer.SetWorkingDirectory(full_dir) 564061da546Spatrick 565061da546Spatrick # Set platform context. 566061da546Spatrick cls.platformContext = lldbplatformutil.createPlatformContext() 567061da546Spatrick 568061da546Spatrick @classmethod 569061da546Spatrick def tearDownClass(cls): 570061da546Spatrick """ 571061da546Spatrick Python unittest framework class teardown fixture. 572061da546Spatrick Do class-wide cleanup. 573061da546Spatrick """ 574061da546Spatrick 575061da546Spatrick if doCleanup: 576061da546Spatrick # First, let's do the platform-specific cleanup. 577061da546Spatrick module = builder_module() 578061da546Spatrick module.cleanup() 579061da546Spatrick 580061da546Spatrick # Subclass might have specific cleanup function defined. 581061da546Spatrick if getattr(cls, "classCleanup", None): 582061da546Spatrick if traceAlways: 583061da546Spatrick print( 584061da546Spatrick "Call class-specific cleanup function for class:", 585061da546Spatrick cls, 586061da546Spatrick file=sys.stderr) 587061da546Spatrick try: 588061da546Spatrick cls.classCleanup() 589061da546Spatrick except: 590061da546Spatrick exc_type, exc_value, exc_tb = sys.exc_info() 591061da546Spatrick traceback.print_exception(exc_type, exc_value, exc_tb) 592061da546Spatrick 593061da546Spatrick # Restore old working directory. 594061da546Spatrick if traceAlways: 595061da546Spatrick print("Restore dir to:", cls.oldcwd, file=sys.stderr) 596061da546Spatrick os.chdir(cls.oldcwd) 597061da546Spatrick 598061da546Spatrick def enableLogChannelsForCurrentTest(self): 599061da546Spatrick if len(lldbtest_config.channels) == 0: 600061da546Spatrick return 601061da546Spatrick 602061da546Spatrick # if debug channels are specified in lldbtest_config.channels, 603061da546Spatrick # create a new set of log files for every test 604061da546Spatrick log_basename = self.getLogBasenameForCurrentTest() 605061da546Spatrick 606061da546Spatrick # confirm that the file is writeable 607061da546Spatrick host_log_path = "{}-host.log".format(log_basename) 608061da546Spatrick open(host_log_path, 'w').close() 609dda28197Spatrick self.log_files.append(host_log_path) 610061da546Spatrick 611061da546Spatrick log_enable = "log enable -Tpn -f {} ".format(host_log_path) 612061da546Spatrick for channel_with_categories in lldbtest_config.channels: 613061da546Spatrick channel_then_categories = channel_with_categories.split(' ', 1) 614061da546Spatrick channel = channel_then_categories[0] 615061da546Spatrick if len(channel_then_categories) > 1: 616061da546Spatrick categories = channel_then_categories[1] 617061da546Spatrick else: 618061da546Spatrick categories = "default" 619061da546Spatrick 620061da546Spatrick if channel == "gdb-remote" and lldb.remote_platform is None: 621061da546Spatrick # communicate gdb-remote categories to debugserver 622061da546Spatrick os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories 623061da546Spatrick 624061da546Spatrick self.ci.HandleCommand( 625061da546Spatrick log_enable + channel_with_categories, self.res) 626061da546Spatrick if not self.res.Succeeded(): 627061da546Spatrick raise Exception( 628061da546Spatrick 'log enable failed (check LLDB_LOG_OPTION env variable)') 629061da546Spatrick 630061da546Spatrick # Communicate log path name to debugserver & lldb-server 631061da546Spatrick # For remote debugging, these variables need to be set when starting the platform 632061da546Spatrick # instance. 633061da546Spatrick if lldb.remote_platform is None: 634061da546Spatrick server_log_path = "{}-server.log".format(log_basename) 635061da546Spatrick open(server_log_path, 'w').close() 636dda28197Spatrick self.log_files.append(server_log_path) 637061da546Spatrick os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path 638061da546Spatrick 639061da546Spatrick # Communicate channels to lldb-server 640061da546Spatrick os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join( 641061da546Spatrick lldbtest_config.channels) 642061da546Spatrick 643061da546Spatrick self.addTearDownHook(self.disableLogChannelsForCurrentTest) 644061da546Spatrick 645061da546Spatrick def disableLogChannelsForCurrentTest(self): 646061da546Spatrick # close all log files that we opened 647061da546Spatrick for channel_and_categories in lldbtest_config.channels: 648061da546Spatrick # channel format - <channel-name> [<category0> [<category1> ...]] 649061da546Spatrick channel = channel_and_categories.split(' ', 1)[0] 650061da546Spatrick self.ci.HandleCommand("log disable " + channel, self.res) 651061da546Spatrick if not self.res.Succeeded(): 652061da546Spatrick raise Exception( 653061da546Spatrick 'log disable failed (check LLDB_LOG_OPTION env variable)') 654061da546Spatrick 655061da546Spatrick # Retrieve the server log (if any) from the remote system. It is assumed the server log 656061da546Spatrick # is writing to the "server.log" file in the current test directory. This can be 657061da546Spatrick # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote 658dda28197Spatrick # platform. 659061da546Spatrick if lldb.remote_platform: 660dda28197Spatrick server_log_path = self.getLogBasenameForCurrentTest() + "-server.log" 661dda28197Spatrick if lldb.remote_platform.Get( 662dda28197Spatrick lldb.SBFileSpec("server.log"), 663dda28197Spatrick lldb.SBFileSpec(server_log_path)).Success(): 664dda28197Spatrick self.log_files.append(server_log_path) 665061da546Spatrick 666061da546Spatrick def setPlatformWorkingDir(self): 667061da546Spatrick if not lldb.remote_platform or not configuration.lldb_platform_working_dir: 668061da546Spatrick return 669061da546Spatrick 670061da546Spatrick components = self.mydir.split(os.path.sep) + [str(self.test_number), self.getBuildDirBasename()] 671061da546Spatrick remote_test_dir = configuration.lldb_platform_working_dir 672061da546Spatrick for c in components: 673061da546Spatrick remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c) 674061da546Spatrick error = lldb.remote_platform.MakeDirectory( 675061da546Spatrick remote_test_dir, 448) # 448 = 0o700 676061da546Spatrick if error.Fail(): 677061da546Spatrick raise Exception("making remote directory '%s': %s" % ( 678061da546Spatrick remote_test_dir, error)) 679061da546Spatrick 680061da546Spatrick lldb.remote_platform.SetWorkingDirectory(remote_test_dir) 681061da546Spatrick 682061da546Spatrick # This function removes all files from the current working directory while leaving 683dda28197Spatrick # the directories in place. The cleanup is required to reduce the disk space required 684061da546Spatrick # by the test suite while leaving the directories untouched is neccessary because 685061da546Spatrick # sub-directories might belong to an other test 686061da546Spatrick def clean_working_directory(): 687061da546Spatrick # TODO: Make it working on Windows when we need it for remote debugging support 688061da546Spatrick # TODO: Replace the heuristic to remove the files with a logic what collects the 689061da546Spatrick # list of files we have to remove during test runs. 690061da546Spatrick shell_cmd = lldb.SBPlatformShellCommand( 691061da546Spatrick "rm %s/*" % remote_test_dir) 692061da546Spatrick lldb.remote_platform.Run(shell_cmd) 693061da546Spatrick self.addTearDownHook(clean_working_directory) 694061da546Spatrick 695061da546Spatrick def getSourceDir(self): 696061da546Spatrick """Return the full path to the current test.""" 697be691f3bSpatrick return os.path.join(configuration.test_src_root, self.mydir) 698061da546Spatrick 699061da546Spatrick def getBuildDirBasename(self): 700061da546Spatrick return self.__class__.__module__ + "." + self.testMethodName 701061da546Spatrick 702061da546Spatrick def getBuildDir(self): 703061da546Spatrick """Return the full path to the current test.""" 704dda28197Spatrick return os.path.join(configuration.test_build_dir, self.mydir, 705061da546Spatrick self.getBuildDirBasename()) 706061da546Spatrick 707061da546Spatrick def makeBuildDir(self): 708061da546Spatrick """Create the test-specific working directory, deleting any previous 709061da546Spatrick contents.""" 710061da546Spatrick bdir = self.getBuildDir() 711061da546Spatrick if os.path.isdir(bdir): 712061da546Spatrick shutil.rmtree(bdir) 713061da546Spatrick lldbutil.mkdir_p(bdir) 714061da546Spatrick 715061da546Spatrick def getBuildArtifact(self, name="a.out"): 716061da546Spatrick """Return absolute path to an artifact in the test's build directory.""" 717061da546Spatrick return os.path.join(self.getBuildDir(), name) 718061da546Spatrick 719061da546Spatrick def getSourcePath(self, name): 720061da546Spatrick """Return absolute path to a file in the test's source directory.""" 721061da546Spatrick return os.path.join(self.getSourceDir(), name) 722061da546Spatrick 723061da546Spatrick @classmethod 724061da546Spatrick def setUpCommands(cls): 725061da546Spatrick commands = [ 726dda28197Spatrick # First of all, clear all settings to have clean state of global properties. 727dda28197Spatrick "settings clear -all", 728dda28197Spatrick 729061da546Spatrick # Disable Spotlight lookup. The testsuite creates 730061da546Spatrick # different binaries with the same UUID, because they only 731061da546Spatrick # differ in the debug info, which is not being hashed. 732061da546Spatrick "settings set symbols.enable-external-lookup false", 733061da546Spatrick 734be691f3bSpatrick # Inherit the TCC permissions from the inferior's parent. 735be691f3bSpatrick "settings set target.inherit-tcc true", 736be691f3bSpatrick 737be691f3bSpatrick # Kill rather than detach from the inferior if something goes wrong. 738be691f3bSpatrick "settings set target.detach-on-error false", 739be691f3bSpatrick 740dda28197Spatrick # Disable fix-its by default so that incorrect expressions in tests don't 741dda28197Spatrick # pass just because Clang thinks it has a fix-it. 742dda28197Spatrick "settings set target.auto-apply-fixits false", 743dda28197Spatrick 744061da546Spatrick # Testsuite runs in parallel and the host can have also other load. 745061da546Spatrick "settings set plugin.process.gdb-remote.packet-timeout 60", 746061da546Spatrick 747061da546Spatrick 'settings set symbols.clang-modules-cache-path "{}"'.format( 748061da546Spatrick configuration.lldb_module_cache_dir), 749061da546Spatrick "settings set use-color false", 750061da546Spatrick ] 751dda28197Spatrick 752dda28197Spatrick # Set any user-overridden settings. 753dda28197Spatrick for setting, value in configuration.settings: 754dda28197Spatrick commands.append('setting set %s %s'%(setting, value)) 755dda28197Spatrick 756061da546Spatrick # Make sure that a sanitizer LLDB's environment doesn't get passed on. 757061da546Spatrick if cls.platformContext and cls.platformContext.shlib_environment_var in os.environ: 758061da546Spatrick commands.append('settings set target.env-vars {}='.format( 759061da546Spatrick cls.platformContext.shlib_environment_var)) 760061da546Spatrick 761061da546Spatrick # Set environment variables for the inferior. 762061da546Spatrick if lldbtest_config.inferior_env: 763061da546Spatrick commands.append('settings set target.env-vars {}'.format( 764061da546Spatrick lldbtest_config.inferior_env)) 765061da546Spatrick return commands 766061da546Spatrick 767061da546Spatrick def setUp(self): 768061da546Spatrick """Fixture for unittest test case setup. 769061da546Spatrick 770061da546Spatrick It works with the test driver to conditionally skip tests and does other 771061da546Spatrick initializations.""" 772061da546Spatrick #import traceback 773061da546Spatrick # traceback.print_stack() 774061da546Spatrick 775061da546Spatrick if "LIBCXX_PATH" in os.environ: 776061da546Spatrick self.libcxxPath = os.environ["LIBCXX_PATH"] 777061da546Spatrick else: 778061da546Spatrick self.libcxxPath = None 779061da546Spatrick 780061da546Spatrick if "LLDBVSCODE_EXEC" in os.environ: 781061da546Spatrick self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"] 782061da546Spatrick else: 783061da546Spatrick self.lldbVSCodeExec = None 784061da546Spatrick 785061da546Spatrick self.lldbOption = " ".join( 786061da546Spatrick "-o '" + s + "'" for s in self.setUpCommands()) 787061da546Spatrick 788061da546Spatrick # If we spawn an lldb process for test (via pexpect), do not load the 789061da546Spatrick # init file unless told otherwise. 790061da546Spatrick if os.environ.get("NO_LLDBINIT") != "NO": 791061da546Spatrick self.lldbOption += " --no-lldbinit" 792061da546Spatrick 793061da546Spatrick # Assign the test method name to self.testMethodName. 794061da546Spatrick # 795061da546Spatrick # For an example of the use of this attribute, look at test/types dir. 796061da546Spatrick # There are a bunch of test cases under test/types and we don't want the 797061da546Spatrick # module cacheing subsystem to be confused with executable name "a.out" 798061da546Spatrick # used for all the test cases. 799061da546Spatrick self.testMethodName = self._testMethodName 800061da546Spatrick 801061da546Spatrick # This is for the case of directly spawning 'lldb'/'gdb' and interacting 802061da546Spatrick # with it using pexpect. 803061da546Spatrick self.child = None 804061da546Spatrick self.child_prompt = "(lldb) " 805061da546Spatrick # If the child is interacting with the embedded script interpreter, 806061da546Spatrick # there are two exits required during tear down, first to quit the 807061da546Spatrick # embedded script interpreter and second to quit the lldb command 808061da546Spatrick # interpreter. 809061da546Spatrick self.child_in_script_interpreter = False 810061da546Spatrick 811061da546Spatrick # These are for customized teardown cleanup. 812061da546Spatrick self.dict = None 813061da546Spatrick self.doTearDownCleanup = False 814061da546Spatrick # And in rare cases where there are multiple teardown cleanups. 815061da546Spatrick self.dicts = [] 816061da546Spatrick self.doTearDownCleanups = False 817061da546Spatrick 818061da546Spatrick # List of spawned subproces.Popen objects 819061da546Spatrick self.subprocesses = [] 820061da546Spatrick 821dda28197Spatrick # List of log files produced by the current test. 822dda28197Spatrick self.log_files = [] 823061da546Spatrick 824be691f3bSpatrick # Create the build directory. 825be691f3bSpatrick # The logs are stored in the build directory, so we have to create it 826be691f3bSpatrick # before creating the first log file. 827be691f3bSpatrick self.makeBuildDir() 828be691f3bSpatrick 829dda28197Spatrick session_file = self.getLogBasenameForCurrentTest()+".log" 830dda28197Spatrick self.log_files.append(session_file) 831dda28197Spatrick 832061da546Spatrick # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 833061da546Spatrick self.session = encoded_file.open(session_file, "utf-8", mode="w") 834061da546Spatrick 835061da546Spatrick # Optimistically set __errored__, __failed__, __expected__ to False 836061da546Spatrick # initially. If the test errored/failed, the session info 837061da546Spatrick # (self.session) is then dumped into a session specific file for 838061da546Spatrick # diagnosis. 839061da546Spatrick self.__cleanup_errored__ = False 840061da546Spatrick self.__errored__ = False 841061da546Spatrick self.__failed__ = False 842061da546Spatrick self.__expected__ = False 843061da546Spatrick # We are also interested in unexpected success. 844061da546Spatrick self.__unexpected__ = False 845061da546Spatrick # And skipped tests. 846061da546Spatrick self.__skipped__ = False 847061da546Spatrick 848061da546Spatrick # See addTearDownHook(self, hook) which allows the client to add a hook 849061da546Spatrick # function to be run during tearDown() time. 850061da546Spatrick self.hooks = [] 851061da546Spatrick 852061da546Spatrick # See HideStdout(self). 853061da546Spatrick self.sys_stdout_hidden = False 854061da546Spatrick 855061da546Spatrick if self.platformContext: 856061da546Spatrick # set environment variable names for finding shared libraries 857061da546Spatrick self.dylibPath = self.platformContext.shlib_environment_var 858061da546Spatrick 859dda28197Spatrick # Create the debugger instance. 860061da546Spatrick self.dbg = lldb.SBDebugger.Create() 861dda28197Spatrick # Copy selected platform from a global instance if it exists. 862dda28197Spatrick if lldb.selected_platform is not None: 863dda28197Spatrick self.dbg.SetSelectedPlatform(lldb.selected_platform) 864061da546Spatrick 865061da546Spatrick if not self.dbg: 866061da546Spatrick raise Exception('Invalid debugger instance') 867061da546Spatrick 868061da546Spatrick # Retrieve the associated command interpreter instance. 869061da546Spatrick self.ci = self.dbg.GetCommandInterpreter() 870061da546Spatrick if not self.ci: 871061da546Spatrick raise Exception('Could not get the command interpreter') 872061da546Spatrick 873061da546Spatrick # And the result object. 874061da546Spatrick self.res = lldb.SBCommandReturnObject() 875061da546Spatrick 876061da546Spatrick self.setPlatformWorkingDir() 877061da546Spatrick self.enableLogChannelsForCurrentTest() 878061da546Spatrick 879be691f3bSpatrick self.lib_lldb = None 880061da546Spatrick self.framework_dir = None 881061da546Spatrick self.darwinWithFramework = False 882be691f3bSpatrick 883be691f3bSpatrick if sys.platform.startswith("darwin") and configuration.lldb_framework_path: 884be691f3bSpatrick framework = configuration.lldb_framework_path 885be691f3bSpatrick lib = os.path.join(framework, 'LLDB') 886be691f3bSpatrick if os.path.exists(lib): 887be691f3bSpatrick self.framework_dir = os.path.dirname(framework) 888be691f3bSpatrick self.lib_lldb = lib 889be691f3bSpatrick self.darwinWithFramework = self.platformIsDarwin() 890061da546Spatrick 891061da546Spatrick def setAsync(self, value): 892061da546Spatrick """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 893061da546Spatrick old_async = self.dbg.GetAsync() 894061da546Spatrick self.dbg.SetAsync(value) 895061da546Spatrick self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 896061da546Spatrick 897061da546Spatrick def cleanupSubprocesses(self): 898be691f3bSpatrick # Terminate subprocesses in reverse order from how they were created. 899be691f3bSpatrick for p in reversed(self.subprocesses): 900061da546Spatrick p.terminate() 901061da546Spatrick del p 902061da546Spatrick del self.subprocesses[:] 903061da546Spatrick 904*f6aab3d8Srobert def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True): 905061da546Spatrick """ Creates a subprocess.Popen object with the specified executable and arguments, 906061da546Spatrick saves it in self.subprocesses, and returns the object. 907061da546Spatrick """ 908061da546Spatrick proc = _RemoteProcess( 909061da546Spatrick install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 910*f6aab3d8Srobert proc.launch(executable, args, extra_env=extra_env) 911061da546Spatrick self.subprocesses.append(proc) 912061da546Spatrick return proc 913061da546Spatrick 914061da546Spatrick def HideStdout(self): 915061da546Spatrick """Hide output to stdout from the user. 916061da546Spatrick 917061da546Spatrick During test execution, there might be cases where we don't want to show the 918061da546Spatrick standard output to the user. For example, 919061da546Spatrick 920061da546Spatrick self.runCmd(r'''sc print("\n\n\tHello!\n")''') 921061da546Spatrick 922061da546Spatrick tests whether command abbreviation for 'script' works or not. There is no 923061da546Spatrick need to show the 'Hello' output to the user as long as the 'script' command 924061da546Spatrick succeeds and we are not in TraceOn() mode (see the '-t' option). 925061da546Spatrick 926061da546Spatrick In this case, the test method calls self.HideStdout(self) to redirect the 927061da546Spatrick sys.stdout to a null device, and restores the sys.stdout upon teardown. 928061da546Spatrick 929061da546Spatrick Note that you should only call this method at most once during a test case 930061da546Spatrick execution. Any subsequent call has no effect at all.""" 931061da546Spatrick if self.sys_stdout_hidden: 932061da546Spatrick return 933061da546Spatrick 934061da546Spatrick self.sys_stdout_hidden = True 935061da546Spatrick old_stdout = sys.stdout 936061da546Spatrick sys.stdout = open(os.devnull, 'w') 937061da546Spatrick 938061da546Spatrick def restore_stdout(): 939061da546Spatrick sys.stdout = old_stdout 940061da546Spatrick self.addTearDownHook(restore_stdout) 941061da546Spatrick 942061da546Spatrick # ======================================================================= 943061da546Spatrick # Methods for customized teardown cleanups as well as execution of hooks. 944061da546Spatrick # ======================================================================= 945061da546Spatrick 946061da546Spatrick def setTearDownCleanup(self, dictionary=None): 947dda28197Spatrick """Register a cleanup action at tearDown() time with a dictionary""" 948061da546Spatrick self.dict = dictionary 949061da546Spatrick self.doTearDownCleanup = True 950061da546Spatrick 951061da546Spatrick def addTearDownCleanup(self, dictionary): 952dda28197Spatrick """Add a cleanup action at tearDown() time with a dictionary""" 953061da546Spatrick self.dicts.append(dictionary) 954061da546Spatrick self.doTearDownCleanups = True 955061da546Spatrick 956061da546Spatrick def addTearDownHook(self, hook): 957061da546Spatrick """ 958061da546Spatrick Add a function to be run during tearDown() time. 959061da546Spatrick 960061da546Spatrick Hooks are executed in a first come first serve manner. 961061da546Spatrick """ 962*f6aab3d8Srobert if callable(hook): 963061da546Spatrick with recording(self, traceAlways) as sbuf: 964061da546Spatrick print( 965061da546Spatrick "Adding tearDown hook:", 966061da546Spatrick getsource_if_available(hook), 967061da546Spatrick file=sbuf) 968061da546Spatrick self.hooks.append(hook) 969061da546Spatrick 970061da546Spatrick return self 971061da546Spatrick 972061da546Spatrick def deletePexpectChild(self): 973061da546Spatrick # This is for the case of directly spawning 'lldb' and interacting with it 974061da546Spatrick # using pexpect. 975061da546Spatrick if self.child and self.child.isalive(): 976061da546Spatrick import pexpect 977061da546Spatrick with recording(self, traceAlways) as sbuf: 978061da546Spatrick print("tearing down the child process....", file=sbuf) 979061da546Spatrick try: 980061da546Spatrick if self.child_in_script_interpreter: 981061da546Spatrick self.child.sendline('quit()') 982061da546Spatrick self.child.expect_exact(self.child_prompt) 983061da546Spatrick self.child.sendline( 984061da546Spatrick 'settings set interpreter.prompt-on-quit false') 985061da546Spatrick self.child.sendline('quit') 986061da546Spatrick self.child.expect(pexpect.EOF) 987061da546Spatrick except (ValueError, pexpect.ExceptionPexpect): 988061da546Spatrick # child is already terminated 989061da546Spatrick pass 990061da546Spatrick except OSError as exception: 991061da546Spatrick import errno 992061da546Spatrick if exception.errno != errno.EIO: 993061da546Spatrick # unexpected error 994061da546Spatrick raise 995061da546Spatrick # child is already terminated 996061da546Spatrick finally: 997061da546Spatrick # Give it one final blow to make sure the child is terminated. 998061da546Spatrick self.child.close() 999061da546Spatrick 1000061da546Spatrick def tearDown(self): 1001061da546Spatrick """Fixture for unittest test case teardown.""" 1002061da546Spatrick self.deletePexpectChild() 1003061da546Spatrick 1004061da546Spatrick # Check and run any hook functions. 1005061da546Spatrick for hook in reversed(self.hooks): 1006061da546Spatrick with recording(self, traceAlways) as sbuf: 1007061da546Spatrick print( 1008061da546Spatrick "Executing tearDown hook:", 1009061da546Spatrick getsource_if_available(hook), 1010061da546Spatrick file=sbuf) 1011061da546Spatrick if funcutils.requires_self(hook): 1012061da546Spatrick hook(self) 1013061da546Spatrick else: 1014061da546Spatrick hook() # try the plain call and hope it works 1015061da546Spatrick 1016061da546Spatrick del self.hooks 1017061da546Spatrick 1018061da546Spatrick # Perform registered teardown cleanup. 1019061da546Spatrick if doCleanup and self.doTearDownCleanup: 1020061da546Spatrick self.cleanup(dictionary=self.dict) 1021061da546Spatrick 1022061da546Spatrick # In rare cases where there are multiple teardown cleanups added. 1023061da546Spatrick if doCleanup and self.doTearDownCleanups: 1024061da546Spatrick if self.dicts: 1025061da546Spatrick for dict in reversed(self.dicts): 1026061da546Spatrick self.cleanup(dictionary=dict) 1027061da546Spatrick 1028dda28197Spatrick # Remove subprocesses created by the test. 1029dda28197Spatrick self.cleanupSubprocesses() 1030dda28197Spatrick 1031dda28197Spatrick # This must be the last statement, otherwise teardown hooks or other 1032dda28197Spatrick # lines might depend on this still being active. 1033dda28197Spatrick lldb.SBDebugger.Destroy(self.dbg) 1034dda28197Spatrick del self.dbg 1035dda28197Spatrick 1036be691f3bSpatrick # All modules should be orphaned now so that they can be cleared from 1037be691f3bSpatrick # the shared module cache. 1038be691f3bSpatrick lldb.SBModule.GarbageCollectAllocatedModules() 1039be691f3bSpatrick 1040be691f3bSpatrick # Assert that the global module cache is empty. 1041be691f3bSpatrick self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0) 1042be691f3bSpatrick 1043be691f3bSpatrick 1044061da546Spatrick # ========================================================= 1045061da546Spatrick # Various callbacks to allow introspection of test progress 1046061da546Spatrick # ========================================================= 1047061da546Spatrick 1048061da546Spatrick def markError(self): 1049061da546Spatrick """Callback invoked when an error (unexpected exception) errored.""" 1050061da546Spatrick self.__errored__ = True 1051061da546Spatrick with recording(self, False) as sbuf: 1052061da546Spatrick # False because there's no need to write "ERROR" to the stderr twice. 1053061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1054061da546Spatrick print("ERROR", file=sbuf) 1055061da546Spatrick 1056061da546Spatrick def markCleanupError(self): 1057061da546Spatrick """Callback invoked when an error occurs while a test is cleaning up.""" 1058061da546Spatrick self.__cleanup_errored__ = True 1059061da546Spatrick with recording(self, False) as sbuf: 1060061da546Spatrick # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1061061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1062061da546Spatrick print("CLEANUP_ERROR", file=sbuf) 1063061da546Spatrick 1064061da546Spatrick def markFailure(self): 1065061da546Spatrick """Callback invoked when a failure (test assertion failure) occurred.""" 1066061da546Spatrick self.__failed__ = True 1067061da546Spatrick with recording(self, False) as sbuf: 1068061da546Spatrick # False because there's no need to write "FAIL" to the stderr twice. 1069061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1070061da546Spatrick print("FAIL", file=sbuf) 1071061da546Spatrick 1072061da546Spatrick def markExpectedFailure(self, err, bugnumber): 1073061da546Spatrick """Callback invoked when an expected failure/error occurred.""" 1074061da546Spatrick self.__expected__ = True 1075061da546Spatrick with recording(self, False) as sbuf: 1076061da546Spatrick # False because there's no need to write "expected failure" to the 1077061da546Spatrick # stderr twice. 1078061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1079061da546Spatrick if bugnumber is None: 1080061da546Spatrick print("expected failure", file=sbuf) 1081061da546Spatrick else: 1082061da546Spatrick print( 1083061da546Spatrick "expected failure (problem id:" + str(bugnumber) + ")", 1084061da546Spatrick file=sbuf) 1085061da546Spatrick 1086061da546Spatrick def markSkippedTest(self): 1087061da546Spatrick """Callback invoked when a test is skipped.""" 1088061da546Spatrick self.__skipped__ = True 1089061da546Spatrick with recording(self, False) as sbuf: 1090061da546Spatrick # False because there's no need to write "skipped test" to the 1091061da546Spatrick # stderr twice. 1092061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1093061da546Spatrick print("skipped test", file=sbuf) 1094061da546Spatrick 1095061da546Spatrick def markUnexpectedSuccess(self, bugnumber): 1096061da546Spatrick """Callback invoked when an unexpected success occurred.""" 1097061da546Spatrick self.__unexpected__ = True 1098061da546Spatrick with recording(self, False) as sbuf: 1099061da546Spatrick # False because there's no need to write "unexpected success" to the 1100061da546Spatrick # stderr twice. 1101061da546Spatrick # Once by the Python unittest framework, and a second time by us. 1102061da546Spatrick if bugnumber is None: 1103061da546Spatrick print("unexpected success", file=sbuf) 1104061da546Spatrick else: 1105061da546Spatrick print( 1106061da546Spatrick "unexpected success (problem id:" + str(bugnumber) + ")", 1107061da546Spatrick file=sbuf) 1108061da546Spatrick 1109061da546Spatrick def getRerunArgs(self): 1110061da546Spatrick return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1111061da546Spatrick 1112be691f3bSpatrick def getLogBasenameForCurrentTest(self, prefix="Incomplete"): 1113061da546Spatrick """ 1114061da546Spatrick returns a partial path that can be used as the beginning of the name of multiple 1115061da546Spatrick log files pertaining to this test 1116061da546Spatrick """ 1117be691f3bSpatrick return os.path.join(self.getBuildDir(), prefix) 1118061da546Spatrick 1119061da546Spatrick def dumpSessionInfo(self): 1120061da546Spatrick """ 1121061da546Spatrick Dump the debugger interactions leading to a test error/failure. This 1122061da546Spatrick allows for more convenient postmortem analysis. 1123061da546Spatrick 1124061da546Spatrick See also LLDBTestResult (dotest.py) which is a singlton class derived 1125061da546Spatrick from TextTestResult and overwrites addError, addFailure, and 1126061da546Spatrick addExpectedFailure methods to allow us to to mark the test instance as 1127061da546Spatrick such. 1128061da546Spatrick """ 1129061da546Spatrick 1130061da546Spatrick # We are here because self.tearDown() detected that this test instance 1131061da546Spatrick # either errored or failed. The lldb.test_result singleton contains 1132dda28197Spatrick # two lists (errors and failures) which get populated by the unittest 1133061da546Spatrick # framework. Look over there for stack trace information. 1134061da546Spatrick # 1135061da546Spatrick # The lists contain 2-tuples of TestCase instances and strings holding 1136061da546Spatrick # formatted tracebacks. 1137061da546Spatrick # 1138061da546Spatrick # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1139061da546Spatrick 1140061da546Spatrick # output tracebacks into session 1141061da546Spatrick pairs = [] 1142061da546Spatrick if self.__errored__: 1143061da546Spatrick pairs = configuration.test_result.errors 1144061da546Spatrick prefix = 'Error' 1145061da546Spatrick elif self.__cleanup_errored__: 1146061da546Spatrick pairs = configuration.test_result.cleanup_errors 1147061da546Spatrick prefix = 'CleanupError' 1148061da546Spatrick elif self.__failed__: 1149061da546Spatrick pairs = configuration.test_result.failures 1150061da546Spatrick prefix = 'Failure' 1151061da546Spatrick elif self.__expected__: 1152061da546Spatrick pairs = configuration.test_result.expectedFailures 1153061da546Spatrick prefix = 'ExpectedFailure' 1154061da546Spatrick elif self.__skipped__: 1155061da546Spatrick prefix = 'SkippedTest' 1156061da546Spatrick elif self.__unexpected__: 1157061da546Spatrick prefix = 'UnexpectedSuccess' 1158061da546Spatrick else: 1159061da546Spatrick prefix = 'Success' 1160061da546Spatrick 1161061da546Spatrick if not self.__unexpected__ and not self.__skipped__: 1162061da546Spatrick for test, traceback in pairs: 1163061da546Spatrick if test is self: 1164061da546Spatrick print(traceback, file=self.session) 1165061da546Spatrick 1166061da546Spatrick import datetime 1167061da546Spatrick print( 1168061da546Spatrick "Session info generated @", 1169061da546Spatrick datetime.datetime.now().ctime(), 1170061da546Spatrick file=self.session) 1171061da546Spatrick self.session.close() 1172061da546Spatrick del self.session 1173061da546Spatrick 1174061da546Spatrick # process the log files 1175061da546Spatrick if prefix != 'Success' or lldbtest_config.log_success: 1176061da546Spatrick # keep all log files, rename them to include prefix 1177be691f3bSpatrick src_log_basename = self.getLogBasenameForCurrentTest() 1178061da546Spatrick dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1179dda28197Spatrick for src in self.log_files: 1180061da546Spatrick if os.path.isfile(src): 1181dda28197Spatrick dst = src.replace(src_log_basename, dst_log_basename) 1182061da546Spatrick if os.name == "nt" and os.path.isfile(dst): 1183061da546Spatrick # On Windows, renaming a -> b will throw an exception if 1184061da546Spatrick # b exists. On non-Windows platforms it silently 1185061da546Spatrick # replaces the destination. Ultimately this means that 1186061da546Spatrick # atomic renames are not guaranteed to be possible on 1187061da546Spatrick # Windows, but we need this to work anyway, so just 1188061da546Spatrick # remove the destination first if it already exists. 1189061da546Spatrick remove_file(dst) 1190061da546Spatrick 1191061da546Spatrick lldbutil.mkdir_p(os.path.dirname(dst)) 1192061da546Spatrick os.rename(src, dst) 1193061da546Spatrick else: 1194061da546Spatrick # success! (and we don't want log files) delete log files 1195dda28197Spatrick for log_file in self.log_files: 1196dda28197Spatrick if os.path.isfile(log_file): 1197061da546Spatrick remove_file(log_file) 1198061da546Spatrick 1199061da546Spatrick # ==================================================== 1200061da546Spatrick # Config. methods supported through a plugin interface 1201061da546Spatrick # (enables reading of the current test configuration) 1202061da546Spatrick # ==================================================== 1203061da546Spatrick 1204061da546Spatrick def isMIPS(self): 1205061da546Spatrick """Returns true if the architecture is MIPS.""" 1206061da546Spatrick arch = self.getArchitecture() 1207061da546Spatrick if re.match("mips", arch): 1208061da546Spatrick return True 1209061da546Spatrick return False 1210061da546Spatrick 1211061da546Spatrick def isPPC64le(self): 1212061da546Spatrick """Returns true if the architecture is PPC64LE.""" 1213061da546Spatrick arch = self.getArchitecture() 1214061da546Spatrick if re.match("powerpc64le", arch): 1215061da546Spatrick return True 1216061da546Spatrick return False 1217061da546Spatrick 1218be691f3bSpatrick def getCPUInfo(self): 1219be691f3bSpatrick triple = self.dbg.GetSelectedPlatform().GetTriple() 1220be691f3bSpatrick 1221be691f3bSpatrick # TODO other platforms, please implement this function 1222be691f3bSpatrick if not re.match(".*-.*-linux", triple): 1223be691f3bSpatrick return "" 1224be691f3bSpatrick 1225be691f3bSpatrick # Need to do something different for non-Linux/Android targets 1226be691f3bSpatrick cpuinfo_path = self.getBuildArtifact("cpuinfo") 1227be691f3bSpatrick if configuration.lldb_platform_name: 1228be691f3bSpatrick self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path) 1229be691f3bSpatrick else: 1230be691f3bSpatrick cpuinfo_path = "/proc/cpuinfo" 1231be691f3bSpatrick 1232be691f3bSpatrick try: 1233be691f3bSpatrick with open(cpuinfo_path, 'r') as f: 1234be691f3bSpatrick cpuinfo = f.read() 1235be691f3bSpatrick except: 1236be691f3bSpatrick return "" 1237be691f3bSpatrick 1238be691f3bSpatrick return cpuinfo 1239be691f3bSpatrick 1240be691f3bSpatrick def isAArch64(self): 1241be691f3bSpatrick """Returns true if the architecture is AArch64.""" 1242*f6aab3d8Srobert arch = self.getArchitecture().lower() 1243*f6aab3d8Srobert return arch in ["aarch64", "arm64", "arm64e"] 1244be691f3bSpatrick 1245be691f3bSpatrick def isAArch64SVE(self): 1246be691f3bSpatrick return self.isAArch64() and "sve" in self.getCPUInfo() 1247be691f3bSpatrick 1248be691f3bSpatrick def isAArch64MTE(self): 1249be691f3bSpatrick return self.isAArch64() and "mte" in self.getCPUInfo() 1250be691f3bSpatrick 1251be691f3bSpatrick def isAArch64PAuth(self): 1252*f6aab3d8Srobert if self.getArchitecture() == "arm64e": 1253*f6aab3d8Srobert return True 1254be691f3bSpatrick return self.isAArch64() and "paca" in self.getCPUInfo() 1255be691f3bSpatrick 1256061da546Spatrick def getArchitecture(self): 1257061da546Spatrick """Returns the architecture in effect the test suite is running with.""" 1258061da546Spatrick module = builder_module() 1259061da546Spatrick arch = module.getArchitecture() 1260061da546Spatrick if arch == 'amd64': 1261061da546Spatrick arch = 'x86_64' 1262dda28197Spatrick if arch in ['armv7l', 'armv8l'] : 1263dda28197Spatrick arch = 'arm' 1264061da546Spatrick return arch 1265061da546Spatrick 1266061da546Spatrick def getLldbArchitecture(self): 1267061da546Spatrick """Returns the architecture of the lldb binary.""" 1268061da546Spatrick if not hasattr(self, 'lldbArchitecture'): 1269061da546Spatrick 1270*f6aab3d8Srobert # These two target settings prevent lldb from doing setup that does 1271*f6aab3d8Srobert # nothing but slow down the end goal of printing the architecture. 1272061da546Spatrick command = [ 1273061da546Spatrick lldbtest_config.lldbExec, 1274*f6aab3d8Srobert "-x", 1275*f6aab3d8Srobert "-b", 1276*f6aab3d8Srobert "-o", "settings set target.preload-symbols false", 1277*f6aab3d8Srobert "-o", "settings set target.load-script-from-symbol-file false", 1278*f6aab3d8Srobert "-o", "file " + lldbtest_config.lldbExec, 1279061da546Spatrick ] 1280061da546Spatrick 1281061da546Spatrick output = check_output(command) 1282*f6aab3d8Srobert str = output.decode() 1283061da546Spatrick 1284061da546Spatrick for line in str.splitlines(): 1285061da546Spatrick m = re.search( 1286*f6aab3d8Srobert r"Current executable set to '.*' \((.*)\)\.", line) 1287061da546Spatrick if m: 1288061da546Spatrick self.lldbArchitecture = m.group(1) 1289061da546Spatrick break 1290061da546Spatrick 1291061da546Spatrick return self.lldbArchitecture 1292061da546Spatrick 1293061da546Spatrick def getCompiler(self): 1294061da546Spatrick """Returns the compiler in effect the test suite is running with.""" 1295061da546Spatrick module = builder_module() 1296061da546Spatrick return module.getCompiler() 1297061da546Spatrick 1298061da546Spatrick def getCompilerBinary(self): 1299061da546Spatrick """Returns the compiler binary the test suite is running with.""" 1300061da546Spatrick return self.getCompiler().split()[0] 1301061da546Spatrick 1302061da546Spatrick def getCompilerVersion(self): 1303061da546Spatrick """ Returns a string that represents the compiler version. 1304061da546Spatrick Supports: llvm, clang. 1305061da546Spatrick """ 1306061da546Spatrick compiler = self.getCompilerBinary() 1307*f6aab3d8Srobert version_output = check_output([compiler, "--version"], errors="replace") 1308*f6aab3d8Srobert m = re.search('version ([0-9.]+)', version_output) 1309061da546Spatrick if m: 1310be691f3bSpatrick return m.group(1) 1311be691f3bSpatrick return 'unknown' 1312061da546Spatrick 1313061da546Spatrick def getDwarfVersion(self): 1314061da546Spatrick """ Returns the dwarf version generated by clang or '0'. """ 1315061da546Spatrick if configuration.dwarf_version: 1316061da546Spatrick return str(configuration.dwarf_version) 1317061da546Spatrick if 'clang' in self.getCompiler(): 1318061da546Spatrick try: 1319*f6aab3d8Srobert triple = builder_module().getTriple(self.getArchitecture()) 1320*f6aab3d8Srobert target = ['-target', triple] if triple else [] 1321061da546Spatrick driver_output = check_output( 1322*f6aab3d8Srobert [self.getCompiler()] + target + '-g -c -x c - -o - -###'.split(), 1323061da546Spatrick stderr=STDOUT) 1324061da546Spatrick driver_output = driver_output.decode("utf-8") 1325061da546Spatrick for line in driver_output.split(os.linesep): 1326061da546Spatrick m = re.search('dwarf-version=([0-9])', line) 1327061da546Spatrick if m: 1328061da546Spatrick return m.group(1) 1329*f6aab3d8Srobert except CalledProcessError: 1330*f6aab3d8Srobert pass 1331061da546Spatrick return '0' 1332061da546Spatrick 1333061da546Spatrick def platformIsDarwin(self): 1334061da546Spatrick """Returns true if the OS triple for the selected platform is any valid apple OS""" 1335061da546Spatrick return lldbplatformutil.platformIsDarwin() 1336061da546Spatrick 1337061da546Spatrick def hasDarwinFramework(self): 1338061da546Spatrick return self.darwinWithFramework 1339061da546Spatrick 1340061da546Spatrick def getPlatform(self): 1341061da546Spatrick """Returns the target platform the test suite is running on.""" 1342061da546Spatrick return lldbplatformutil.getPlatform() 1343061da546Spatrick 1344061da546Spatrick def isIntelCompiler(self): 1345061da546Spatrick """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1346061da546Spatrick return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1347061da546Spatrick 1348061da546Spatrick def expectedCompilerVersion(self, compiler_version): 1349061da546Spatrick """Returns True iff compiler_version[1] matches the current compiler version. 1350061da546Spatrick Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1351061da546Spatrick Any operator other than the following defaults to an equality test: 1352061da546Spatrick '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1353be691f3bSpatrick 1354be691f3bSpatrick If the current compiler version cannot be determined, we assume it is close to the top 1355be691f3bSpatrick of trunk, so any less-than or equal-to comparisons will return False, and any 1356be691f3bSpatrick greater-than or not-equal-to comparisons will return True. 1357061da546Spatrick """ 1358be691f3bSpatrick if compiler_version is None: 1359061da546Spatrick return True 1360061da546Spatrick operator = str(compiler_version[0]) 1361061da546Spatrick version = compiler_version[1] 1362061da546Spatrick 1363be691f3bSpatrick if version is None: 1364061da546Spatrick return True 1365be691f3bSpatrick 1366be691f3bSpatrick test_compiler_version = self.getCompilerVersion() 1367be691f3bSpatrick if test_compiler_version == 'unknown': 1368be691f3bSpatrick # Assume the compiler version is at or near the top of trunk. 1369be691f3bSpatrick return operator in ['>', '>=', '!', '!=', 'not'] 1370be691f3bSpatrick 1371be691f3bSpatrick if operator == '>': 1372be691f3bSpatrick return LooseVersion(test_compiler_version) > LooseVersion(version) 1373be691f3bSpatrick if operator == '>=' or operator == '=>': 1374be691f3bSpatrick return LooseVersion(test_compiler_version) >= LooseVersion(version) 1375be691f3bSpatrick if operator == '<': 1376be691f3bSpatrick return LooseVersion(test_compiler_version) < LooseVersion(version) 1377be691f3bSpatrick if operator == '<=' or operator == '=<': 1378be691f3bSpatrick return LooseVersion(test_compiler_version) <= LooseVersion(version) 1379be691f3bSpatrick if operator == '!=' or operator == '!' or operator == 'not': 1380be691f3bSpatrick return str(version) not in str(test_compiler_version) 1381be691f3bSpatrick return str(version) in str(test_compiler_version) 1382061da546Spatrick 1383061da546Spatrick def expectedCompiler(self, compilers): 1384061da546Spatrick """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1385061da546Spatrick if (compilers is None): 1386061da546Spatrick return True 1387061da546Spatrick 1388061da546Spatrick for compiler in compilers: 1389061da546Spatrick if compiler in self.getCompiler(): 1390061da546Spatrick return True 1391061da546Spatrick 1392061da546Spatrick return False 1393061da546Spatrick 1394061da546Spatrick def expectedArch(self, archs): 1395061da546Spatrick """Returns True iff any element of archs is a sub-string of the current architecture.""" 1396061da546Spatrick if (archs is None): 1397061da546Spatrick return True 1398061da546Spatrick 1399061da546Spatrick for arch in archs: 1400061da546Spatrick if arch in self.getArchitecture(): 1401061da546Spatrick return True 1402061da546Spatrick 1403061da546Spatrick return False 1404061da546Spatrick 1405061da546Spatrick def getRunOptions(self): 1406061da546Spatrick """Command line option for -A and -C to run this test again, called from 1407061da546Spatrick self.dumpSessionInfo().""" 1408061da546Spatrick arch = self.getArchitecture() 1409061da546Spatrick comp = self.getCompiler() 1410061da546Spatrick option_str = "" 1411061da546Spatrick if arch: 1412061da546Spatrick option_str = "-A " + arch 1413061da546Spatrick if comp: 1414061da546Spatrick option_str += " -C " + comp 1415061da546Spatrick return option_str 1416061da546Spatrick 1417061da546Spatrick def getDebugInfo(self): 1418061da546Spatrick method = getattr(self, self.testMethodName) 1419061da546Spatrick return getattr(method, "debug_info", None) 1420061da546Spatrick 1421*f6aab3d8Srobert def build( 1422*f6aab3d8Srobert self, 1423*f6aab3d8Srobert debug_info=None, 1424*f6aab3d8Srobert architecture=None, 1425*f6aab3d8Srobert compiler=None, 1426*f6aab3d8Srobert dictionary=None, 1427*f6aab3d8Srobert make_targets=None): 1428*f6aab3d8Srobert """Platform specific way to build binaries.""" 1429*f6aab3d8Srobert if not architecture and configuration.arch: 1430*f6aab3d8Srobert architecture = configuration.arch 1431*f6aab3d8Srobert 1432*f6aab3d8Srobert if debug_info is None: 1433*f6aab3d8Srobert debug_info = self.getDebugInfo() 1434*f6aab3d8Srobert 1435*f6aab3d8Srobert dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1436*f6aab3d8Srobert 1437*f6aab3d8Srobert testdir = self.mydir 1438*f6aab3d8Srobert testname = self.getBuildDirBasename() 1439*f6aab3d8Srobert 1440*f6aab3d8Srobert module = builder_module() 1441*f6aab3d8Srobert command = builder_module().getBuildCommand(debug_info, architecture, 1442*f6aab3d8Srobert compiler, dictionary, testdir, testname, make_targets) 1443*f6aab3d8Srobert if command is None: 1444*f6aab3d8Srobert raise Exception("Don't know how to build binary") 1445*f6aab3d8Srobert 1446*f6aab3d8Srobert self.runBuildCommand(command) 1447*f6aab3d8Srobert 1448*f6aab3d8Srobert def runBuildCommand(self, command): 1449*f6aab3d8Srobert self.trace(seven.join_for_shell(command)) 1450*f6aab3d8Srobert try: 1451*f6aab3d8Srobert output = check_output(command, stderr=STDOUT, errors="replace") 1452*f6aab3d8Srobert except CalledProcessError as cpe: 1453*f6aab3d8Srobert raise build_exception.BuildError(cpe) 1454*f6aab3d8Srobert self.trace(output) 1455*f6aab3d8Srobert 1456*f6aab3d8Srobert 1457061da546Spatrick # ================================================== 1458061da546Spatrick # Build methods supported through a plugin interface 1459061da546Spatrick # ================================================== 1460061da546Spatrick 1461061da546Spatrick def getstdlibFlag(self): 1462061da546Spatrick """ Returns the proper -stdlib flag, or empty if not required.""" 1463061da546Spatrick if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": 1464061da546Spatrick stdlibflag = "-stdlib=libc++" 1465061da546Spatrick else: # this includes NetBSD 1466061da546Spatrick stdlibflag = "" 1467061da546Spatrick return stdlibflag 1468061da546Spatrick 1469061da546Spatrick def getstdFlag(self): 1470061da546Spatrick """ Returns the proper stdflag. """ 1471061da546Spatrick if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1472061da546Spatrick stdflag = "-std=c++0x" 1473061da546Spatrick else: 1474061da546Spatrick stdflag = "-std=c++11" 1475061da546Spatrick return stdflag 1476061da546Spatrick 1477061da546Spatrick def buildDriver(self, sources, exe_name): 1478061da546Spatrick """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1479061da546Spatrick or LLDB.framework). 1480061da546Spatrick """ 1481061da546Spatrick stdflag = self.getstdFlag() 1482061da546Spatrick stdlibflag = self.getstdlibFlag() 1483061da546Spatrick 1484dda28197Spatrick lib_dir = configuration.lldb_libs_dir 1485061da546Spatrick if self.hasDarwinFramework(): 1486061da546Spatrick d = {'CXX_SOURCES': sources, 1487061da546Spatrick 'EXE': exe_name, 1488061da546Spatrick 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1489061da546Spatrick 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1490be691f3bSpatrick 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir), 1491061da546Spatrick } 1492061da546Spatrick elif sys.platform.startswith('win'): 1493061da546Spatrick d = { 1494061da546Spatrick 'CXX_SOURCES': sources, 1495061da546Spatrick 'EXE': exe_name, 1496061da546Spatrick 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1497061da546Spatrick stdlibflag, 1498061da546Spatrick os.path.join( 1499061da546Spatrick os.environ["LLDB_SRC"], 1500061da546Spatrick "include")), 1501be691f3bSpatrick 'LD_EXTRAS': "-L%s -lliblldb" % lib_dir} 1502061da546Spatrick else: 1503061da546Spatrick d = { 1504061da546Spatrick 'CXX_SOURCES': sources, 1505061da546Spatrick 'EXE': exe_name, 1506061da546Spatrick 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1507061da546Spatrick stdlibflag, 1508061da546Spatrick os.path.join( 1509061da546Spatrick os.environ["LLDB_SRC"], 1510061da546Spatrick "include")), 1511dda28197Spatrick 'LD_EXTRAS': "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1512061da546Spatrick if self.TraceOn(): 1513061da546Spatrick print( 1514061da546Spatrick "Building LLDB Driver (%s) from sources %s" % 1515061da546Spatrick (exe_name, sources)) 1516061da546Spatrick 1517*f6aab3d8Srobert self.build(dictionary=d) 1518061da546Spatrick 1519061da546Spatrick def buildLibrary(self, sources, lib_name): 1520061da546Spatrick """Platform specific way to build a default library. """ 1521061da546Spatrick 1522061da546Spatrick stdflag = self.getstdFlag() 1523061da546Spatrick 1524dda28197Spatrick lib_dir = configuration.lldb_libs_dir 1525061da546Spatrick if self.hasDarwinFramework(): 1526061da546Spatrick d = {'DYLIB_CXX_SOURCES': sources, 1527061da546Spatrick 'DYLIB_NAME': lib_name, 1528061da546Spatrick 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1529061da546Spatrick 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1530be691f3bSpatrick 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.lib_lldb, self.framework_dir), 1531061da546Spatrick } 1532061da546Spatrick elif self.getPlatform() == 'windows': 1533061da546Spatrick d = { 1534061da546Spatrick 'DYLIB_CXX_SOURCES': sources, 1535061da546Spatrick 'DYLIB_NAME': lib_name, 1536061da546Spatrick 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, 1537061da546Spatrick os.path.join( 1538061da546Spatrick os.environ["LLDB_SRC"], 1539061da546Spatrick "include")), 1540be691f3bSpatrick 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % lib_dir} 1541061da546Spatrick else: 1542061da546Spatrick d = { 1543061da546Spatrick 'DYLIB_CXX_SOURCES': sources, 1544061da546Spatrick 'DYLIB_NAME': lib_name, 1545061da546Spatrick 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1546061da546Spatrick os.path.join( 1547061da546Spatrick os.environ["LLDB_SRC"], 1548061da546Spatrick "include")), 1549dda28197Spatrick 'LD_EXTRAS': "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1550061da546Spatrick if self.TraceOn(): 1551061da546Spatrick print( 1552061da546Spatrick "Building LLDB Library (%s) from sources %s" % 1553061da546Spatrick (lib_name, sources)) 1554061da546Spatrick 1555*f6aab3d8Srobert self.build(dictionary=d) 1556061da546Spatrick 1557061da546Spatrick def buildProgram(self, sources, exe_name): 1558061da546Spatrick """ Platform specific way to build an executable from C/C++ sources. """ 1559061da546Spatrick d = {'CXX_SOURCES': sources, 1560061da546Spatrick 'EXE': exe_name} 1561*f6aab3d8Srobert self.build(dictionary=d) 1562061da546Spatrick 1563061da546Spatrick def signBinary(self, binary_path): 1564061da546Spatrick if sys.platform.startswith("darwin"): 1565061da546Spatrick codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1566061da546Spatrick lldbtest_config.codesign_identity, binary_path) 1567061da546Spatrick call(codesign_cmd, shell=True) 1568061da546Spatrick 1569061da546Spatrick def findBuiltClang(self): 1570061da546Spatrick """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1571061da546Spatrick paths_to_try = [ 1572061da546Spatrick "llvm-build/Release+Asserts/x86_64/bin/clang", 1573061da546Spatrick "llvm-build/Debug+Asserts/x86_64/bin/clang", 1574061da546Spatrick "llvm-build/Release/x86_64/bin/clang", 1575061da546Spatrick "llvm-build/Debug/x86_64/bin/clang", 1576061da546Spatrick ] 1577061da546Spatrick lldb_root_path = os.path.join( 1578061da546Spatrick os.path.dirname(__file__), "..", "..", "..", "..") 1579061da546Spatrick for p in paths_to_try: 1580061da546Spatrick path = os.path.join(lldb_root_path, p) 1581061da546Spatrick if os.path.exists(path): 1582061da546Spatrick return path 1583061da546Spatrick 1584061da546Spatrick # Tries to find clang at the same folder as the lldb 1585061da546Spatrick lldb_dir = os.path.dirname(lldbtest_config.lldbExec) 1586*f6aab3d8Srobert path = shutil.which("clang", path=lldb_dir) 1587061da546Spatrick if path is not None: 1588061da546Spatrick return path 1589061da546Spatrick 1590061da546Spatrick return os.environ["CC"] 1591061da546Spatrick 1592061da546Spatrick 1593*f6aab3d8Srobert def yaml2obj(self, yaml_path, obj_path, max_size=None): 1594061da546Spatrick """ 1595061da546Spatrick Create an object file at the given path from a yaml file. 1596061da546Spatrick 1597061da546Spatrick Throws subprocess.CalledProcessError if the object could not be created. 1598061da546Spatrick """ 1599dda28197Spatrick yaml2obj_bin = configuration.get_yaml2obj_path() 1600dda28197Spatrick if not yaml2obj_bin: 1601be691f3bSpatrick self.assertTrue(False, "No valid yaml2obj executable specified") 1602dda28197Spatrick command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path] 1603*f6aab3d8Srobert if max_size is not None: 1604*f6aab3d8Srobert command += ["--max-size=%d" % max_size] 1605*f6aab3d8Srobert self.runBuildCommand(command) 1606061da546Spatrick 1607061da546Spatrick def cleanup(self, dictionary=None): 1608061da546Spatrick """Platform specific way to do cleanup after build.""" 1609061da546Spatrick module = builder_module() 1610*f6aab3d8Srobert if not module.cleanup(dictionary): 1611061da546Spatrick raise Exception( 1612061da546Spatrick "Don't know how to do cleanup with dictionary: " + 1613061da546Spatrick dictionary) 1614061da546Spatrick 1615be691f3bSpatrick def invoke(self, obj, name, trace=False): 1616be691f3bSpatrick """Use reflection to call a method dynamically with no argument.""" 1617be691f3bSpatrick trace = (True if traceAlways else trace) 1618be691f3bSpatrick 1619be691f3bSpatrick method = getattr(obj, name) 1620be691f3bSpatrick import inspect 1621be691f3bSpatrick self.assertTrue(inspect.ismethod(method), 1622be691f3bSpatrick name + "is a method name of object: " + str(obj)) 1623be691f3bSpatrick result = method() 1624be691f3bSpatrick with recording(self, trace) as sbuf: 1625be691f3bSpatrick print(str(method) + ":", result, file=sbuf) 1626be691f3bSpatrick return result 1627be691f3bSpatrick 1628061da546Spatrick def getLLDBLibraryEnvVal(self): 1629061da546Spatrick """ Returns the path that the OS-specific library search environment variable 1630061da546Spatrick (self.dylibPath) should be set to in order for a program to find the LLDB 1631061da546Spatrick library. If an environment variable named self.dylibPath is already set, 1632061da546Spatrick the new path is appended to it and returned. 1633061da546Spatrick """ 1634061da546Spatrick existing_library_path = os.environ[ 1635061da546Spatrick self.dylibPath] if self.dylibPath in os.environ else None 1636061da546Spatrick if existing_library_path: 1637be691f3bSpatrick return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir) 1638be691f3bSpatrick if sys.platform.startswith("darwin") and configuration.lldb_framework_path: 1639be691f3bSpatrick return configuration.lldb_framework_path 1640be691f3bSpatrick return configuration.lldb_libs_dir 1641061da546Spatrick 1642061da546Spatrick def getLibcPlusPlusLibs(self): 1643061da546Spatrick if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): 1644061da546Spatrick return ['libc++.so.1'] 1645061da546Spatrick else: 1646061da546Spatrick return ['libc++.1.dylib', 'libc++abi.'] 1647061da546Spatrick 1648be691f3bSpatrick def run_platform_command(self, cmd): 1649be691f3bSpatrick platform = self.dbg.GetSelectedPlatform() 1650be691f3bSpatrick shell_command = lldb.SBPlatformShellCommand(cmd) 1651be691f3bSpatrick err = platform.Run(shell_command) 1652be691f3bSpatrick return (err, shell_command.GetStatus(), shell_command.GetOutput()) 1653be691f3bSpatrick 1654*f6aab3d8Srobert def get_stats(self, options=None): 1655*f6aab3d8Srobert """ 1656*f6aab3d8Srobert Get the output of the "statistics dump" with optional extra options 1657*f6aab3d8Srobert and return the JSON as a python dictionary. 1658*f6aab3d8Srobert """ 1659*f6aab3d8Srobert return_obj = lldb.SBCommandReturnObject() 1660*f6aab3d8Srobert command = "statistics dump " 1661*f6aab3d8Srobert if options is not None: 1662*f6aab3d8Srobert command += options 1663*f6aab3d8Srobert self.ci.HandleCommand(command, return_obj, False) 1664*f6aab3d8Srobert metrics_json = return_obj.GetOutput() 1665*f6aab3d8Srobert return json.loads(metrics_json) 1666*f6aab3d8Srobert 1667061da546Spatrick# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1668061da546Spatrick# We change the test methods to create a new test method for each test for each debug info we are 1669061da546Spatrick# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1670061da546Spatrick# the new test method we remove the old method at the same time. This functionality can be 1671061da546Spatrick# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1672061da546Spatrick# level by using the decorator @no_debug_info_test. 1673061da546Spatrick 1674061da546Spatrick 1675061da546Spatrickclass LLDBTestCaseFactory(type): 1676061da546Spatrick 1677061da546Spatrick def __new__(cls, name, bases, attrs): 1678061da546Spatrick original_testcase = super( 1679061da546Spatrick LLDBTestCaseFactory, cls).__new__( 1680061da546Spatrick cls, name, bases, attrs) 1681061da546Spatrick if original_testcase.NO_DEBUG_INFO_TESTCASE: 1682061da546Spatrick return original_testcase 1683061da546Spatrick 1684061da546Spatrick newattrs = {} 1685061da546Spatrick for attrname, attrvalue in attrs.items(): 1686061da546Spatrick if attrname.startswith("test") and not getattr( 1687061da546Spatrick attrvalue, "__no_debug_info_test__", False): 1688061da546Spatrick 1689061da546Spatrick # If any debug info categories were explicitly tagged, assume that list to be 1690061da546Spatrick # authoritative. If none were specified, try with all debug 1691061da546Spatrick # info formats. 1692*f6aab3d8Srobert all_dbginfo_categories = set(test_categories.debug_info_categories.keys()) 1693061da546Spatrick categories = set( 1694061da546Spatrick getattr( 1695061da546Spatrick attrvalue, 1696061da546Spatrick "categories", 1697061da546Spatrick [])) & all_dbginfo_categories 1698061da546Spatrick if not categories: 1699*f6aab3d8Srobert categories = [category for category, can_replicate \ 1700*f6aab3d8Srobert in test_categories.debug_info_categories.items() \ 1701*f6aab3d8Srobert if can_replicate] 1702061da546Spatrick 1703061da546Spatrick for cat in categories: 1704061da546Spatrick @decorators.add_test_categories([cat]) 1705061da546Spatrick @wraps(attrvalue) 1706061da546Spatrick def test_method(self, attrvalue=attrvalue): 1707061da546Spatrick return attrvalue(self) 1708061da546Spatrick 1709061da546Spatrick method_name = attrname + "_" + cat 1710061da546Spatrick test_method.__name__ = method_name 1711061da546Spatrick test_method.debug_info = cat 1712061da546Spatrick newattrs[method_name] = test_method 1713061da546Spatrick 1714061da546Spatrick else: 1715061da546Spatrick newattrs[attrname] = attrvalue 1716061da546Spatrick return super( 1717061da546Spatrick LLDBTestCaseFactory, 1718061da546Spatrick cls).__new__( 1719061da546Spatrick cls, 1720061da546Spatrick name, 1721061da546Spatrick bases, 1722061da546Spatrick newattrs) 1723061da546Spatrick 1724061da546Spatrick# Setup the metaclass for this class to change the list of the test 1725061da546Spatrick# methods when a new class is loaded 1726061da546Spatrick 1727061da546Spatrick 1728*f6aab3d8Srobertclass TestBase(Base, metaclass=LLDBTestCaseFactory): 1729061da546Spatrick """ 1730061da546Spatrick This abstract base class is meant to be subclassed. It provides default 1731061da546Spatrick implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1732061da546Spatrick among other things. 1733061da546Spatrick 1734061da546Spatrick Important things for test class writers: 1735061da546Spatrick 1736061da546Spatrick - The setUp method sets up things to facilitate subsequent interactions 1737061da546Spatrick with the debugger as part of the test. These include: 1738061da546Spatrick - populate the test method name 1739061da546Spatrick - create/get a debugger set with synchronous mode (self.dbg) 1740061da546Spatrick - get the command interpreter from with the debugger (self.ci) 1741061da546Spatrick - create a result object for use with the command interpreter 1742061da546Spatrick (self.res) 1743061da546Spatrick - plus other stuffs 1744061da546Spatrick 1745061da546Spatrick - The tearDown method tries to perform some necessary cleanup on behalf 1746061da546Spatrick of the test to return the debugger to a good state for the next test. 1747061da546Spatrick These include: 1748061da546Spatrick - execute any tearDown hooks registered by the test method with 1749061da546Spatrick TestBase.addTearDownHook(); examples can be found in 1750061da546Spatrick settings/TestSettings.py 1751061da546Spatrick - kill the inferior process associated with each target, if any, 1752061da546Spatrick and, then delete the target from the debugger's target list 1753061da546Spatrick - perform build cleanup before running the next test method in the 1754061da546Spatrick same test class; examples of registering for this service can be 1755061da546Spatrick found in types/TestIntegerTypes.py with the call: 1756061da546Spatrick - self.setTearDownCleanup(dictionary=d) 1757061da546Spatrick 1758061da546Spatrick - Similarly setUpClass and tearDownClass perform classwise setup and 1759061da546Spatrick teardown fixtures. The tearDownClass method invokes a default build 1760061da546Spatrick cleanup for the entire test class; also, subclasses can implement the 1761061da546Spatrick classmethod classCleanup(cls) to perform special class cleanup action. 1762061da546Spatrick 1763061da546Spatrick - The instance methods runCmd and expect are used heavily by existing 1764061da546Spatrick test cases to send a command to the command interpreter and to perform 1765061da546Spatrick string/pattern matching on the output of such command execution. The 1766061da546Spatrick expect method also provides a mode to peform string/pattern matching 1767061da546Spatrick without running a command. 1768061da546Spatrick 1769*f6aab3d8Srobert - The build method is used to build the binaries used during a 1770*f6aab3d8Srobert particular test scenario. A plugin should be provided for the 1771*f6aab3d8Srobert sys.platform running the test suite. The Mac OS X implementation is 1772*f6aab3d8Srobert located in builders/darwin.py. 1773061da546Spatrick """ 1774061da546Spatrick 1775061da546Spatrick # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1776061da546Spatrick # test multiple times with various debug info types. 1777061da546Spatrick NO_DEBUG_INFO_TESTCASE = False 1778061da546Spatrick 1779061da546Spatrick # Maximum allowed attempts when launching the inferior process. 1780061da546Spatrick # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1781061da546Spatrick maxLaunchCount = 1 1782061da546Spatrick 1783061da546Spatrick # Time to wait before the next launching attempt in second(s). 1784061da546Spatrick # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1785061da546Spatrick timeWaitNextLaunch = 1.0 1786061da546Spatrick 1787061da546Spatrick def generateSource(self, source): 1788061da546Spatrick template = source + '.template' 1789061da546Spatrick temp = os.path.join(self.getSourceDir(), template) 1790061da546Spatrick with open(temp, 'r') as f: 1791061da546Spatrick content = f.read() 1792061da546Spatrick 1793061da546Spatrick public_api_dir = os.path.join( 1794061da546Spatrick os.environ["LLDB_SRC"], "include", "lldb", "API") 1795061da546Spatrick 1796061da546Spatrick # Look under the include/lldb/API directory and add #include statements 1797061da546Spatrick # for all the SB API headers. 1798061da546Spatrick public_headers = os.listdir(public_api_dir) 1799061da546Spatrick # For different platforms, the include statement can vary. 1800061da546Spatrick if self.hasDarwinFramework(): 1801061da546Spatrick include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" 1802061da546Spatrick else: 1803*f6aab3d8Srobert include_stmt = "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)" 1804061da546Spatrick list = [eval(include_stmt) for header in public_headers if ( 1805061da546Spatrick header.startswith("SB") and header.endswith(".h"))] 1806061da546Spatrick includes = '\n'.join(list) 1807061da546Spatrick new_content = content.replace('%include_SB_APIs%', includes) 1808be691f3bSpatrick new_content = new_content.replace('%SOURCE_DIR%', self.getSourceDir()) 1809061da546Spatrick src = os.path.join(self.getBuildDir(), source) 1810061da546Spatrick with open(src, 'w') as f: 1811061da546Spatrick f.write(new_content) 1812061da546Spatrick 1813061da546Spatrick self.addTearDownHook(lambda: os.remove(src)) 1814061da546Spatrick 1815061da546Spatrick def setUp(self): 1816061da546Spatrick # Works with the test driver to conditionally skip tests via 1817061da546Spatrick # decorators. 1818061da546Spatrick Base.setUp(self) 1819061da546Spatrick 1820061da546Spatrick for s in self.setUpCommands(): 1821061da546Spatrick self.runCmd(s) 1822061da546Spatrick 1823061da546Spatrick if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1824061da546Spatrick self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1825061da546Spatrick 1826061da546Spatrick if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1827061da546Spatrick self.timeWaitNextLaunch = float( 1828061da546Spatrick os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1829061da546Spatrick 1830061da546Spatrick # We want our debugger to be synchronous. 1831061da546Spatrick self.dbg.SetAsync(False) 1832061da546Spatrick 1833061da546Spatrick # Retrieve the associated command interpreter instance. 1834061da546Spatrick self.ci = self.dbg.GetCommandInterpreter() 1835061da546Spatrick if not self.ci: 1836061da546Spatrick raise Exception('Could not get the command interpreter') 1837061da546Spatrick 1838061da546Spatrick # And the result object. 1839061da546Spatrick self.res = lldb.SBCommandReturnObject() 1840061da546Spatrick 1841061da546Spatrick def registerSharedLibrariesWithTarget(self, target, shlibs): 1842061da546Spatrick '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1843061da546Spatrick 1844061da546Spatrick Any modules in the target that have their remote install file specification set will 1845061da546Spatrick get uploaded to the remote host. This function registers the local copies of the 1846061da546Spatrick shared libraries with the target and sets their remote install locations so they will 1847061da546Spatrick be uploaded when the target is run. 1848061da546Spatrick ''' 1849061da546Spatrick if not shlibs or not self.platformContext: 1850061da546Spatrick return None 1851061da546Spatrick 1852061da546Spatrick shlib_environment_var = self.platformContext.shlib_environment_var 1853061da546Spatrick shlib_prefix = self.platformContext.shlib_prefix 1854061da546Spatrick shlib_extension = '.' + self.platformContext.shlib_extension 1855061da546Spatrick 1856be691f3bSpatrick dirs = [] 1857061da546Spatrick # Add any shared libraries to our target if remote so they get 1858061da546Spatrick # uploaded into the working directory on the remote side 1859061da546Spatrick for name in shlibs: 1860061da546Spatrick # The path can be a full path to a shared library, or a make file name like "Foo" for 1861061da546Spatrick # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1862061da546Spatrick # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1863061da546Spatrick # of the shared library accordingly 1864061da546Spatrick if os.path.isfile(name): 1865061da546Spatrick local_shlib_path = name # name is the full path to the local shared library 1866061da546Spatrick else: 1867061da546Spatrick # Check relative names 1868061da546Spatrick local_shlib_path = os.path.join( 1869061da546Spatrick self.getBuildDir(), shlib_prefix + name + shlib_extension) 1870061da546Spatrick if not os.path.exists(local_shlib_path): 1871061da546Spatrick local_shlib_path = os.path.join( 1872061da546Spatrick self.getBuildDir(), name + shlib_extension) 1873061da546Spatrick if not os.path.exists(local_shlib_path): 1874061da546Spatrick local_shlib_path = os.path.join(self.getBuildDir(), name) 1875061da546Spatrick 1876061da546Spatrick # Make sure we found the local shared library in the above code 1877061da546Spatrick self.assertTrue(os.path.exists(local_shlib_path)) 1878061da546Spatrick 1879be691f3bSpatrick 1880061da546Spatrick # Add the shared library to our target 1881061da546Spatrick shlib_module = target.AddModule(local_shlib_path, None, None, None) 1882061da546Spatrick if lldb.remote_platform: 1883061da546Spatrick # We must set the remote install location if we want the shared library 1884061da546Spatrick # to get uploaded to the remote target 1885061da546Spatrick remote_shlib_path = lldbutil.append_to_process_working_directory(self, 1886061da546Spatrick os.path.basename(local_shlib_path)) 1887061da546Spatrick shlib_module.SetRemoteInstallFileSpec( 1888061da546Spatrick lldb.SBFileSpec(remote_shlib_path, False)) 1889be691f3bSpatrick dir_to_add = self.get_process_working_directory() 1890be691f3bSpatrick else: 1891be691f3bSpatrick dir_to_add = os.path.dirname(local_shlib_path) 1892061da546Spatrick 1893be691f3bSpatrick if dir_to_add not in dirs: 1894be691f3bSpatrick dirs.append(dir_to_add) 1895be691f3bSpatrick 1896be691f3bSpatrick env_value = self.platformContext.shlib_path_separator.join(dirs) 1897be691f3bSpatrick return ['%s=%s' % (shlib_environment_var, env_value)] 1898061da546Spatrick 1899061da546Spatrick def registerSanitizerLibrariesWithTarget(self, target): 1900061da546Spatrick runtimes = [] 1901061da546Spatrick for m in target.module_iter(): 1902061da546Spatrick libspec = m.GetFileSpec() 1903061da546Spatrick if "clang_rt" in libspec.GetFilename(): 1904061da546Spatrick runtimes.append(os.path.join(libspec.GetDirectory(), 1905061da546Spatrick libspec.GetFilename())) 1906061da546Spatrick return self.registerSharedLibrariesWithTarget(target, runtimes) 1907061da546Spatrick 1908061da546Spatrick # utility methods that tests can use to access the current objects 1909061da546Spatrick def target(self): 1910061da546Spatrick if not self.dbg: 1911061da546Spatrick raise Exception('Invalid debugger instance') 1912061da546Spatrick return self.dbg.GetSelectedTarget() 1913061da546Spatrick 1914061da546Spatrick def process(self): 1915061da546Spatrick if not self.dbg: 1916061da546Spatrick raise Exception('Invalid debugger instance') 1917061da546Spatrick return self.dbg.GetSelectedTarget().GetProcess() 1918061da546Spatrick 1919061da546Spatrick def thread(self): 1920061da546Spatrick if not self.dbg: 1921061da546Spatrick raise Exception('Invalid debugger instance') 1922061da546Spatrick return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1923061da546Spatrick 1924061da546Spatrick def frame(self): 1925061da546Spatrick if not self.dbg: 1926061da546Spatrick raise Exception('Invalid debugger instance') 1927061da546Spatrick return self.dbg.GetSelectedTarget().GetProcess( 1928061da546Spatrick ).GetSelectedThread().GetSelectedFrame() 1929061da546Spatrick 1930061da546Spatrick def get_process_working_directory(self): 1931061da546Spatrick '''Get the working directory that should be used when launching processes for local or remote processes.''' 1932061da546Spatrick if lldb.remote_platform: 1933061da546Spatrick # Remote tests set the platform working directory up in 1934061da546Spatrick # TestBase.setUp() 1935061da546Spatrick return lldb.remote_platform.GetWorkingDirectory() 1936061da546Spatrick else: 1937061da546Spatrick # local tests change directory into each test subdirectory 1938061da546Spatrick return self.getBuildDir() 1939061da546Spatrick 1940061da546Spatrick def tearDown(self): 1941061da546Spatrick # Ensure all the references to SB objects have gone away so that we can 1942061da546Spatrick # be sure that all test-specific resources have been freed before we 1943061da546Spatrick # attempt to delete the targets. 1944061da546Spatrick gc.collect() 1945061da546Spatrick 1946061da546Spatrick # Delete the target(s) from the debugger as a general cleanup step. 1947061da546Spatrick # This includes terminating the process for each target, if any. 1948061da546Spatrick # We'd like to reuse the debugger for our next test without incurring 1949061da546Spatrick # the initialization overhead. 1950061da546Spatrick targets = [] 1951061da546Spatrick for target in self.dbg: 1952061da546Spatrick if target: 1953061da546Spatrick targets.append(target) 1954061da546Spatrick process = target.GetProcess() 1955061da546Spatrick if process: 1956061da546Spatrick rc = self.invoke(process, "Kill") 1957dda28197Spatrick assert rc.Success() 1958061da546Spatrick for target in targets: 1959061da546Spatrick self.dbg.DeleteTarget(target) 1960061da546Spatrick 1961dda28197Spatrick # Assert that all targets are deleted. 1962be691f3bSpatrick self.assertEqual(self.dbg.GetNumTargets(), 0) 1963dda28197Spatrick 1964061da546Spatrick # Do this last, to make sure it's in reverse order from how we setup. 1965061da546Spatrick Base.tearDown(self) 1966061da546Spatrick 1967061da546Spatrick def switch_to_thread_with_stop_reason(self, stop_reason): 1968061da546Spatrick """ 1969061da546Spatrick Run the 'thread list' command, and select the thread with stop reason as 1970061da546Spatrick 'stop_reason'. If no such thread exists, no select action is done. 1971061da546Spatrick """ 1972061da546Spatrick from .lldbutil import stop_reason_to_str 1973061da546Spatrick self.runCmd('thread list') 1974061da546Spatrick output = self.res.GetOutput() 1975061da546Spatrick thread_line_pattern = re.compile( 1976061da546Spatrick "^[ *] thread #([0-9]+):.*stop reason = %s" % 1977061da546Spatrick stop_reason_to_str(stop_reason)) 1978061da546Spatrick for line in output.splitlines(): 1979061da546Spatrick matched = thread_line_pattern.match(line) 1980061da546Spatrick if matched: 1981061da546Spatrick self.runCmd('thread select %s' % matched.group(1)) 1982061da546Spatrick 1983061da546Spatrick def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 1984061da546Spatrick """ 1985061da546Spatrick Ask the command interpreter to handle the command and then check its 1986061da546Spatrick return status. 1987061da546Spatrick """ 1988061da546Spatrick # Fail fast if 'cmd' is not meaningful. 1989be691f3bSpatrick if cmd is None: 1990061da546Spatrick raise Exception("Bad 'cmd' parameter encountered") 1991061da546Spatrick 1992061da546Spatrick trace = (True if traceAlways else trace) 1993061da546Spatrick 1994061da546Spatrick if cmd.startswith("target create "): 1995061da546Spatrick cmd = cmd.replace("target create ", "file ") 1996061da546Spatrick 1997061da546Spatrick running = (cmd.startswith("run") or cmd.startswith("process launch")) 1998061da546Spatrick 1999061da546Spatrick for i in range(self.maxLaunchCount if running else 1): 2000061da546Spatrick self.ci.HandleCommand(cmd, self.res, inHistory) 2001061da546Spatrick 2002061da546Spatrick with recording(self, trace) as sbuf: 2003061da546Spatrick print("runCmd:", cmd, file=sbuf) 2004061da546Spatrick if not check: 2005061da546Spatrick print("check of return status not required", file=sbuf) 2006061da546Spatrick if self.res.Succeeded(): 2007061da546Spatrick print("output:", self.res.GetOutput(), file=sbuf) 2008061da546Spatrick else: 2009061da546Spatrick print("runCmd failed!", file=sbuf) 2010061da546Spatrick print(self.res.GetError(), file=sbuf) 2011061da546Spatrick 2012061da546Spatrick if self.res.Succeeded(): 2013061da546Spatrick break 2014061da546Spatrick elif running: 2015061da546Spatrick # For process launch, wait some time before possible next try. 2016061da546Spatrick time.sleep(self.timeWaitNextLaunch) 2017061da546Spatrick with recording(self, trace) as sbuf: 2018061da546Spatrick print("Command '" + cmd + "' failed!", file=sbuf) 2019061da546Spatrick 2020061da546Spatrick if check: 2021061da546Spatrick output = "" 2022061da546Spatrick if self.res.GetOutput(): 2023061da546Spatrick output += "\nCommand output:\n" + self.res.GetOutput() 2024061da546Spatrick if self.res.GetError(): 2025061da546Spatrick output += "\nError output:\n" + self.res.GetError() 2026061da546Spatrick if msg: 2027061da546Spatrick msg += output 2028061da546Spatrick if cmd: 2029061da546Spatrick cmd += output 2030061da546Spatrick self.assertTrue(self.res.Succeeded(), 2031061da546Spatrick msg if (msg) else CMD_MSG(cmd)) 2032061da546Spatrick 2033061da546Spatrick def match( 2034061da546Spatrick self, 2035061da546Spatrick str, 2036061da546Spatrick patterns, 2037061da546Spatrick msg=None, 2038061da546Spatrick trace=False, 2039061da546Spatrick error=False, 2040061da546Spatrick matching=True, 2041061da546Spatrick exe=True): 2042061da546Spatrick """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2043061da546Spatrick 2044061da546Spatrick Otherwise, all the arguments have the same meanings as for the expect function""" 2045061da546Spatrick 2046061da546Spatrick trace = (True if traceAlways else trace) 2047061da546Spatrick 2048061da546Spatrick if exe: 2049061da546Spatrick # First run the command. If we are expecting error, set check=False. 2050061da546Spatrick # Pass the assert message along since it provides more semantic 2051061da546Spatrick # info. 2052061da546Spatrick self.runCmd( 2053061da546Spatrick str, 2054061da546Spatrick msg=msg, 2055061da546Spatrick trace=( 2056061da546Spatrick True if trace else False), 2057061da546Spatrick check=not error) 2058061da546Spatrick 2059061da546Spatrick # Then compare the output against expected strings. 2060061da546Spatrick output = self.res.GetError() if error else self.res.GetOutput() 2061061da546Spatrick 2062061da546Spatrick # If error is True, the API client expects the command to fail! 2063061da546Spatrick if error: 2064061da546Spatrick self.assertFalse(self.res.Succeeded(), 2065061da546Spatrick "Command '" + str + "' is expected to fail!") 2066061da546Spatrick else: 2067061da546Spatrick # No execution required, just compare str against the golden input. 2068061da546Spatrick output = str 2069061da546Spatrick with recording(self, trace) as sbuf: 2070061da546Spatrick print("looking at:", output, file=sbuf) 2071061da546Spatrick 2072061da546Spatrick # The heading says either "Expecting" or "Not expecting". 2073061da546Spatrick heading = "Expecting" if matching else "Not expecting" 2074061da546Spatrick 2075061da546Spatrick for pattern in patterns: 2076061da546Spatrick # Match Objects always have a boolean value of True. 2077061da546Spatrick match_object = re.search(pattern, output) 2078061da546Spatrick matched = bool(match_object) 2079061da546Spatrick with recording(self, trace) as sbuf: 2080061da546Spatrick print("%s pattern: %s" % (heading, pattern), file=sbuf) 2081061da546Spatrick print("Matched" if matched else "Not matched", file=sbuf) 2082061da546Spatrick if matched: 2083061da546Spatrick break 2084061da546Spatrick 2085061da546Spatrick self.assertTrue(matched if matching else not matched, 2086061da546Spatrick msg if msg else EXP_MSG(str, output, exe)) 2087061da546Spatrick 2088061da546Spatrick return match_object 2089061da546Spatrick 2090dda28197Spatrick def check_completion_with_desc(self, str_input, match_desc_pairs, enforce_order=False): 2091dda28197Spatrick """ 2092dda28197Spatrick Checks that when the given input is completed at the given list of 2093dda28197Spatrick completions and descriptions is returned. 2094dda28197Spatrick :param str_input: The input that should be completed. The completion happens at the end of the string. 2095dda28197Spatrick :param match_desc_pairs: A list of pairs that indicate what completions have to be in the list of 2096dda28197Spatrick completions returned by LLDB. The first element of the pair is the completion 2097dda28197Spatrick string that LLDB should generate and the second element the description. 2098dda28197Spatrick :param enforce_order: True iff the order in which the completions are returned by LLDB 2099dda28197Spatrick should match the order of the match_desc_pairs pairs. 2100dda28197Spatrick """ 2101061da546Spatrick interp = self.dbg.GetCommandInterpreter() 2102061da546Spatrick match_strings = lldb.SBStringList() 2103061da546Spatrick description_strings = lldb.SBStringList() 2104061da546Spatrick num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) 2105061da546Spatrick self.assertEqual(len(description_strings), len(match_strings)) 2106061da546Spatrick 2107dda28197Spatrick # The index of the last matched description in description_strings or 2108dda28197Spatrick # -1 if no description has been matched yet. 2109dda28197Spatrick last_found_index = -1 2110dda28197Spatrick out_of_order_errors = "" 2111061da546Spatrick missing_pairs = [] 2112061da546Spatrick for pair in match_desc_pairs: 2113061da546Spatrick found_pair = False 2114061da546Spatrick for i in range(num_matches + 1): 2115061da546Spatrick match_candidate = match_strings.GetStringAtIndex(i) 2116061da546Spatrick description_candidate = description_strings.GetStringAtIndex(i) 2117061da546Spatrick if match_candidate == pair[0] and description_candidate == pair[1]: 2118061da546Spatrick found_pair = True 2119dda28197Spatrick if enforce_order and last_found_index > i: 2120dda28197Spatrick new_err = ("Found completion " + pair[0] + " at index " + 2121dda28197Spatrick str(i) + " in returned completion list but " + 2122dda28197Spatrick "should have been after completion " + 2123dda28197Spatrick match_strings.GetStringAtIndex(last_found_index) + 2124dda28197Spatrick " (index:" + str(last_found_index) + ")\n") 2125dda28197Spatrick out_of_order_errors += new_err 2126dda28197Spatrick last_found_index = i 2127061da546Spatrick break 2128061da546Spatrick if not found_pair: 2129061da546Spatrick missing_pairs.append(pair) 2130061da546Spatrick 2131dda28197Spatrick error_msg = "" 2132dda28197Spatrick got_failure = False 2133061da546Spatrick if len(missing_pairs): 2134dda28197Spatrick got_failure = True 2135dda28197Spatrick error_msg += "Missing pairs:\n" 2136061da546Spatrick for pair in missing_pairs: 2137061da546Spatrick error_msg += " [" + pair[0] + ":" + pair[1] + "]\n" 2138dda28197Spatrick if len(out_of_order_errors): 2139dda28197Spatrick got_failure = True 2140dda28197Spatrick error_msg += out_of_order_errors 2141dda28197Spatrick if got_failure: 2142061da546Spatrick error_msg += "Got the following " + str(num_matches) + " completions back:\n" 2143061da546Spatrick for i in range(num_matches + 1): 2144061da546Spatrick match_candidate = match_strings.GetStringAtIndex(i) 2145061da546Spatrick description_candidate = description_strings.GetStringAtIndex(i) 2146dda28197Spatrick error_msg += "[" + match_candidate + ":" + description_candidate + "] index " + str(i) + "\n" 2147dda28197Spatrick self.assertFalse(got_failure, error_msg) 2148061da546Spatrick 2149061da546Spatrick def complete_exactly(self, str_input, patterns): 2150061da546Spatrick self.complete_from_to(str_input, patterns, True) 2151061da546Spatrick 2152061da546Spatrick def complete_from_to(self, str_input, patterns, turn_off_re_match=False): 2153061da546Spatrick """Test that the completion mechanism completes str_input to patterns, 2154061da546Spatrick where patterns could be a pattern-string or a list of pattern-strings""" 2155061da546Spatrick # Patterns should not be None in order to proceed. 2156061da546Spatrick self.assertFalse(patterns is None) 2157061da546Spatrick # And should be either a string or list of strings. Check for list type 2158061da546Spatrick # below, if not, make a list out of the singleton string. If patterns 2159061da546Spatrick # is not a string or not a list of strings, there'll be runtime errors 2160061da546Spatrick # later on. 2161061da546Spatrick if not isinstance(patterns, list): 2162061da546Spatrick patterns = [patterns] 2163061da546Spatrick 2164061da546Spatrick interp = self.dbg.GetCommandInterpreter() 2165061da546Spatrick match_strings = lldb.SBStringList() 2166061da546Spatrick num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) 2167061da546Spatrick common_match = match_strings.GetStringAtIndex(0) 2168061da546Spatrick if num_matches == 0: 2169061da546Spatrick compare_string = str_input 2170061da546Spatrick else: 2171061da546Spatrick if common_match != None and len(common_match) > 0: 2172061da546Spatrick compare_string = str_input + common_match 2173061da546Spatrick else: 2174061da546Spatrick compare_string = "" 2175061da546Spatrick for idx in range(1, num_matches+1): 2176061da546Spatrick compare_string += match_strings.GetStringAtIndex(idx) + "\n" 2177061da546Spatrick 2178061da546Spatrick for p in patterns: 2179061da546Spatrick if turn_off_re_match: 2180061da546Spatrick self.expect( 2181061da546Spatrick compare_string, msg=COMPLETION_MSG( 2182061da546Spatrick str_input, p, match_strings), exe=False, substrs=[p]) 2183061da546Spatrick else: 2184061da546Spatrick self.expect( 2185061da546Spatrick compare_string, msg=COMPLETION_MSG( 2186061da546Spatrick str_input, p, match_strings), exe=False, patterns=[p]) 2187061da546Spatrick 2188061da546Spatrick def completions_match(self, command, completions): 2189061da546Spatrick """Checks that the completions for the given command are equal to the 2190061da546Spatrick given list of completions""" 2191061da546Spatrick interp = self.dbg.GetCommandInterpreter() 2192061da546Spatrick match_strings = lldb.SBStringList() 2193061da546Spatrick interp.HandleCompletion(command, len(command), 0, -1, match_strings) 2194061da546Spatrick # match_strings is a 1-indexed list, so we have to slice... 2195061da546Spatrick self.assertItemsEqual(completions, list(match_strings)[1:], 2196061da546Spatrick "List of returned completion is wrong") 2197061da546Spatrick 2198be691f3bSpatrick def completions_contain(self, command, completions): 2199be691f3bSpatrick """Checks that the completions for the given command contain the given 2200be691f3bSpatrick list of completions.""" 2201be691f3bSpatrick interp = self.dbg.GetCommandInterpreter() 2202be691f3bSpatrick match_strings = lldb.SBStringList() 2203be691f3bSpatrick interp.HandleCompletion(command, len(command), 0, -1, match_strings) 2204be691f3bSpatrick for completion in completions: 2205be691f3bSpatrick # match_strings is a 1-indexed list, so we have to slice... 2206be691f3bSpatrick self.assertIn(completion, list(match_strings)[1:], 2207be691f3bSpatrick "Couldn't find expected completion") 2208be691f3bSpatrick 2209061da546Spatrick def filecheck( 2210061da546Spatrick self, 2211061da546Spatrick command, 2212061da546Spatrick check_file, 2213061da546Spatrick filecheck_options = '', 2214061da546Spatrick expect_cmd_failure = False): 2215061da546Spatrick # Run the command. 2216061da546Spatrick self.runCmd( 2217061da546Spatrick command, 2218061da546Spatrick check=(not expect_cmd_failure), 2219061da546Spatrick msg="FileCheck'ing result of `{0}`".format(command)) 2220061da546Spatrick 2221061da546Spatrick self.assertTrue((not expect_cmd_failure) == self.res.Succeeded()) 2222061da546Spatrick 2223061da546Spatrick # Get the error text if there was an error, and the regular text if not. 2224061da546Spatrick output = self.res.GetOutput() if self.res.Succeeded() \ 2225061da546Spatrick else self.res.GetError() 2226061da546Spatrick 2227061da546Spatrick # Assemble the absolute path to the check file. As a convenience for 2228061da546Spatrick # LLDB inline tests, assume that the check file is a relative path to 2229061da546Spatrick # a file within the inline test directory. 2230061da546Spatrick if check_file.endswith('.pyc'): 2231061da546Spatrick check_file = check_file[:-1] 2232061da546Spatrick check_file_abs = os.path.abspath(check_file) 2233061da546Spatrick 2234061da546Spatrick # Run FileCheck. 2235061da546Spatrick filecheck_bin = configuration.get_filecheck_path() 2236061da546Spatrick if not filecheck_bin: 2237061da546Spatrick self.assertTrue(False, "No valid FileCheck executable specified") 2238061da546Spatrick filecheck_args = [filecheck_bin, check_file_abs] 2239061da546Spatrick if filecheck_options: 2240061da546Spatrick filecheck_args.append(filecheck_options) 2241061da546Spatrick subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) 2242061da546Spatrick cmd_stdout, cmd_stderr = subproc.communicate(input=output) 2243061da546Spatrick cmd_status = subproc.returncode 2244061da546Spatrick 2245061da546Spatrick filecheck_cmd = " ".join(filecheck_args) 2246061da546Spatrick filecheck_trace = """ 2247061da546Spatrick--- FileCheck trace (code={0}) --- 2248061da546Spatrick{1} 2249061da546Spatrick 2250061da546SpatrickFileCheck input: 2251061da546Spatrick{2} 2252061da546Spatrick 2253061da546SpatrickFileCheck output: 2254061da546Spatrick{3} 2255061da546Spatrick{4} 2256061da546Spatrick""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) 2257061da546Spatrick 2258061da546Spatrick trace = cmd_status != 0 or traceAlways 2259061da546Spatrick with recording(self, trace) as sbuf: 2260061da546Spatrick print(filecheck_trace, file=sbuf) 2261061da546Spatrick 2262061da546Spatrick self.assertTrue(cmd_status == 0) 2263061da546Spatrick 2264061da546Spatrick def expect( 2265061da546Spatrick self, 2266*f6aab3d8Srobert string, 2267061da546Spatrick msg=None, 2268061da546Spatrick patterns=None, 2269061da546Spatrick startstr=None, 2270061da546Spatrick endstr=None, 2271061da546Spatrick substrs=None, 2272061da546Spatrick trace=False, 2273061da546Spatrick error=False, 2274dda28197Spatrick ordered=True, 2275061da546Spatrick matching=True, 2276061da546Spatrick exe=True, 2277061da546Spatrick inHistory=False): 2278061da546Spatrick """ 2279061da546Spatrick Similar to runCmd; with additional expect style output matching ability. 2280061da546Spatrick 2281061da546Spatrick Ask the command interpreter to handle the command and then check its 2282061da546Spatrick return status. The 'msg' parameter specifies an informational assert 2283061da546Spatrick message. We expect the output from running the command to start with 2284061da546Spatrick 'startstr', matches the substrings contained in 'substrs', and regexp 2285061da546Spatrick matches the patterns contained in 'patterns'. 2286061da546Spatrick 2287dda28197Spatrick When matching is true and ordered is true, which are both the default, 2288dda28197Spatrick the strings in the substrs array have to appear in the command output 2289dda28197Spatrick in the order in which they appear in the array. 2290dda28197Spatrick 2291061da546Spatrick If the keyword argument error is set to True, it signifies that the API 2292061da546Spatrick client is expecting the command to fail. In this case, the error stream 2293061da546Spatrick from running the command is retrieved and compared against the golden 2294061da546Spatrick input, instead. 2295061da546Spatrick 2296061da546Spatrick If the keyword argument matching is set to False, it signifies that the API 2297061da546Spatrick client is expecting the output of the command not to match the golden 2298061da546Spatrick input. 2299061da546Spatrick 2300*f6aab3d8Srobert Finally, the required argument 'string' represents the lldb command to be 2301061da546Spatrick sent to the command interpreter. In case the keyword argument 'exe' is 2302*f6aab3d8Srobert set to False, the 'string' is treated as a string to be matched/not-matched 2303061da546Spatrick against the golden input. 2304061da546Spatrick """ 2305be691f3bSpatrick # Catch cases where `expect` has been miscalled. Specifically, prevent 2306be691f3bSpatrick # this easy to make mistake: 2307be691f3bSpatrick # self.expect("lldb command", "some substr") 2308be691f3bSpatrick # The `msg` parameter is used only when a failed match occurs. A failed 2309be691f3bSpatrick # match can only occur when one of `patterns`, `startstr`, `endstr`, or 2310be691f3bSpatrick # `substrs` has been given. Thus, if a `msg` is given, it's an error to 2311be691f3bSpatrick # not also provide one of the matcher parameters. 2312be691f3bSpatrick if msg and not (patterns or startstr or endstr or substrs or error): 2313be691f3bSpatrick assert False, "expect() missing a matcher argument" 2314be691f3bSpatrick 2315be691f3bSpatrick # Check `patterns` and `substrs` are not accidentally given as strings. 2316*f6aab3d8Srobert assert not isinstance(patterns, str), \ 2317be691f3bSpatrick "patterns must be a collection of strings" 2318*f6aab3d8Srobert assert not isinstance(substrs, str), \ 2319be691f3bSpatrick "substrs must be a collection of strings" 2320be691f3bSpatrick 2321061da546Spatrick trace = (True if traceAlways else trace) 2322061da546Spatrick 2323061da546Spatrick if exe: 2324061da546Spatrick # First run the command. If we are expecting error, set check=False. 2325061da546Spatrick # Pass the assert message along since it provides more semantic 2326061da546Spatrick # info. 2327061da546Spatrick self.runCmd( 2328*f6aab3d8Srobert string, 2329061da546Spatrick msg=msg, 2330061da546Spatrick trace=( 2331061da546Spatrick True if trace else False), 2332061da546Spatrick check=not error, 2333061da546Spatrick inHistory=inHistory) 2334061da546Spatrick 2335061da546Spatrick # Then compare the output against expected strings. 2336061da546Spatrick output = self.res.GetError() if error else self.res.GetOutput() 2337061da546Spatrick 2338061da546Spatrick # If error is True, the API client expects the command to fail! 2339061da546Spatrick if error: 2340061da546Spatrick self.assertFalse(self.res.Succeeded(), 2341*f6aab3d8Srobert "Command '" + string + "' is expected to fail!") 2342061da546Spatrick else: 2343*f6aab3d8Srobert # No execution required, just compare string against the golden input. 2344*f6aab3d8Srobert if isinstance(string, lldb.SBCommandReturnObject): 2345*f6aab3d8Srobert output = string.GetOutput() 2346061da546Spatrick else: 2347*f6aab3d8Srobert output = string 2348061da546Spatrick with recording(self, trace) as sbuf: 2349061da546Spatrick print("looking at:", output, file=sbuf) 2350061da546Spatrick 2351be691f3bSpatrick expecting_str = "Expecting" if matching else "Not expecting" 2352be691f3bSpatrick def found_str(matched): 2353be691f3bSpatrick return "was found" if matched else "was not found" 2354061da546Spatrick 2355be691f3bSpatrick # To be used as assert fail message and/or trace content 2356be691f3bSpatrick log_lines = [ 2357be691f3bSpatrick "{}:".format("Ran command" if exe else "Checking string"), 2358*f6aab3d8Srobert "\"{}\"".format(string), 2359be691f3bSpatrick # Space out command and output 2360be691f3bSpatrick "", 2361be691f3bSpatrick ] 2362be691f3bSpatrick if exe: 2363be691f3bSpatrick # Newline before output to make large strings more readable 2364be691f3bSpatrick log_lines.append("Got output:\n{}".format(output)) 2365061da546Spatrick 2366be691f3bSpatrick # Assume that we start matched if we want a match 2367be691f3bSpatrick # Meaning if you have no conditions, matching or 2368be691f3bSpatrick # not matching will always pass 2369be691f3bSpatrick matched = matching 2370be691f3bSpatrick 2371be691f3bSpatrick # We will stop checking on first failure 2372061da546Spatrick if startstr: 2373be691f3bSpatrick matched = output.startswith(startstr) 2374be691f3bSpatrick log_lines.append("{} start string: \"{}\" ({})".format( 2375be691f3bSpatrick expecting_str, startstr, found_str(matched))) 2376061da546Spatrick 2377be691f3bSpatrick if endstr and matched == matching: 2378061da546Spatrick matched = output.endswith(endstr) 2379be691f3bSpatrick log_lines.append("{} end string: \"{}\" ({})".format( 2380be691f3bSpatrick expecting_str, endstr, found_str(matched))) 2381061da546Spatrick 2382be691f3bSpatrick if substrs and matched == matching: 2383dda28197Spatrick start = 0 2384061da546Spatrick for substr in substrs: 2385dda28197Spatrick index = output[start:].find(substr) 2386*f6aab3d8Srobert start = start + index + len(substr) if ordered and matching else 0 2387dda28197Spatrick matched = index != -1 2388be691f3bSpatrick log_lines.append("{} sub string: \"{}\" ({})".format( 2389be691f3bSpatrick expecting_str, substr, found_str(matched))) 2390be691f3bSpatrick 2391be691f3bSpatrick if matched != matching: 2392061da546Spatrick break 2393061da546Spatrick 2394be691f3bSpatrick if patterns and matched == matching: 2395061da546Spatrick for pattern in patterns: 2396be691f3bSpatrick matched = re.search(pattern, output) 2397be691f3bSpatrick 2398be691f3bSpatrick pattern_line = "{} regex pattern: \"{}\" ({}".format( 2399be691f3bSpatrick expecting_str, pattern, found_str(matched)) 2400be691f3bSpatrick if matched: 2401be691f3bSpatrick pattern_line += ", matched \"{}\"".format( 2402be691f3bSpatrick matched.group(0)) 2403be691f3bSpatrick pattern_line += ")" 2404be691f3bSpatrick log_lines.append(pattern_line) 2405be691f3bSpatrick 2406be691f3bSpatrick # Convert to bool because match objects 2407be691f3bSpatrick # are True-ish but != True itself 2408be691f3bSpatrick matched = bool(matched) 2409be691f3bSpatrick if matched != matching: 2410061da546Spatrick break 2411061da546Spatrick 2412be691f3bSpatrick # If a check failed, add any extra assert message 2413be691f3bSpatrick if msg is not None and matched != matching: 2414be691f3bSpatrick log_lines.append(msg) 2415be691f3bSpatrick 2416be691f3bSpatrick log_msg = "\n".join(log_lines) 2417be691f3bSpatrick with recording(self, trace) as sbuf: 2418be691f3bSpatrick print(log_msg, file=sbuf) 2419be691f3bSpatrick if matched != matching: 2420be691f3bSpatrick self.fail(log_msg) 2421061da546Spatrick 2422061da546Spatrick def expect_expr( 2423061da546Spatrick self, 2424061da546Spatrick expr, 2425061da546Spatrick result_summary=None, 2426061da546Spatrick result_value=None, 2427061da546Spatrick result_type=None, 2428be691f3bSpatrick result_children=None 2429061da546Spatrick ): 2430061da546Spatrick """ 2431061da546Spatrick Evaluates the given expression and verifies the result. 2432061da546Spatrick :param expr: The expression as a string. 2433061da546Spatrick :param result_summary: The summary that the expression should have. None if the summary should not be checked. 2434061da546Spatrick :param result_value: The value that the expression should have. None if the value should not be checked. 2435061da546Spatrick :param result_type: The type that the expression result should have. None if the type should not be checked. 2436be691f3bSpatrick :param result_children: The expected children of the expression result 2437be691f3bSpatrick as a list of ValueChecks. None if the children shouldn't be checked. 2438061da546Spatrick """ 2439061da546Spatrick self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") 2440061da546Spatrick 2441061da546Spatrick frame = self.frame() 2442dda28197Spatrick options = lldb.SBExpressionOptions() 2443061da546Spatrick 2444dda28197Spatrick # Disable fix-its that tests don't pass by accident. 2445dda28197Spatrick options.SetAutoApplyFixIts(False) 2446061da546Spatrick 2447dda28197Spatrick # Set the usual default options for normal expressions. 2448dda28197Spatrick options.SetIgnoreBreakpoints(True) 2449dda28197Spatrick 2450dda28197Spatrick if self.frame().IsValid(): 2451dda28197Spatrick options.SetLanguage(frame.GuessLanguage()) 2452dda28197Spatrick eval_result = self.frame().EvaluateExpression(expr, options) 2453dda28197Spatrick else: 2454be691f3bSpatrick target = self.target() 2455be691f3bSpatrick # If there is no selected target, run the expression in the dummy 2456be691f3bSpatrick # target. 2457be691f3bSpatrick if not target.IsValid(): 2458be691f3bSpatrick target = self.dbg.GetDummyTarget() 2459be691f3bSpatrick eval_result = target.EvaluateExpression(expr, options) 2460dda28197Spatrick 2461be691f3bSpatrick value_check = ValueCheck(type=result_type, value=result_value, 2462be691f3bSpatrick summary=result_summary, children=result_children) 2463be691f3bSpatrick value_check.check_value(self, eval_result, str(eval_result)) 2464be691f3bSpatrick return eval_result 2465061da546Spatrick 2466be691f3bSpatrick def expect_var_path( 2467be691f3bSpatrick self, 2468be691f3bSpatrick var_path, 2469be691f3bSpatrick summary=None, 2470be691f3bSpatrick value=None, 2471be691f3bSpatrick type=None, 2472be691f3bSpatrick children=None 2473be691f3bSpatrick ): 2474be691f3bSpatrick """ 2475be691f3bSpatrick Evaluates the given variable path and verifies the result. 2476be691f3bSpatrick See also 'frame variable' and SBFrame.GetValueForVariablePath. 2477be691f3bSpatrick :param var_path: The variable path as a string. 2478be691f3bSpatrick :param summary: The summary that the variable should have. None if the summary should not be checked. 2479be691f3bSpatrick :param value: The value that the variable should have. None if the value should not be checked. 2480be691f3bSpatrick :param type: The type that the variable result should have. None if the type should not be checked. 2481be691f3bSpatrick :param children: The expected children of the variable as a list of ValueChecks. 2482be691f3bSpatrick None if the children shouldn't be checked. 2483be691f3bSpatrick """ 2484be691f3bSpatrick self.assertTrue(var_path.strip() == var_path, 2485be691f3bSpatrick "Expression contains trailing/leading whitespace: '" + var_path + "'") 2486061da546Spatrick 2487be691f3bSpatrick frame = self.frame() 2488be691f3bSpatrick eval_result = frame.GetValueForVariablePath(var_path) 2489061da546Spatrick 2490be691f3bSpatrick value_check = ValueCheck(type=type, value=value, 2491be691f3bSpatrick summary=summary, children=children) 2492be691f3bSpatrick value_check.check_value(self, eval_result, str(eval_result)) 2493be691f3bSpatrick return eval_result 2494061da546Spatrick 2495dda28197Spatrick """Assert that an lldb.SBError is in the "success" state.""" 2496dda28197Spatrick def assertSuccess(self, obj, msg=None): 2497dda28197Spatrick if not obj.Success(): 2498dda28197Spatrick error = obj.GetCString() 2499dda28197Spatrick self.fail(self._formatMessage(msg, 2500dda28197Spatrick "'{}' is not success".format(error))) 2501dda28197Spatrick 2502*f6aab3d8Srobert """Assert that a command return object is successful""" 2503*f6aab3d8Srobert def assertCommandReturn(self, obj, msg=None): 2504*f6aab3d8Srobert if not obj.Succeeded(): 2505*f6aab3d8Srobert error = obj.GetError() 2506*f6aab3d8Srobert self.fail(self._formatMessage(msg, 2507*f6aab3d8Srobert "'{}' is not success".format(error))) 2508*f6aab3d8Srobert 2509*f6aab3d8Srobert """Assert two states are equal""" 2510*f6aab3d8Srobert def assertState(self, first, second, msg=None): 2511*f6aab3d8Srobert if first != second: 2512*f6aab3d8Srobert error = "{} ({}) != {} ({})".format( 2513*f6aab3d8Srobert lldbutil.state_type_to_str(first), first, 2514*f6aab3d8Srobert lldbutil.state_type_to_str(second), second) 2515*f6aab3d8Srobert self.fail(self._formatMessage(msg, error)) 2516*f6aab3d8Srobert 2517*f6aab3d8Srobert """Assert two stop reasons are equal""" 2518*f6aab3d8Srobert def assertStopReason(self, first, second, msg=None): 2519*f6aab3d8Srobert if first != second: 2520*f6aab3d8Srobert error = "{} ({}) != {} ({})".format( 2521*f6aab3d8Srobert lldbutil.stop_reason_to_str(first), first, 2522*f6aab3d8Srobert lldbutil.stop_reason_to_str(second), second) 2523*f6aab3d8Srobert self.fail(self._formatMessage(msg, error)) 2524*f6aab3d8Srobert 2525*f6aab3d8Srobert def createTestTarget(self, file_path=None, msg=None, 2526*f6aab3d8Srobert load_dependent_modules=True): 2527be691f3bSpatrick """ 2528be691f3bSpatrick Creates a target from the file found at the given file path. 2529be691f3bSpatrick Asserts that the resulting target is valid. 2530be691f3bSpatrick :param file_path: The file path that should be used to create the target. 2531be691f3bSpatrick The default argument opens the current default test 2532be691f3bSpatrick executable in the current test directory. 2533be691f3bSpatrick :param msg: A custom error message. 2534be691f3bSpatrick """ 2535be691f3bSpatrick if file_path is None: 2536be691f3bSpatrick file_path = self.getBuildArtifact("a.out") 2537be691f3bSpatrick error = lldb.SBError() 2538be691f3bSpatrick triple = "" 2539be691f3bSpatrick platform = "" 2540be691f3bSpatrick target = self.dbg.CreateTarget(file_path, triple, platform, 2541be691f3bSpatrick load_dependent_modules, error) 2542be691f3bSpatrick if error.Fail(): 2543be691f3bSpatrick err = "Couldn't create target for path '{}': {}".format(file_path, 2544be691f3bSpatrick str(error)) 2545be691f3bSpatrick self.fail(self._formatMessage(msg, err)) 2546be691f3bSpatrick 2547be691f3bSpatrick self.assertTrue(target.IsValid(), "Got invalid target without error") 2548be691f3bSpatrick return target 2549be691f3bSpatrick 2550061da546Spatrick # ================================================= 2551061da546Spatrick # Misc. helper methods for debugging test execution 2552061da546Spatrick # ================================================= 2553061da546Spatrick 2554061da546Spatrick def DebugSBValue(self, val): 2555061da546Spatrick """Debug print a SBValue object, if traceAlways is True.""" 2556061da546Spatrick from .lldbutil import value_type_to_str 2557061da546Spatrick 2558061da546Spatrick if not traceAlways: 2559061da546Spatrick return 2560061da546Spatrick 2561061da546Spatrick err = sys.stderr 2562061da546Spatrick err.write(val.GetName() + ":\n") 2563061da546Spatrick err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2564061da546Spatrick err.write('\t' + "ByteSize -> " + 2565061da546Spatrick str(val.GetByteSize()) + '\n') 2566061da546Spatrick err.write('\t' + "NumChildren -> " + 2567061da546Spatrick str(val.GetNumChildren()) + '\n') 2568061da546Spatrick err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2569061da546Spatrick err.write('\t' + "ValueAsUnsigned -> " + 2570061da546Spatrick str(val.GetValueAsUnsigned()) + '\n') 2571061da546Spatrick err.write( 2572061da546Spatrick '\t' + 2573061da546Spatrick "ValueType -> " + 2574061da546Spatrick value_type_to_str( 2575061da546Spatrick val.GetValueType()) + 2576061da546Spatrick '\n') 2577061da546Spatrick err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2578061da546Spatrick err.write('\t' + "IsPointerType -> " + 2579061da546Spatrick str(val.TypeIsPointerType()) + '\n') 2580061da546Spatrick err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2581061da546Spatrick 2582061da546Spatrick def DebugSBType(self, type): 2583061da546Spatrick """Debug print a SBType object, if traceAlways is True.""" 2584061da546Spatrick if not traceAlways: 2585061da546Spatrick return 2586061da546Spatrick 2587061da546Spatrick err = sys.stderr 2588061da546Spatrick err.write(type.GetName() + ":\n") 2589061da546Spatrick err.write('\t' + "ByteSize -> " + 2590061da546Spatrick str(type.GetByteSize()) + '\n') 2591*f6aab3d8Srobert err.write('\t' + "IsAggregateType -> " + 2592*f6aab3d8Srobert str(type.IsAggregateType()) + '\n') 2593061da546Spatrick err.write('\t' + "IsPointerType -> " + 2594061da546Spatrick str(type.IsPointerType()) + '\n') 2595061da546Spatrick err.write('\t' + "IsReferenceType -> " + 2596061da546Spatrick str(type.IsReferenceType()) + '\n') 2597061da546Spatrick 2598061da546Spatrick def DebugPExpect(self, child): 2599061da546Spatrick """Debug the spwaned pexpect object.""" 2600061da546Spatrick if not traceAlways: 2601061da546Spatrick return 2602061da546Spatrick 2603061da546Spatrick print(child) 2604061da546Spatrick 2605061da546Spatrick @classmethod 2606061da546Spatrick def RemoveTempFile(cls, file): 2607061da546Spatrick if os.path.exists(file): 2608061da546Spatrick remove_file(file) 2609061da546Spatrick 2610061da546Spatrick# On Windows, the first attempt to delete a recently-touched file can fail 2611061da546Spatrick# because of a race with antimalware scanners. This function will detect a 2612061da546Spatrick# failure and retry. 2613061da546Spatrick 2614061da546Spatrick 2615061da546Spatrickdef remove_file(file, num_retries=1, sleep_duration=0.5): 2616061da546Spatrick for i in range(num_retries + 1): 2617061da546Spatrick try: 2618061da546Spatrick os.remove(file) 2619061da546Spatrick return True 2620061da546Spatrick except: 2621061da546Spatrick time.sleep(sleep_duration) 2622061da546Spatrick continue 2623061da546Spatrick return False 2624