1"""
2Test lldb target stop-hook mechanism to see whether it fires off correctly .
3"""
4
5import os
6import unittest2
7import lldb
8import pexpect
9from lldbtest import *
10
11class StopHookMechanismTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "stop-hook")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @dsym_test
17    def test_with_dsym(self):
18        """Test the stop-hook mechanism."""
19        self.buildDsym()
20        self.stop_hook_firing()
21
22    @skipIfLinux # llvm.org/pr15037: stop-hooks sometimes fail to fire on Linux (disabled to avoid needless noise)
23    @dwarf_test
24    def test_with_dwarf(self):
25        """Test the stop-hook mechanism."""
26        self.buildDwarf()
27        self.stop_hook_firing()
28
29    def setUp(self):
30        # Call super's setUp().
31        TestBase.setUp(self)
32        # Find the line numbers inside main.cpp.
33        self.begl = line_number('main.cpp', '// Set breakpoint here to test target stop-hook.')
34        self.endl = line_number('main.cpp', '// End of the line range for which stop-hook is to be run.')
35        self.correct_step_line = line_number ('main.cpp', '// We should stop here after stepping.')
36        self.line = line_number('main.cpp', '// Another breakpoint which is outside of the stop-hook range.')
37
38    def stop_hook_firing(self):
39        """Test the stop-hook mechanism."""
40        exe = os.path.join(os.getcwd(), "a.out")
41        prompt = "(lldb) "
42        add_prompt = "Enter your stop hook command(s).  Type 'DONE' to end.\r\n> "
43        add_prompt1 = "\r\n> "
44
45        # So that the child gets torn down after the test.
46        self.child = pexpect.spawn('%s %s %s' % (self.lldbHere, self.lldbOption, exe))
47        child = self.child
48        # Turn on logging for what the child sends back.
49        if self.TraceOn():
50            child.logfile_read = sys.stdout
51
52        # Set the breakpoint, followed by the target stop-hook commands.
53        child.expect_exact(prompt)
54        child.sendline('breakpoint set -f main.cpp -l %d' % self.begl)
55        child.expect_exact(prompt)
56        child.sendline('breakpoint set -f main.cpp -l %d' % self.line)
57        child.expect_exact(prompt)
58        child.sendline('target stop-hook add -f main.cpp -l %d -e %d' % (self.begl, self.endl))
59        child.expect_exact(add_prompt)
60        child.sendline('expr ptr')
61        child.expect_exact(add_prompt1)
62        child.sendline('DONE')
63        child.expect_exact(prompt)
64        child.sendline('target stop-hook list')
65
66        # Now run the program, expect to stop at the the first breakpoint which is within the stop-hook range.
67        child.expect_exact(prompt)
68        child.sendline('run')
69        child.expect_exact(prompt)
70        child.sendline('thread step-over')
71        # Expecting to find the output emitted by the firing of our stop hook.
72        child.expect_exact('(void *) $')
73        # This is orthogonal to the main stop hook test, but this example shows a bug in
74        # CLANG where the line table entry for the "return -1" actually includes some code
75        # from the other branch of the if/else, so we incorrectly stop at the "return -1" line.
76        # I fixed that in lldb and I'm sticking in a test here because I don't want to have to
77        # make up a whole nother test case for it.
78        child.sendline('frame info')
79        child.expect_exact('at main.cpp:%d'%self.correct_step_line)
80
81        # Now continue the inferior, we'll stop at another breakpoint which is outside the stop-hook range.
82        child.sendline('process continue')
83        child.expect_exact('// Another breakpoint which is outside of the stop-hook range.')
84        #self.DebugPExpect(child)
85        child.sendline('thread step-over')
86        child.expect_exact('// Another breakpoint which is outside of the stop-hook range.')
87        #self.DebugPExpect(child)
88        # Verify that the 'Stop Hooks' mechanism is NOT BEING fired off.
89        self.expect(child.before, exe=False, matching=False,
90            substrs = ['(void *) $'])
91
92
93if __name__ == '__main__':
94    import atexit
95    lldb.SBDebugger.Initialize()
96    atexit.register(lambda: lldb.SBDebugger.Terminate())
97    unittest2.main()
98