1"""Test that types defined in shared libraries work correctly."""
2
3
4import lldb
5import unittest2
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8import lldbsuite.test.lldbutil as lldbutil
9
10
11class SharedLibTestCase(TestBase):
12
13    def setUp(self):
14        # Call super's setUp().
15        TestBase.setUp(self)
16        # Find the line number to break inside main().
17        self.source = "shared.c"
18        self.line = line_number(self.source, "// Set breakpoint 0 here.")
19        self.shlib_names = ["foo"]
20
21    def common_setup(self):
22        # Run in synchronous mode
23        self.dbg.SetAsync(False)
24        self.runCmd("settings set symbols.load-on-demand true")
25
26        # Create a target by the debugger.
27        self.target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
28        self.assertTrue(self.target, VALID_TARGET)
29
30        # Register our shared libraries for remote targets so they get
31        # automatically uploaded
32        self.environment = self.registerSharedLibrariesWithTarget(
33            self.target, self.shlib_names
34        )
35
36        ctx = self.platformContext
37        self.shared_lib_name = ctx.shlib_prefix + "foo." + ctx.shlib_extension
38
39    @skipIfWindows
40    def test_source_line_breakpoint(self):
41        self.build()
42        self.common_setup()
43
44        lldbutil.run_break_set_by_file_and_line(
45            self, "foo.c", 4, num_expected_locations=1, loc_exact=True
46        )
47
48        # Now launch the process, and do not stop at entry point.
49        process = self.target.LaunchSimple(
50            None, self.environment, self.get_process_working_directory()
51        )
52        self.assertTrue(process, PROCESS_IS_VALID)
53
54        # The stop reason of the thread should be breakpoint.
55        self.expect(
56            "thread list",
57            STOPPED_DUE_TO_BREAKPOINT,
58            substrs=["stopped", "stop reason = breakpoint"],
59        )
60        # The breakpoint should have a hit count of 1.
61        lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1)
62
63        thread = process.GetSelectedThread()
64        stack_frames = lldbutil.get_stack_frames(thread)
65        self.assertGreater(len(stack_frames), 2)
66
67        leaf_frame = stack_frames[0]
68        self.assertEqual("foo.c", leaf_frame.GetLineEntry().GetFileSpec().GetFilename())
69        self.assertEqual(4, leaf_frame.GetLineEntry().GetLine())
70
71        parent_frame = stack_frames[1]
72        self.assertEqual(
73            "shared.c", parent_frame.GetLineEntry().GetFileSpec().GetFilename()
74        )
75        self.assertEqual(7, parent_frame.GetLineEntry().GetLine())
76
77    @skipIfWindows
78    def test_symbolic_breakpoint(self):
79        self.build()
80        self.common_setup()
81
82        lldbutil.run_break_set_by_symbol(
83            self, "foo", sym_exact=True, num_expected_locations=1
84        )
85
86        # Now launch the process, and do not stop at entry point.
87        process = self.target.LaunchSimple(
88            None, self.environment, self.get_process_working_directory()
89        )
90        self.assertTrue(process, PROCESS_IS_VALID)
91
92        # The stop reason of the thread should be breakpoint.
93        self.expect(
94            "thread list",
95            STOPPED_DUE_TO_BREAKPOINT,
96            substrs=["stopped", "stop reason = breakpoint"],
97        )
98        # The breakpoint should have a hit count of 1.
99        lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1)
100
101        thread = process.GetSelectedThread()
102        stack_frames = lldbutil.get_stack_frames(thread)
103        self.assertGreater(len(stack_frames), 2)
104
105        leaf_frame = stack_frames[0]
106        self.assertEqual("foo.c", leaf_frame.GetLineEntry().GetFileSpec().GetFilename())
107        self.assertEqual(4, leaf_frame.GetLineEntry().GetLine())
108
109        parent_frame = stack_frames[1]
110        self.assertEqual(
111            "shared.c", parent_frame.GetLineEntry().GetFileSpec().GetFilename()
112        )
113        self.assertEqual(7, parent_frame.GetLineEntry().GetLine())
114
115    @skipIfWindows
116    def test_global_variable_hydration(self):
117        self.build()
118        self.common_setup()
119
120        lldbutil.run_break_set_by_file_and_line(
121            self, self.source, self.line, num_expected_locations=1, loc_exact=True
122        )
123
124        # Now launch the process, and do not stop at entry point.
125        process = self.target.LaunchSimple(
126            None, self.environment, self.get_process_working_directory()
127        )
128        self.assertTrue(process, PROCESS_IS_VALID)
129
130        # The stop reason of the thread should be breakpoint.
131        self.expect(
132            "thread list",
133            STOPPED_DUE_TO_BREAKPOINT,
134            substrs=["stopped", "stop reason = breakpoint"],
135        )
136
137        # The breakpoint should have a hit count of 1.
138        lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1)
139
140        self.expect(
141            "target variable --shlib a.out",
142            "Breakpoint in a.out should have hydrated the debug info",
143            substrs=["global_shared = 897"],
144        )
145
146        self.expect(
147            "target variable --shlib " + self.shared_lib_name,
148            "shared library should not have debug info by default",
149            matching=False,
150            substrs=["global_foo"],
151        )
152
153        self.expect(
154            "target variable global_foo --shlib " + self.shared_lib_name,
155            "Match global_foo in symbol table should hydrate debug info",
156            matching=True,
157            substrs=["global_foo = 321"],
158        )
159