lldbtest.py revision 73a8710e6c7bceda0abeacea054c4aa6d5572d44
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_SIGNAL = "Process state is stopped due to signal"
157
158STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
159
160DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
161
162VALID_BREAKPOINT = "Got a valid breakpoint"
163
164VALID_FILESPEC = "Got a valid filespec"
165
166VALID_PROCESS = "Got a valid process"
167
168VALID_TARGET = "Got a valid target"
169
170VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
171
172
173#
174# And a generic "Command '%s' returns successfully" message generator.
175#
176def CMD_MSG(str, exe):
177    if exe:
178        return "Command '%s' returns successfully" % str
179    else:
180        return "'%s' compares successfully" % str
181
182#
183# And a generic "Value of setting '%s' is correct" message generator.
184#
185def SETTING_MSG(setting):
186    return "Value of setting '%s' is correct" % setting
187
188#
189# Returns an env variable array from the os.environ map object.
190#
191def EnvArray():
192    return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values())
193
194def line_number(filename, string_to_match):
195    """Helper function to return the line number of the first matched string."""
196    with open(filename, 'r') as f:
197        for i, line in enumerate(f):
198            if line.find(string_to_match) != -1:
199                # Found our match.
200                return i+1
201    return -1
202
203def pointer_size():
204    """Return the pointer size of the host system."""
205    import ctypes
206    a_pointer = ctypes.c_void_p(0xffff)
207    return 8 * ctypes.sizeof(a_pointer)
208
209
210class recording(StringIO.StringIO):
211    """
212    A nice little context manager for recording the debugger interactions into
213    our session object.  If trace flag is ON, it also emits the interactions
214    into the stderr.
215    """
216    def __init__(self, test, trace):
217        """Create a StringIO instance; record the session obj and trace flag."""
218        StringIO.StringIO.__init__(self)
219        self.session = test.session if test else None
220        self.trace = trace
221
222    def __enter__(self):
223        """
224        Context management protocol on entry to the body of the with statement.
225        Just return the StringIO object.
226        """
227        return self
228
229    def __exit__(self, type, value, tb):
230        """
231        Context management protocol on exit from the body of the with statement.
232        If trace is ON, it emits the recordings into stderr.  Always add the
233        recordings to our session object.  And close the StringIO object, too.
234        """
235        if self.trace:
236            print >> sys.stderr, self.getvalue()
237        if self.session:
238            print >> self.session, self.getvalue()
239        self.close()
240
241# From 2.7's subprocess.check_output() convenience function.
242def system(*popenargs, **kwargs):
243    r"""Run command with arguments and return its output as a byte string.
244
245    If the exit code was non-zero it raises a CalledProcessError.  The
246    CalledProcessError object will have the return code in the returncode
247    attribute and output in the output attribute.
248
249    The arguments are the same as for the Popen constructor.  Example:
250
251    >>> check_output(["ls", "-l", "/dev/null"])
252    'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'
253
254    The stdout argument is not allowed as it is used internally.
255    To capture standard error in the result, use stderr=STDOUT.
256
257    >>> check_output(["/bin/sh", "-c",
258    ...               "ls -l non_existent_file ; exit 0"],
259    ...              stderr=STDOUT)
260    'ls: non_existent_file: No such file or directory\n'
261    """
262
263    # Assign the sender object to variable 'test' and remove it from kwargs.
264    test = kwargs.pop('sender', None)
265
266    if 'stdout' in kwargs:
267        raise ValueError('stdout argument not allowed, it will be overridden.')
268    process = Popen(stdout=PIPE, *popenargs, **kwargs)
269    output, error = process.communicate()
270    retcode = process.poll()
271
272    with recording(test, traceAlways) as sbuf:
273        if isinstance(popenargs, types.StringTypes):
274            args = [popenargs]
275        else:
276            args = list(popenargs)
277        print >> sbuf
278        print >> sbuf, "os command:", args
279        print >> sbuf, "stdout:", output
280        print >> sbuf, "stderr:", error
281        print >> sbuf, "retcode:", retcode
282        print >> sbuf
283
284    if retcode:
285        cmd = kwargs.get("args")
286        if cmd is None:
287            cmd = popenargs[0]
288        raise CalledProcessError(retcode, cmd)
289    return output
290
291class TestBase(unittest2.TestCase):
292    """This LLDB abstract base class is meant to be subclassed."""
293
294    @classmethod
295    def skipLongRunningTest(cls):
296        """
297        By default, we skip long running test case.
298        This can be overridden by passing '-l' to the test driver (dotest.py).
299        """
300        if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]:
301            return False
302        else:
303            return True
304
305    # The concrete subclass should override this attribute.
306    mydir = None
307
308    # State pertaining to the inferior process, if any.
309    # This reflects inferior process started through the command interface with
310    # either the lldb "run" or "process launch" command.
311    # See also self.runCmd().
312    runStarted = False
313
314    # Maximum allowed attempts when launching the inferior process.
315    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
316    maxLaunchCount = 3;
317
318    # Time to wait before the next launching attempt in second(s).
319    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
320    timeWait = 1.0;
321
322    # Keep track of the old current working directory.
323    oldcwd = None
324
325    @classmethod
326    def setUpClass(cls):
327        """
328        Python unittest framework class setup fixture.
329        Do current directory manipulation.
330        """
331
332        # Fail fast if 'mydir' attribute is not overridden.
333        if not cls.mydir or len(cls.mydir) == 0:
334            raise Exception("Subclasses must override the 'mydir' attribute.")
335        # Save old working directory.
336        cls.oldcwd = os.getcwd()
337
338        # Change current working directory if ${LLDB_TEST} is defined.
339        # See also dotest.py which sets up ${LLDB_TEST}.
340        if ("LLDB_TEST" in os.environ):
341            if traceAlways:
342                print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir)
343            os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir))
344
345    @classmethod
346    def tearDownClass(cls):
347        """
348        Python unittest framework class teardown fixture.
349        Do class-wide cleanup.
350        """
351
352        if doCleanup:
353            # First, let's do the platform-specific cleanup.
354            module = __import__(sys.platform)
355            if not module.cleanup():
356                raise Exception("Don't know how to do cleanup")
357
358            # Subclass might have specific cleanup function defined.
359            if getattr(cls, "classCleanup", None):
360                if traceAlways:
361                    print >> sys.stderr, "Call class-specific cleanup function for class:", cls
362                try:
363                    cls.classCleanup()
364                except:
365                    exc_type, exc_value, exc_tb = sys.exc_info()
366                    traceback.print_exception(exc_type, exc_value, exc_tb)
367
368        # Restore old working directory.
369        if traceAlways:
370            print >> sys.stderr, "Restore dir to:", cls.oldcwd
371        os.chdir(cls.oldcwd)
372
373    def setUp(self):
374        #import traceback
375        #traceback.print_stack()
376
377        if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and
378            os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'):
379            time.sleep(0.5)
380
381        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
382            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
383
384        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
385            self.timeWait = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
386
387        # Create the debugger instance if necessary.
388        try:
389            self.dbg = lldb.DBG
390        except AttributeError:
391            self.dbg = lldb.SBDebugger.Create()
392
393        if not self.dbg.IsValid():
394            raise Exception('Invalid debugger instance')
395
396        # We want our debugger to be synchronous.
397        self.dbg.SetAsync(False)
398
399        # There is no process associated with the debugger as yet.
400        # See also self.tearDown() where it checks whether self.process has a
401        # valid reference and calls self.process.Kill() to kill the process.
402        self.process = None
403
404        # Retrieve the associated command interpreter instance.
405        self.ci = self.dbg.GetCommandInterpreter()
406        if not self.ci:
407            raise Exception('Could not get the command interpreter')
408
409        # And the result object.
410        self.res = lldb.SBCommandReturnObject()
411
412        # These are for customized teardown cleanup.
413        self.dict = None
414        self.doTearDownCleanup = False
415
416        # Create a string buffer to record the session info, to be dumped into a
417        # test case specific file if test failure is encountered.
418        self.session = StringIO.StringIO()
419
420        # Optimistically set self.__errored__ and self.__failed__ to False
421        # initially.  If the test errored/failed, the session info
422        # (self.session) is then dumped into a session specific file for
423        # diagnosis.
424        self.__errored__ = False
425        self.__failed__ = False
426
427        # See addTearDownHook(self, hook) which allows the client to add a hook
428        # function to be run during tearDown() time.
429        self.hooks = []
430
431    def markError(self):
432        """Callback invoked when we (the test case instance) errored."""
433        self.__errored__ = True
434        with recording(self, False) as sbuf:
435            # False because there's no need to write "ERROR" to the stderr twice.
436            # Once by the Python unittest framework, and a second time by us.
437            print >> sbuf, "ERROR"
438
439    def markFailure(self):
440        """Callback invoked when we (the test case instance) failed."""
441        self.__failed__ = True
442        with recording(self, False) as sbuf:
443            # False because there's no need to write "FAIL" to the stderr twice.
444            # Once by the Python unittest framework, and a second time by us.
445            print >> sbuf, "FAIL"
446
447    def dumpSessionInfo(self):
448        """
449        Dump the debugger interactions leading to a test error/failure.  This
450        allows for more convenient postmortem analysis.
451        """
452        for test, err in lldb.test_result.errors:
453            if test is self:
454                print >> self.session, err
455        for test, err in lldb.test_result.failures:
456            if test is self:
457                print >> self.session, err
458
459        dname = os.path.join(os.environ["LLDB_TEST"],
460                             os.environ["LLDB_TIMESTAMP"])
461        if not os.path.isdir(dname):
462            os.mkdir(dname)
463        fname = os.path.join(dname, "%s.log" % self.id())
464        with open(fname, "w") as f:
465            print >> f, self.session.getvalue()
466
467    def setTearDownCleanup(self, dictionary=None):
468        """Register a cleanup action at tearDown() time with a dictinary"""
469        self.dict = dictionary
470        self.doTearDownCleanup = True
471
472    def addTearDownHook(self, hook):
473        """
474        Add a function to be run during tearDown() time.
475
476        Hooks are executed in a first come first serve manner.
477        """
478        if callable(hook):
479            with recording(self, traceAlways) as sbuf:
480                import inspect
481                print >> sbuf, "Adding tearDown hook:", inspect.getsource(hook)
482            self.hooks.append(hook)
483
484    def tearDown(self):
485        #import traceback
486        #traceback.print_stack()
487
488        # Check and run any hook functions.
489        for hook in self.hooks:
490            with recording(self, traceAlways) as sbuf:
491                import inspect
492                print >> sbuf, "Executing tearDown hook:", inspect.getsource(hook)
493            hook()
494
495        # Terminate the current process being debugged, if any.
496        if self.runStarted:
497            self.runCmd("process kill", PROCESS_KILLED, check=False)
498        elif self.process and self.process.IsValid():
499            rc = self.invoke(self.process, "Kill")
500            self.assertTrue(rc.Success(), PROCESS_KILLED)
501            del self.process
502
503        del self.dbg
504        del self.hooks
505
506        # Perform registered teardown cleanup.
507        if doCleanup and self.doTearDownCleanup:
508            module = __import__(sys.platform)
509            if not module.cleanup(self, dictionary=self.dict):
510                raise Exception("Don't know how to do cleanup")
511
512        # See also LLDBTestResult (dotest.py) which is a singlton class derived
513        # from TextTestResult and overwrites addError()/addFailure() methods to
514        # allow us to to check the error/failure status here.
515        if self.__errored__ or self.__failed__:
516            self.dumpSessionInfo()
517
518    def runCmd(self, cmd, msg=None, check=True, trace=False, setCookie=True):
519        """
520        Ask the command interpreter to handle the command and then check its
521        return status.
522        """
523        # Fail fast if 'cmd' is not meaningful.
524        if not cmd or len(cmd) == 0:
525            raise Exception("Bad 'cmd' parameter encountered")
526
527        trace = (True if traceAlways else trace)
528
529        running = (cmd.startswith("run") or cmd.startswith("process launch"))
530
531        for i in range(self.maxLaunchCount if running else 1):
532            self.ci.HandleCommand(cmd, self.res)
533
534            with recording(self, trace) as sbuf:
535                print >> sbuf, "runCmd:", cmd
536                if not check:
537                    print >> sbuf, "check of return status not required"
538                if self.res.Succeeded():
539                    print >> sbuf, "output:", self.res.GetOutput()
540                else:
541                    print >> sbuf, "runCmd failed!"
542                    print >> sbuf, self.res.GetError()
543
544            if running:
545                # For process launch, wait some time before possible next try.
546                time.sleep(self.timeWait)
547
548            if self.res.Succeeded():
549                break
550            elif running:
551                with recording(self, True) as sbuf:
552                    print >> sbuf, "Command '" + cmd + "' failed!"
553
554        # Modify runStarted only if "run" or "process launch" was encountered.
555        if running:
556            self.runStarted = running and setCookie
557
558        if check:
559            self.assertTrue(self.res.Succeeded(),
560                            msg if msg else CMD_MSG(cmd, True))
561
562    def expect(self, str, msg=None, patterns=None, startstr=None, substrs=None, trace=False, error=False, matching=True, exe=True):
563        """
564        Similar to runCmd; with additional expect style output matching ability.
565
566        Ask the command interpreter to handle the command and then check its
567        return status.  The 'msg' parameter specifies an informational assert
568        message.  We expect the output from running the command to start with
569        'startstr', matches the substrings contained in 'substrs', and regexp
570        matches the patterns contained in 'patterns'.
571
572        If the keyword argument error is set to True, it signifies that the API
573        client is expecting the command to fail.  In this case, the error stream
574        from running the command is retrieved and compared against the golden
575        input, instead.
576
577        If the keyword argument matching is set to False, it signifies that the API
578        client is expecting the output of the command not to match the golden
579        input.
580
581        Finally, the required argument 'str' represents the lldb command to be
582        sent to the command interpreter.  In case the keyword argument 'exe' is
583        set to False, the 'str' is treated as a string to be matched/not-matched
584        against the golden input.
585        """
586        trace = (True if traceAlways else trace)
587
588        if exe:
589            # First run the command.  If we are expecting error, set check=False.
590            self.runCmd(str, trace = (True if trace else False), check = not error)
591
592            # Then compare the output against expected strings.
593            output = self.res.GetError() if error else self.res.GetOutput()
594
595            # If error is True, the API client expects the command to fail!
596            if error:
597                self.assertFalse(self.res.Succeeded(),
598                                 "Command '" + str + "' is expected to fail!")
599        else:
600            # No execution required, just compare str against the golden input.
601            output = str
602            with recording(self, trace) as sbuf:
603                print >> sbuf, "looking at:", output
604
605        # The heading says either "Expecting" or "Not expecting".
606        heading = "Expecting" if matching else "Not expecting"
607
608        # Start from the startstr, if specified.
609        # If there's no startstr, set the initial state appropriately.
610        matched = output.startswith(startstr) if startstr else (True if matching else False)
611
612        if startstr:
613            with recording(self, trace) as sbuf:
614                print >> sbuf, "%s start string: %s" % (heading, startstr)
615                print >> sbuf, "Matched" if matched else "Not matched"
616
617        # Look for sub strings, if specified.
618        keepgoing = matched if matching else not matched
619        if substrs and keepgoing:
620            for str in substrs:
621                matched = output.find(str) != -1
622                with recording(self, trace) as sbuf:
623                    print >> sbuf, "%s sub string: %s" % (heading, str)
624                    print >> sbuf, "Matched" if matched else "Not matched"
625                keepgoing = matched if matching else not matched
626                if not keepgoing:
627                    break
628
629        # Search for regular expression patterns, if specified.
630        keepgoing = matched if matching else not matched
631        if patterns and keepgoing:
632            for pattern in patterns:
633                # Match Objects always have a boolean value of True.
634                matched = bool(re.search(pattern, output))
635                with recording(self, trace) as sbuf:
636                    print >> sbuf, "%s pattern: %s" % (heading, pattern)
637                    print >> sbuf, "Matched" if matched else "Not matched"
638                keepgoing = matched if matching else not matched
639                if not keepgoing:
640                    break
641
642        self.assertTrue(matched if matching else not matched,
643                        msg if msg else CMD_MSG(str, exe))
644
645    def invoke(self, obj, name, trace=False):
646        """Use reflection to call a method dynamically with no argument."""
647        trace = (True if traceAlways else trace)
648
649        method = getattr(obj, name)
650        import inspect
651        self.assertTrue(inspect.ismethod(method),
652                        name + "is a method name of object: " + str(obj))
653        result = method()
654        with recording(self, trace) as sbuf:
655            print >> sbuf, str(method) + ":",  result
656        return result
657
658    def breakAfterLaunch(self, process, func, trace=False):
659        """
660        Perform some dancees after LaunchProcess() to break at func name.
661
662        Return True if we can successfully break at the func name in due time.
663        """
664        trace = (True if traceAlways else trace)
665
666        count = 0
667        while True:
668            # The stop reason of the thread should be breakpoint.
669            thread = process.GetThreadAtIndex(0)
670            SR = thread.GetStopReason()
671            with recording(self, trace) as sbuf:
672                print >> sbuf, "StopReason =", StopReasonString(SR)
673
674            if SR == StopReasonEnum("Breakpoint"):
675                frame = thread.GetFrameAtIndex(0)
676                name = frame.GetFunction().GetName()
677                with recording(self, trace) as sbuf:
678                    print >> sbuf, "function =", name
679                if (name == func):
680                    # We got what we want; now break out of the loop.
681                    return True
682
683            # The inferior is in a transient state; continue the process.
684            time.sleep(1.0)
685            with recording(self, trace) as sbuf:
686                print >> sbuf, "Continuing the process:", process
687            process.Continue()
688
689            count = count + 1
690            if count == 15:
691                with recording(self, trace) as sbuf:
692                    print >> sbuf, "Reached 15 iterations, giving up..."
693                # Enough iterations already, break out of the loop.
694                return False
695
696            # End of while loop.
697
698
699    def buildDefault(self, architecture=None, compiler=None, dictionary=None):
700        """Platform specific way to build the default binaries."""
701        module = __import__(sys.platform)
702        if not module.buildDefault(self, architecture, compiler, dictionary):
703            raise Exception("Don't know how to build default binary")
704
705    def buildDsym(self, architecture=None, compiler=None, dictionary=None):
706        """Platform specific way to build binaries with dsym info."""
707        module = __import__(sys.platform)
708        if not module.buildDsym(self, architecture, compiler, dictionary):
709            raise Exception("Don't know how to build binary with dsym")
710
711    def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
712        """Platform specific way to build binaries with dwarf maps."""
713        module = __import__(sys.platform)
714        if not module.buildDwarf(self, architecture, compiler, dictionary):
715            raise Exception("Don't know how to build binary with dwarf")
716
717    def DebugSBValue(self, frame, val):
718        """Debug print a SBValue object, if traceAlways is True."""
719        if not traceAlways:
720            return
721
722        err = sys.stderr
723        err.write(val.GetName() + ":\n")
724        err.write('\t' + "TypeName    -> " + val.GetTypeName()          + '\n')
725        err.write('\t' + "ByteSize    -> " + str(val.GetByteSize())     + '\n')
726        err.write('\t' + "NumChildren -> " + str(val.GetNumChildren())  + '\n')
727        err.write('\t' + "Value       -> " + str(val.GetValue(frame))   + '\n')
728        err.write('\t' + "Summary     -> " + str(val.GetSummary(frame)) + '\n')
729        err.write('\t' + "IsPtrType   -> " + str(val.TypeIsPtrType())   + '\n')
730        err.write('\t' + "Location    -> " + val.GetLocation(frame)     + '\n')
731
732