Johnny Chen | d5f66fc | 2010-12-23 01:12:19 +0000 | [diff] [blame] | 1 | """ |
| 2 | Use lldb Python SBFrame API to get the argument values of the call stacks. |
| 3 | """ |
| 4 | |
| 5 | import os, time |
| 6 | import re |
| 7 | import unittest2 |
| 8 | import lldb, lldbutil |
| 9 | from lldbtest import * |
| 10 | |
| 11 | class FrameAPITestCase(TestBase): |
| 12 | |
| 13 | mydir = os.path.join("python_api", "frame") |
| 14 | |
Johnny Chen | d5f66fc | 2010-12-23 01:12:19 +0000 | [diff] [blame] | 15 | @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") |
| 16 | @python_api_test |
| 17 | def test_get_arg_vals_for_call_stack_with_dsym(self): |
| 18 | """Exercise SBFrame.GetVariables() API to get argument vals.""" |
| 19 | self.buildDsym() |
| 20 | self.do_get_arg_vals() |
| 21 | |
Johnny Chen | d5f66fc | 2010-12-23 01:12:19 +0000 | [diff] [blame] | 22 | @python_api_test |
| 23 | def test_get_arg_vals_for_call_stack_with_dwarf(self): |
| 24 | """Exercise SBFrame.GetVariables() API to get argument vals.""" |
| 25 | self.buildDwarf() |
| 26 | self.do_get_arg_vals() |
| 27 | |
| 28 | def do_get_arg_vals(self): |
| 29 | """Get argument vals for the call stack when stopped on a breakpoint.""" |
| 30 | exe = os.path.join(os.getcwd(), "a.out") |
| 31 | |
| 32 | # Create a target by the debugger. |
| 33 | target = self.dbg.CreateTarget(exe) |
| 34 | self.assertTrue(target.IsValid(), VALID_TARGET) |
| 35 | |
| 36 | # Now create a breakpoint on main.c by name 'c'. |
| 37 | breakpoint = target.BreakpointCreateByName('c', 'a.out') |
| 38 | #print "breakpoint:", breakpoint |
| 39 | self.assertTrue(breakpoint.IsValid() and |
| 40 | breakpoint.GetNumLocations() == 1, |
| 41 | VALID_BREAKPOINT) |
| 42 | |
| 43 | # Now launch the process, and do not stop at the entry point. |
| 44 | # Note that we don't assign the process to self.process as in other test |
| 45 | # cases. We want the inferior to run till it exits and there's no need |
| 46 | # for the testing framework to kill the inferior upon tearDown(). |
| 47 | process = target.LaunchProcess([], [], os.ctermid(), 0, False) |
| 48 | |
| 49 | process = target.GetProcess() |
| 50 | self.assertTrue(process.GetState() == lldb.eStateStopped, |
| 51 | PROCESS_STOPPED) |
| 52 | |
| 53 | # Keeps track of the number of times 'a' is called where it is within a |
| 54 | # depth of 3 of the 'c' leaf function. |
| 55 | callsOfA = 0 |
| 56 | |
| 57 | import StringIO |
| 58 | session = StringIO.StringIO() |
| 59 | while process.GetState() == lldb.eStateStopped: |
| 60 | thread = process.GetThreadAtIndex(0) |
| 61 | # Inspect at most 3 frames. |
| 62 | numFrames = min(3, thread.GetNumFrames()) |
| 63 | for i in range(numFrames): |
| 64 | frame = thread.GetFrameAtIndex(i) |
| 65 | print "frame:", frame |
| 66 | #print "frame.FindValue('val', lldb.eValueTypeVariableArgument)", frame.FindValue('val', lldb.eValueTypeVariableArgument).GetValue(frame) |
| 67 | #print "frame.FindValue('ch', lldb.eValueTypeVariableArgument)", frame.FindValue('ch', lldb.eValueTypeVariableArgument).GetValue(frame) |
| 68 | #print "frame.EvaluateExpression('val'):", frame.EvaluateExpression('val').GetValue(frame) |
| 69 | #print "frame.EvaluateExpression('ch'):", frame.EvaluateExpression('ch').GetValue(frame) |
| 70 | name = frame.GetFunction().GetName() |
| 71 | if name == 'a': |
| 72 | callsOfA = callsOfA + 1 |
| 73 | |
| 74 | # We'll inspect only the arguments for the current frame: |
| 75 | # |
| 76 | # arguments => True |
| 77 | # locals => False |
| 78 | # statics => False |
| 79 | # in_scope_only => True |
| 80 | valList = frame.GetVariables(True, False, False, True) |
| 81 | argList = [] |
| 82 | from lldbutil import lldb_iter |
| 83 | for val in lldb_iter(valList, 'GetSize', 'GetValueAtIndex'): |
| 84 | #self.DebugSBValue(frame, val) |
| 85 | argList.append("(%s)%s=%s" % (val.GetTypeName(), |
| 86 | val.GetName(), |
| 87 | val.GetValue(frame))) |
| 88 | print >> session, "%s(%s)" % (name, ", ".join(argList)) |
| 89 | |
| 90 | print >> session, "---" |
| 91 | process.Continue() |
| 92 | |
| 93 | # At this point, the inferior process should have exited. |
| 94 | self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED) |
| 95 | |
| 96 | # Expect to find 'a' on the call stacks two times. |
| 97 | self.assertTrue(callsOfA == 2, |
| 98 | "Expect to find 'a' on the call stacks two times") |
| 99 | # By design, the 'a' call frame has the following arg vals: |
| 100 | # o a((int)val=1, (char)ch='A') |
| 101 | # o a((int)val=3, (char)ch='A') |
| 102 | print "Full stack traces when stopped on the breakpoint 'c':" |
| 103 | print session.getvalue() |
Johnny Chen | d5f66fc | 2010-12-23 01:12:19 +0000 | [diff] [blame] | 104 | self.expect(session.getvalue(), "Argugment values displayed correctly", |
| 105 | exe=False, |
| 106 | substrs = ["a((int)val=1, (char)ch='A')", |
| 107 | "a((int)val=3, (char)ch='A')"]) |
| 108 | |
| 109 | |
| 110 | if __name__ == '__main__': |
| 111 | import atexit |
| 112 | lldb.SBDebugger.Initialize() |
| 113 | atexit.register(lambda: lldb.SBDebugger.Terminate()) |
| 114 | unittest2.main() |