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