lldbtest.py revision 2c8d1596ec40c321d6d39c2b32c33fd662b66c11
1"""
2LLDB module which provides the abstract base class of lldb test case.
3
4The concrete subclass can override lldbtest.TesBase in order to inherit the
5common behavior for unitest.TestCase.setUp/tearDown implemented in this file.
6
7The subclass should override the attribute mydir in order for the python runtime
8to locate the individual test cases when running as part of a large test suite
9or when running each test case as a separate python invocation.
10
11./dotest.py provides a test driver which sets up the environment to run the
12entire test suite.  Users who want to run a test case on its own can specify the
13LLDB_TEST and PYTHONPATH environment variables, for example:
14
15$ export LLDB_TEST=$PWD
16$ export PYTHONPATH=/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:$LLDB_TEST:$LLDB_TEST/plugins
17$ echo $LLDB_TEST
18/Volumes/data/lldb/svn/trunk/test
19$ echo $PYTHONPATH
20/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:/Volumes/data/lldb/svn/trunk/test:/Volumes/data/lldb/svn/trunk/test/plugins
21$ python function_types/TestFunctionTypes.py
22.
23----------------------------------------------------------------------
24Ran 1 test in 0.363s
25
26OK
27$ LLDB_COMMAND_TRACE=YES python array_types/TestArrayTypes.py
28
29...
30
31runCmd: breakpoint set -f main.c -l 42
32output: Breakpoint created: 1: file ='main.c', line = 42, locations = 1
33
34runCmd: run
35output: Launching '/Volumes/data/lldb/svn/trunk/test/array_types/a.out'  (x86_64)
36
37...
38
39runCmd: frame variable strings
40output: (char *[4]) strings = {
41  (char *) strings[0] = 0x0000000100000f0c "Hello",
42  (char *) strings[1] = 0x0000000100000f12 "Hola",
43  (char *) strings[2] = 0x0000000100000f17 "Bonjour",
44  (char *) strings[3] = 0x0000000100000f1f "Guten Tag"
45}
46
47runCmd: frame variable char_16
48output: (char [16]) char_16 = {
49  (char) char_16[0] = 'H',
50  (char) char_16[1] = 'e',
51  (char) char_16[2] = 'l',
52  (char) char_16[3] = 'l',
53  (char) char_16[4] = 'o',
54  (char) char_16[5] = ' ',
55  (char) char_16[6] = 'W',
56  (char) char_16[7] = 'o',
57  (char) char_16[8] = 'r',
58  (char) char_16[9] = 'l',
59  (char) char_16[10] = 'd',
60  (char) char_16[11] = '\n',
61  (char) char_16[12] = '\0',
62  (char) char_16[13] = '\0',
63  (char) char_16[14] = '\0',
64  (char) char_16[15] = '\0'
65}
66
67runCmd: frame variable ushort_matrix
68output: (unsigned short [2][3]) ushort_matrix = {
69  (unsigned short [3]) ushort_matrix[0] = {
70    (unsigned short) ushort_matrix[0][0] = 0x0001,
71    (unsigned short) ushort_matrix[0][1] = 0x0002,
72    (unsigned short) ushort_matrix[0][2] = 0x0003
73  },
74  (unsigned short [3]) ushort_matrix[1] = {
75    (unsigned short) ushort_matrix[1][0] = 0x000b,
76    (unsigned short) ushort_matrix[1][1] = 0x0016,
77    (unsigned short) ushort_matrix[1][2] = 0x0021
78  }
79}
80
81runCmd: frame variable long_6
82output: (long [6]) long_6 = {
83  (long) long_6[0] = 1,
84  (long) long_6[1] = 2,
85  (long) long_6[2] = 3,
86  (long) long_6[3] = 4,
87  (long) long_6[4] = 5,
88  (long) long_6[5] = 6
89}
90
91.
92----------------------------------------------------------------------
93Ran 1 test in 0.349s
94
95OK
96$
97"""
98
99import os, sys, traceback
100import re
101from subprocess import *
102import StringIO
103import time
104import types
105import unittest2
106import lldb
107
108# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables
109# LLDB_COMMAND_TRACE and LLDB_NO_CLEANUP are set from '-t' and '-r dir' options.
110
111# By default, traceAlways is False.
112if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES":
113    traceAlways = True
114else:
115    traceAlways = False
116
117# By default, doCleanup is True.
118if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"]=="NO":
119    doCleanup = False
120else:
121    doCleanup = True
122
123
124#
125# Some commonly used assert messages.
126#
127
128COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected"
129
130CURRENT_EXECUTABLE_SET = "Current executable set successfully"
131
132PROCESS_IS_VALID = "Process is valid"
133
134PROCESS_KILLED = "Process is killed successfully"
135
136RUN_SUCCEEDED = "Process is launched successfully"
137
138RUN_COMPLETED = "Process exited successfully"
139
140BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly"
141
142BREAKPOINT_CREATED = "Breakpoint created successfully"
143
144BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
145
146BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1"
147
148BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2"
149
150BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3"
151
152STEP_OUT_SUCCEEDED = "Thread step-out succeeded"
153
154STOPPED_DUE_TO_BREAKPOINT = "Process state is stopped due to breakpoint"
155
156STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition"
157
158STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal"
159
160STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
161
162DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
163
164VALID_BREAKPOINT = "Got a valid breakpoint"
165
166VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"
167
168VALID_FILESPEC = "Got a valid filespec"
169
170VALID_PROCESS = "Got a valid process"
171
172VALID_TARGET = "Got a valid target"
173
174VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
175
176
177#
178# And a generic "Command '%s' returns successfully" message generator.
179#
180def CMD_MSG(str, exe):
181    if exe:
182        return "Command '%s' returns successfully" % str
183    else:
184        return "'%s' compares successfully" % str
185
186#
187# And a generic "Value of setting '%s' is correct" message generator.
188#
189def SETTING_MSG(setting):
190    return "Value of setting '%s' is correct" % setting
191
192#
193# Returns an env variable array from the os.environ map object.
194#
195def EnvArray():
196    return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values())
197
198def line_number(filename, string_to_match):
199    """Helper function to return the line number of the first matched string."""
200    with open(filename, 'r') as f:
201        for i, line in enumerate(f):
202            if line.find(string_to_match) != -1:
203                # Found our match.
204                return i+1
205    return -1
206
207def pointer_size():
208    """Return the pointer size of the host system."""
209    import ctypes
210    a_pointer = ctypes.c_void_p(0xffff)
211    return 8 * ctypes.sizeof(a_pointer)
212
213
214class recording(StringIO.StringIO):
215    """
216    A nice little context manager for recording the debugger interactions into
217    our session object.  If trace flag is ON, it also emits the interactions
218    into the stderr.
219    """
220    def __init__(self, test, trace):
221        """Create a StringIO instance; record the session obj and trace flag."""
222        StringIO.StringIO.__init__(self)
223        self.session = test.session if test else None
224        self.trace = trace
225
226    def __enter__(self):
227        """
228        Context management protocol on entry to the body of the with statement.
229        Just return the StringIO object.
230        """
231        return self
232
233    def __exit__(self, type, value, tb):
234        """
235        Context management protocol on exit from the body of the with statement.
236        If trace is ON, it emits the recordings into stderr.  Always add the
237        recordings to our session object.  And close the StringIO object, too.
238        """
239        if self.trace:
240            print >> sys.stderr, self.getvalue()
241        if self.session:
242            print >> self.session, self.getvalue()
243        self.close()
244
245# From 2.7's subprocess.check_output() convenience function.
246def system(*popenargs, **kwargs):
247    r"""Run command with arguments and return its output as a byte string.
248
249    If the exit code was non-zero it raises a CalledProcessError.  The
250    CalledProcessError object will have the return code in the returncode
251    attribute and output in the output attribute.
252
253    The arguments are the same as for the Popen constructor.  Example:
254
255    >>> check_output(["ls", "-l", "/dev/null"])
256    'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'
257
258    The stdout argument is not allowed as it is used internally.
259    To capture standard error in the result, use stderr=STDOUT.
260
261    >>> check_output(["/bin/sh", "-c",
262    ...               "ls -l non_existent_file ; exit 0"],
263    ...              stderr=STDOUT)
264    'ls: non_existent_file: No such file or directory\n'
265    """
266
267    # Assign the sender object to variable 'test' and remove it from kwargs.
268    test = kwargs.pop('sender', None)
269
270    if 'stdout' in kwargs:
271        raise ValueError('stdout argument not allowed, it will be overridden.')
272    process = Popen(stdout=PIPE, *popenargs, **kwargs)
273    output, error = process.communicate()
274    retcode = process.poll()
275
276    with recording(test, traceAlways) as sbuf:
277        if isinstance(popenargs, types.StringTypes):
278            args = [popenargs]
279        else:
280            args = list(popenargs)
281        print >> sbuf
282        print >> sbuf, "os command:", args
283        print >> sbuf, "stdout:", output
284        print >> sbuf, "stderr:", error
285        print >> sbuf, "retcode:", retcode
286        print >> sbuf
287
288    if retcode:
289        cmd = kwargs.get("args")
290        if cmd is None:
291            cmd = popenargs[0]
292        raise CalledProcessError(retcode, cmd)
293    return output
294
295def getsource_if_available(obj):
296    """
297    Return the text of the source code for an object if available.  Otherwise,
298    a print representation is returned.
299    """
300    import inspect
301    try:
302        return inspect.getsource(obj)
303    except:
304        return repr(obj)
305
306class TestBase(unittest2.TestCase):
307    """
308    This abstract base class is meant to be subclassed.  It provides default
309    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
310    among other things.
311
312    Important things for test class writers:
313
314        - Overwrite the mydir class attribute, otherwise your test class won't
315          run.  It specifies the relative directory to the top level 'test' so
316          the test harness can change to the correct working directory before
317          running your test.
318
319        - The setUp method sets up things to facilitate subsequent interactions
320          with the debugger as part of the test.  These include:
321              - create/get a debugger set with synchronous mode (self.dbg)
322              - get the command interpreter from with the debugger (self.ci)
323              - create a result object for use with the command interpreter
324                (self.result)
325              - plus other stuffs
326
327        - The tearDown method tries to perform some necessary cleanup on behalf
328          of the test to return the debugger to a good state for the next test.
329          These include:
330              - execute any tearDown hooks registered by the test method with
331                TestBase.addTearDownHook(); examples can be found in
332                settings/TestSettings.py
333              - kill the inferior process launched during the test method
334                    - if by 'run' or 'process launch' command, 'process kill'
335                      command is used
336                    - if the test method uses LLDB Python API to launch process,
337                      it should assign the process object to self.process; that
338                      way, tearDown will use self.process.Kill() on the object
339              - perform build cleanup before running the next test method in the
340                same test class; examples of registering for this service can be
341                found in types/TestIntegerTypes.py with the call:
342                    - self.setTearDownCleanup(dictionary=d)
343
344        - Similarly setUpClass and tearDownClass perform classwise setup and
345          teardown fixtures.  The tearDownClass method invokes a default build
346          cleanup for the entire test class;  also, subclasses can implement the
347          classmethod classCleanup(cls) to perform special class cleanup action.
348
349        - The instance methods runCmd and expect are used heavily by existing
350          test cases to send a command to the command interpreter and to perform
351          string/pattern matching on the output of such command execution.  The
352          expect method also provides a mode to peform string/pattern matching
353          without running a command.
354
355        - The build methods buildDefault, buildDsym, and buildDwarf are used to
356          build the binaries used during a particular test scenario.  A plugin
357          should be provided for the sys.platform running the test suite.  The
358          Mac OS X implementation is located in plugins/darwin.py.
359
360    """
361
362    @classmethod
363    def skipLongRunningTest(cls):
364        """
365        By default, we skip long running test case.
366        This can be overridden by passing '-l' to the test driver (dotest.py).
367        """
368        if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]:
369            return False
370        else:
371            return True
372
373    # The concrete subclass should override this attribute.
374    mydir = None
375
376    # State pertaining to the inferior process, if any.
377    # This reflects inferior process started through the command interface with
378    # either the lldb "run" or "process launch" command.
379    # See also self.runCmd().
380    runStarted = False
381
382    # Maximum allowed attempts when launching the inferior process.
383    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
384    maxLaunchCount = 3;
385
386    # Time to wait before the next launching attempt in second(s).
387    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
388    timeWait = 1.0;
389
390    # Keep track of the old current working directory.
391    oldcwd = None
392
393    @classmethod
394    def setUpClass(cls):
395        """
396        Python unittest framework class setup fixture.
397        Do current directory manipulation.
398        """
399
400        # Fail fast if 'mydir' attribute is not overridden.
401        if not cls.mydir or len(cls.mydir) == 0:
402            raise Exception("Subclasses must override the 'mydir' attribute.")
403        # Save old working directory.
404        cls.oldcwd = os.getcwd()
405
406        # Change current working directory if ${LLDB_TEST} is defined.
407        # See also dotest.py which sets up ${LLDB_TEST}.
408        if ("LLDB_TEST" in os.environ):
409            if traceAlways:
410                print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir)
411            os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir))
412
413    @classmethod
414    def tearDownClass(cls):
415        """
416        Python unittest framework class teardown fixture.
417        Do class-wide cleanup.
418        """
419
420        if doCleanup:
421            # First, let's do the platform-specific cleanup.
422            module = __import__(sys.platform)
423            if not module.cleanup():
424                raise Exception("Don't know how to do cleanup")
425
426            # Subclass might have specific cleanup function defined.
427            if getattr(cls, "classCleanup", None):
428                if traceAlways:
429                    print >> sys.stderr, "Call class-specific cleanup function for class:", cls
430                try:
431                    cls.classCleanup()
432                except:
433                    exc_type, exc_value, exc_tb = sys.exc_info()
434                    traceback.print_exception(exc_type, exc_value, exc_tb)
435
436        # Restore old working directory.
437        if traceAlways:
438            print >> sys.stderr, "Restore dir to:", cls.oldcwd
439        os.chdir(cls.oldcwd)
440
441    def setUp(self):
442        #import traceback
443        #traceback.print_stack()
444
445        if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and
446            os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'):
447            time.sleep(0.5)
448
449        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
450            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
451
452        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
453            self.timeWait = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
454
455        # Create the debugger instance if necessary.
456        try:
457            self.dbg = lldb.DBG
458        except AttributeError:
459            self.dbg = lldb.SBDebugger.Create()
460
461        if not self.dbg.IsValid():
462            raise Exception('Invalid debugger instance')
463
464        # We want our debugger to be synchronous.
465        self.dbg.SetAsync(False)
466
467        # There is no process associated with the debugger as yet.
468        # See also self.tearDown() where it checks whether self.process has a
469        # valid reference and calls self.process.Kill() to kill the process.
470        self.process = None
471
472        # Retrieve the associated command interpreter instance.
473        self.ci = self.dbg.GetCommandInterpreter()
474        if not self.ci:
475            raise Exception('Could not get the command interpreter')
476
477        # And the result object.
478        self.res = lldb.SBCommandReturnObject()
479
480        # These are for customized teardown cleanup.
481        self.dict = None
482        self.doTearDownCleanup = False
483
484        # Create a string buffer to record the session info, to be dumped into a
485        # test case specific file if test failure is encountered.
486        self.session = StringIO.StringIO()
487
488        # Optimistically set __errored__, __failed__, __expected__ to False
489        # initially.  If the test errored/failed, the session info
490        # (self.session) is then dumped into a session specific file for
491        # diagnosis.
492        self.__errored__ = False
493        self.__failed__ = False
494        self.__expected__ = False
495
496        # See addTearDownHook(self, hook) which allows the client to add a hook
497        # function to be run during tearDown() time.
498        self.hooks = []
499
500    def markError(self):
501        """Callback invoked when we (the test case instance) errored."""
502        self.__errored__ = True
503        with recording(self, False) as sbuf:
504            # False because there's no need to write "ERROR" to the stderr twice.
505            # Once by the Python unittest framework, and a second time by us.
506            print >> sbuf, "ERROR"
507
508    def markFailure(self):
509        """Callback invoked when we (the test case instance) failed."""
510        self.__failed__ = True
511        with recording(self, False) as sbuf:
512            # False because there's no need to write "FAIL" to the stderr twice.
513            # Once by the Python unittest framework, and a second time by us.
514            print >> sbuf, "FAIL"
515
516    def markExpectedFailure(self):
517        """Callback invoked when an expected failure/error occurred."""
518        self.__expected__ = True
519        with recording(self, False) as sbuf:
520            # False because there's no need to write "expected failure" to the
521            # stderr twice.
522            # Once by the Python unittest framework, and a second time by us.
523            print >> sbuf, "expected failure"
524
525    def dumpSessionInfo(self):
526        """
527        Dump the debugger interactions leading to a test error/failure.  This
528        allows for more convenient postmortem analysis.
529
530        See also LLDBTestResult (dotest.py) which is a singlton class derived
531        from TextTestResult and overwrites addError, addFailure, and
532        addExpectedFailure methods to allow us to to mark the test instance as
533        such.
534        """
535
536        # We are here because self.tearDown() detected that this test instance
537        # either errored or failed.  The lldb.test_result singleton contains
538        # two lists (erros and failures) which get populated by the unittest
539        # framework.  Look over there for stack trace information.
540        #
541        # The lists contain 2-tuples of TestCase instances and strings holding
542        # formatted tracebacks.
543        #
544        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
545        if self.__errored__:
546            pairs = lldb.test_result.errors
547        elif self.__failed__:
548            pairs = lldb.test_result.failures
549        elif self.__expected__:
550            pairs = lldb.test_result.expectedFailures
551        else:
552            # Simply return, there's no session info to dump!
553            return
554
555        for test, traceback in pairs:
556            if test is self:
557                print >> self.session, traceback
558
559        dname = os.path.join(os.environ["LLDB_TEST"],
560                             os.environ["LLDB_SESSION_DIRNAME"])
561        if not os.path.isdir(dname):
562            os.mkdir(dname)
563        fname = os.path.join(dname, "%s.log" % self.id())
564        with open(fname, "w") as f:
565            import datetime
566            print >> f, "Session info generated @", datetime.datetime.now().ctime()
567            print >> f, self.session.getvalue()
568
569    def setTearDownCleanup(self, dictionary=None):
570        """Register a cleanup action at tearDown() time with a dictinary"""
571        self.dict = dictionary
572        self.doTearDownCleanup = True
573
574    def addTearDownHook(self, hook):
575        """
576        Add a function to be run during tearDown() time.
577
578        Hooks are executed in a first come first serve manner.
579        """
580        if callable(hook):
581            with recording(self, traceAlways) as sbuf:
582                print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook)
583            self.hooks.append(hook)
584
585    def tearDown(self):
586        #import traceback
587        #traceback.print_stack()
588
589        # Check and run any hook functions.
590        for hook in self.hooks:
591            with recording(self, traceAlways) as sbuf:
592                print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook)
593            hook()
594
595        # Terminate the current process being debugged, if any.
596        if self.runStarted:
597            self.runCmd("process kill", PROCESS_KILLED, check=False)
598        elif self.process and self.process.IsValid():
599            rc = self.invoke(self.process, "Kill")
600            self.assertTrue(rc.Success(), PROCESS_KILLED)
601            del self.process
602
603        del self.dbg
604        del self.hooks
605
606        # Perform registered teardown cleanup.
607        if doCleanup and self.doTearDownCleanup:
608            module = __import__(sys.platform)
609            if not module.cleanup(self, dictionary=self.dict):
610                raise Exception("Don't know how to do cleanup")
611
612        # We always dump the session infos for failures/errors.
613        self.dumpSessionInfo()
614
615    def runCmd(self, cmd, msg=None, check=True, trace=False, setCookie=True):
616        """
617        Ask the command interpreter to handle the command and then check its
618        return status.
619        """
620        # Fail fast if 'cmd' is not meaningful.
621        if not cmd or len(cmd) == 0:
622            raise Exception("Bad 'cmd' parameter encountered")
623
624        trace = (True if traceAlways else trace)
625
626        running = (cmd.startswith("run") or cmd.startswith("process launch"))
627
628        for i in range(self.maxLaunchCount if running else 1):
629            self.ci.HandleCommand(cmd, self.res)
630
631            with recording(self, trace) as sbuf:
632                print >> sbuf, "runCmd:", cmd
633                if not check:
634                    print >> sbuf, "check of return status not required"
635                if self.res.Succeeded():
636                    print >> sbuf, "output:", self.res.GetOutput()
637                else:
638                    print >> sbuf, "runCmd failed!"
639                    print >> sbuf, self.res.GetError()
640
641            if running:
642                # For process launch, wait some time before possible next try.
643                time.sleep(self.timeWait)
644
645            if self.res.Succeeded():
646                break
647            elif running:
648                with recording(self, True) as sbuf:
649                    print >> sbuf, "Command '" + cmd + "' failed!"
650
651        # Modify runStarted only if "run" or "process launch" was encountered.
652        if running:
653            self.runStarted = running and setCookie
654
655        if check:
656            self.assertTrue(self.res.Succeeded(),
657                            msg if msg else CMD_MSG(cmd, True))
658
659    def expect(self, str, msg=None, patterns=None, startstr=None, substrs=None, trace=False, error=False, matching=True, exe=True):
660        """
661        Similar to runCmd; with additional expect style output matching ability.
662
663        Ask the command interpreter to handle the command and then check its
664        return status.  The 'msg' parameter specifies an informational assert
665        message.  We expect the output from running the command to start with
666        'startstr', matches the substrings contained in 'substrs', and regexp
667        matches the patterns contained in 'patterns'.
668
669        If the keyword argument error is set to True, it signifies that the API
670        client is expecting the command to fail.  In this case, the error stream
671        from running the command is retrieved and compared against the golden
672        input, instead.
673
674        If the keyword argument matching is set to False, it signifies that the API
675        client is expecting the output of the command not to match the golden
676        input.
677
678        Finally, the required argument 'str' represents the lldb command to be
679        sent to the command interpreter.  In case the keyword argument 'exe' is
680        set to False, the 'str' is treated as a string to be matched/not-matched
681        against the golden input.
682        """
683        trace = (True if traceAlways else trace)
684
685        if exe:
686            # First run the command.  If we are expecting error, set check=False.
687            # Pass the assert message along since it provides more semantic info.
688            self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error)
689
690            # Then compare the output against expected strings.
691            output = self.res.GetError() if error else self.res.GetOutput()
692
693            # If error is True, the API client expects the command to fail!
694            if error:
695                self.assertFalse(self.res.Succeeded(),
696                                 "Command '" + str + "' is expected to fail!")
697        else:
698            # No execution required, just compare str against the golden input.
699            output = str
700            with recording(self, trace) as sbuf:
701                print >> sbuf, "looking at:", output
702
703        # The heading says either "Expecting" or "Not expecting".
704        heading = "Expecting" if matching else "Not expecting"
705
706        # Start from the startstr, if specified.
707        # If there's no startstr, set the initial state appropriately.
708        matched = output.startswith(startstr) if startstr else (True if matching else False)
709
710        if startstr:
711            with recording(self, trace) as sbuf:
712                print >> sbuf, "%s start string: %s" % (heading, startstr)
713                print >> sbuf, "Matched" if matched else "Not matched"
714
715        # Look for sub strings, if specified.
716        keepgoing = matched if matching else not matched
717        if substrs and keepgoing:
718            for str in substrs:
719                matched = output.find(str) != -1
720                with recording(self, trace) as sbuf:
721                    print >> sbuf, "%s sub string: %s" % (heading, str)
722                    print >> sbuf, "Matched" if matched else "Not matched"
723                keepgoing = matched if matching else not matched
724                if not keepgoing:
725                    break
726
727        # Search for regular expression patterns, if specified.
728        keepgoing = matched if matching else not matched
729        if patterns and keepgoing:
730            for pattern in patterns:
731                # Match Objects always have a boolean value of True.
732                matched = bool(re.search(pattern, output))
733                with recording(self, trace) as sbuf:
734                    print >> sbuf, "%s pattern: %s" % (heading, pattern)
735                    print >> sbuf, "Matched" if matched else "Not matched"
736                keepgoing = matched if matching else not matched
737                if not keepgoing:
738                    break
739
740        self.assertTrue(matched if matching else not matched,
741                        msg if msg else CMD_MSG(str, exe))
742
743    def invoke(self, obj, name, trace=False):
744        """Use reflection to call a method dynamically with no argument."""
745        trace = (True if traceAlways else trace)
746
747        method = getattr(obj, name)
748        import inspect
749        self.assertTrue(inspect.ismethod(method),
750                        name + "is a method name of object: " + str(obj))
751        result = method()
752        with recording(self, trace) as sbuf:
753            print >> sbuf, str(method) + ":",  result
754        return result
755
756    def breakAfterLaunch(self, process, func, trace=False):
757        """
758        Perform some dancees after LaunchProcess() to break at func name.
759
760        Return True if we can successfully break at the func name in due time.
761        """
762        trace = (True if traceAlways else trace)
763
764        count = 0
765        while True:
766            # The stop reason of the thread should be breakpoint.
767            thread = process.GetThreadAtIndex(0)
768            SR = thread.GetStopReason()
769            with recording(self, trace) as sbuf:
770                print >> sbuf, "StopReason =", StopReasonString(SR)
771
772            if SR == StopReasonEnum("Breakpoint"):
773                frame = thread.GetFrameAtIndex(0)
774                name = frame.GetFunction().GetName()
775                with recording(self, trace) as sbuf:
776                    print >> sbuf, "function =", name
777                if (name == func):
778                    # We got what we want; now break out of the loop.
779                    return True
780
781            # The inferior is in a transient state; continue the process.
782            time.sleep(1.0)
783            with recording(self, trace) as sbuf:
784                print >> sbuf, "Continuing the process:", process
785            process.Continue()
786
787            count = count + 1
788            if count == 15:
789                with recording(self, trace) as sbuf:
790                    print >> sbuf, "Reached 15 iterations, giving up..."
791                # Enough iterations already, break out of the loop.
792                return False
793
794            # End of while loop.
795
796
797    def buildDefault(self, architecture=None, compiler=None, dictionary=None):
798        """Platform specific way to build the default binaries."""
799        module = __import__(sys.platform)
800        if not module.buildDefault(self, architecture, compiler, dictionary):
801            raise Exception("Don't know how to build default binary")
802
803    def buildDsym(self, architecture=None, compiler=None, dictionary=None):
804        """Platform specific way to build binaries with dsym info."""
805        module = __import__(sys.platform)
806        if not module.buildDsym(self, architecture, compiler, dictionary):
807            raise Exception("Don't know how to build binary with dsym")
808
809    def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
810        """Platform specific way to build binaries with dwarf maps."""
811        module = __import__(sys.platform)
812        if not module.buildDwarf(self, architecture, compiler, dictionary):
813            raise Exception("Don't know how to build binary with dwarf")
814
815    def DebugSBValue(self, frame, val):
816        """Debug print a SBValue object, if traceAlways is True."""
817        from lldbutil import ValueTypeString
818
819        if not traceAlways:
820            return
821
822        err = sys.stderr
823        err.write(val.GetName() + ":\n")
824        err.write('\t' + "TypeName      -> " + val.GetTypeName()            + '\n')
825        err.write('\t' + "ByteSize      -> " + str(val.GetByteSize())       + '\n')
826        err.write('\t' + "NumChildren   -> " + str(val.GetNumChildren())    + '\n')
827        err.write('\t' + "Value         -> " + str(val.GetValue(frame))     + '\n')
828        err.write('\t' + "ValueType     -> " + ValueTypeString(val.GetValueType()) + '\n')
829        err.write('\t' + "Summary       -> " + str(val.GetSummary(frame))   + '\n')
830        err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n')
831        err.write('\t' + "Location      -> " + val.GetLocation(frame)       + '\n')
832
833