1"""
2Test the lldb disassemble command on each call frame when stopped on C's ctor.
3"""
4
5import os, time
6import unittest2
7import lldb
8from lldbtest import *
9import lldbutil
10
11class IterateFrameAndDisassembleTestCase(TestBase):
12
13    mydir = os.path.join("lang", "cpp", "class_types")
14    failing_compilers = ['clang', 'gcc']
15
16    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
17    @dsym_test
18    def test_with_dsym_and_run_command(self):
19        """Disassemble each call frame when stopped on C's constructor."""
20        self.buildDsym()
21        self.disassemble_call_stack()
22
23    @dwarf_test
24    @expectedFailureFreeBSD('llvm.org/pr14540')
25    @expectedFailureLinux('llvm.org/pr14540', failing_compilers)
26    def test_with_dwarf_and_run_command(self):
27        """Disassemble each call frame when stopped on C's constructor."""
28        self.buildDwarf()
29        self.disassemble_call_stack()
30
31    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
32    @python_api_test
33    @dsym_test
34    def test_with_dsym_and_python_api(self):
35        """Disassemble each call frame when stopped on C's constructor."""
36        self.buildDsym()
37        self.disassemble_call_stack_python()
38
39    @python_api_test
40    @dwarf_test
41    @expectedFailureFreeBSD('llvm.org/pr14540')
42    @expectedFailureLinux('llvm.org/pr14540', failing_compilers)
43    def test_with_dwarf_and_python_api(self):
44        """Disassemble each call frame when stopped on C's constructor."""
45        self.buildDwarf()
46        self.disassemble_call_stack_python()
47
48    def setUp(self):
49        # Call super's setUp().
50        TestBase.setUp(self)
51        # Find the line number to break for main.cpp.
52        self.line = line_number('main.cpp', '// Set break point at this line.')
53
54    def breakOnCtor(self):
55        """Setup/run the program so it stops on C's constructor."""
56        exe = os.path.join(os.getcwd(), "a.out")
57        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
58
59        # Break on the ctor function of class C.
60        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1)
61
62        self.runCmd("run", RUN_SUCCEEDED)
63
64        # The stop reason of the thread should be breakpoint.
65        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
66            substrs = ['stopped',
67                       'stop reason = breakpoint'])
68
69        # We should be stopped on the ctor function of class C.
70        self.expect("thread backtrace", BACKTRACE_DISPLAYED_CORRECTLY,
71            substrs = ['C::C'])
72
73    def disassemble_call_stack(self):
74        """Disassemble each call frame when stopped on C's constructor."""
75        self.breakOnCtor()
76
77        raw_output = self.res.GetOutput()
78        frameRE = re.compile(r"""
79                              ^\s\sframe        # heading for the frame info,
80                              .*                # wildcard, and
81                              0x[0-9a-f]{16}    # the frame pc, and
82                              \sa.out`(.+)      # module`function, and
83                              \s\+\s            # the rest ' + ....'
84                              """, re.VERBOSE)
85        for line in raw_output.split(os.linesep):
86            match = frameRE.search(line)
87            if match:
88                function = match.group(1)
89                #print "line:", line
90                #print "function:", function
91                self.runCmd("disassemble -n '%s'" % function)
92
93    def disassemble_call_stack_python(self):
94        """Disassemble each call frame when stopped on C's constructor."""
95        self.breakOnCtor()
96
97        # Now use the Python API to get at each function on the call stack and
98        # disassemble it.
99        target = self.dbg.GetSelectedTarget()
100        process = target.GetProcess()
101        thread = process.GetThreadAtIndex(0)
102        depth = thread.GetNumFrames()
103        for i in range(depth - 1):
104            frame = thread.GetFrameAtIndex(i)
105            function = frame.GetFunction()
106            # Print the function header.
107            if self.TraceOn():
108                print
109                print function
110            if function:
111                # Get all instructions for this function and print them out.
112                insts = function.GetInstructions(target)
113                for inst in insts:
114                    # We could simply do 'print inst' to print out the disassembly.
115                    # But we want to print to stdout only if self.TraceOn() is True.
116                    disasm = str(inst)
117                    if self.TraceOn():
118                        print disasm
119
120
121if __name__ == '__main__':
122    import atexit
123    lldb.SBDebugger.Initialize()
124    atexit.register(lambda: lldb.SBDebugger.Terminate())
125    unittest2.main()
126