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