xref: /llvm-project/lldb/test/API/python_api/sbplatform/TestLocateModuleCallback.py (revision f03dbdb70aed74ed64c1a42a85e47e3f86315ae7)
1"""
2Test platform locate module callback functionality
3"""
4
5import ctypes
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from pathlib import Path
9
10import lldb
11
12UNITTESTS_TARGET_INPUTS_PATH = "../../../../unittests/Target/Inputs"
13MODULE_PLATFORM_PATH = "/system/lib64/AndroidModule.so"
14MODULE_TRIPLE = "aarch64-none-linux"
15MODULE_RESOLVED_TRIPLE = "aarch64--linux-android"
16MODULE_UUID = "80008338-82A0-51E5-5922-C905D23890DA-BDDEFECC"
17MODULE_FUNCTION = "boom"
18MODULE_HIDDEN_FUNCTION = "boom_hidden"
19MODULE_FILE = "AndroidModule.so"
20MODULE_NON_EXISTENT_FILE = "non-existent-file"
21SYMBOL_FILE = "AndroidModule.unstripped.so"
22BREAKPAD_SYMBOL_FILE = "AndroidModule.so.sym"
23SYMBOL_STRIPPED = "stripped"
24SYMBOL_UNSTRIPPED = "unstripped"
25
26
27class LocateModuleCallbackTestCase(TestBase):
28    def setUp(self):
29        TestBase.setUp(self)
30        self.platform = self.dbg.GetSelectedPlatform()
31        self.target = self.dbg.CreateTarget("")
32        self.assertTrue(self.target)
33
34        self.input_dir = (
35            Path(self.getSourceDir()) / UNITTESTS_TARGET_INPUTS_PATH
36        ).resolve()
37        self.assertTrue(self.input_dir.is_dir())
38
39    def check_module_spec(self, module_spec: lldb.SBModuleSpec):
40        self.assertEqual(
41            MODULE_UUID.replace("-", ""),
42            ctypes.string_at(
43                int(module_spec.GetUUIDBytes()),
44                module_spec.GetUUIDLength(),
45            )
46            .hex()
47            .upper(),
48        )
49
50        self.assertEqual(MODULE_TRIPLE, module_spec.GetTriple())
51
52        self.assertEqual(MODULE_PLATFORM_PATH, module_spec.GetFileSpec().fullpath)
53
54    def check_module(self, module: lldb.SBModule, symbol_file: str, symbol_kind: str):
55        self.assertTrue(module.IsValid())
56
57        self.assertEqual(
58            MODULE_UUID,
59            module.GetUUIDString(),
60        )
61
62        self.assertEqual(MODULE_RESOLVED_TRIPLE, module.GetTriple())
63
64        self.assertEqual(MODULE_PLATFORM_PATH, module.GetPlatformFileSpec().fullpath)
65
66        self.assertEqual(
67            str(self.input_dir / MODULE_FILE),
68            module.GetFileSpec().fullpath,
69        )
70
71        self.assertEqual(
72            str(self.input_dir / symbol_file),
73            module.GetSymbolFileSpec().fullpath,
74        )
75
76        sc_list = module.FindFunctions(MODULE_FUNCTION, lldb.eSymbolTypeCode)
77        self.assertEqual(1, sc_list.GetSize())
78        sc_list = module.FindFunctions(MODULE_HIDDEN_FUNCTION, lldb.eSymbolTypeCode)
79        self.assertEqual(0 if symbol_kind == SYMBOL_STRIPPED else 1, sc_list.GetSize())
80
81    def test_set_non_callable(self):
82        # The callback should be callable.
83        non_callable = "a"
84
85        with self.assertRaises(TypeError, msg="Need a callable object or None!"):
86            self.platform.SetLocateModuleCallback(non_callable)
87
88    def test_set_wrong_args(self):
89        # The callback should accept 3 argument.
90        def test_args2(a, b):
91            pass
92
93        with self.assertRaises(TypeError, msg="Expected 3 argument callable object"):
94            self.platform.SetLocateModuleCallback(test_args2)
95
96    def test_default(self):
97        # The default behavior is to locate the module with LLDB implementation
98        # and AddModule should fail.
99        module = self.target.AddModule(
100            MODULE_PLATFORM_PATH,
101            MODULE_TRIPLE,
102            MODULE_UUID,
103        )
104
105        self.assertFalse(module)
106
107    def test_set_none(self):
108        # SetLocateModuleCallback should succeed to clear the callback with None.
109        # and AddModule should fail.
110        self.assertTrue(self.platform.SetLocateModuleCallback(None).Success())
111
112        module = self.target.AddModule(
113            MODULE_PLATFORM_PATH,
114            MODULE_TRIPLE,
115            MODULE_UUID,
116        )
117
118        self.assertFalse(module)
119
120    def test_return_error(self):
121        # The callback fails, AddModule should fail.
122        def test_locate_module(
123            module_spec: lldb.SBModuleSpec,
124            module_file_spec: lldb.SBFileSpec,
125            symbol_file_spec: lldb.SBFileSpec,
126        ):
127            self.check_module_spec(module_spec)
128            return lldb.SBError("locate module callback failed")
129
130        self.assertTrue(
131            self.platform.SetLocateModuleCallback(test_locate_module).Success()
132        )
133
134        module = self.target.AddModule(
135            MODULE_PLATFORM_PATH,
136            MODULE_TRIPLE,
137            MODULE_UUID,
138        )
139
140        self.assertFalse(module)
141
142    def test_return_no_files(self):
143        # The callback succeeds but not return any files, AddModule should fail.
144        def test_locate_module(
145            module_spec: lldb.SBModuleSpec,
146            module_file_spec: lldb.SBFileSpec,
147            symbol_file_spec: lldb.SBFileSpec,
148        ):
149            self.check_module_spec(module_spec)
150            return lldb.SBError()
151
152        self.assertTrue(
153            self.platform.SetLocateModuleCallback(test_locate_module).Success()
154        )
155
156        module = self.target.AddModule(
157            MODULE_PLATFORM_PATH,
158            MODULE_TRIPLE,
159            MODULE_UUID,
160        )
161
162        self.assertFalse(module)
163
164    def test_return_non_existent_module(self):
165        # The callback returns non-existent module file, AddModule should fail.
166        def test_locate_module(
167            module_spec: lldb.SBModuleSpec,
168            module_file_spec: lldb.SBFileSpec,
169            symbol_file_spec: lldb.SBFileSpec,
170        ):
171            self.check_module_spec(module_spec)
172
173            module_file_spec.SetDirectory(str(self.input_dir))
174            module_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
175
176            return lldb.SBError()
177
178        self.assertTrue(
179            self.platform.SetLocateModuleCallback(test_locate_module).Success()
180        )
181
182        module = self.target.AddModule(
183            MODULE_PLATFORM_PATH,
184            MODULE_TRIPLE,
185            MODULE_UUID,
186        )
187
188        self.assertFalse(module)
189
190    def test_return_module_with_non_existent_symbol(self):
191        # The callback returns a module and non-existent symbol file,
192        # AddModule should fail.
193        def test_locate_module(
194            module_spec: lldb.SBModuleSpec,
195            module_file_spec: lldb.SBFileSpec,
196            symbol_file_spec: lldb.SBFileSpec,
197        ):
198            self.check_module_spec(module_spec)
199
200            module_file_spec.SetDirectory(str(self.input_dir))
201            module_file_spec.SetFilename(MODULE_FILE)
202
203            symbol_file_spec.SetDirectory(str(self.input_dir))
204            symbol_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
205
206            return lldb.SBError()
207
208        self.assertTrue(
209            self.platform.SetLocateModuleCallback(test_locate_module).Success()
210        )
211
212        module = self.target.AddModule(
213            MODULE_PLATFORM_PATH,
214            MODULE_TRIPLE,
215            MODULE_UUID,
216        )
217
218        self.assertFalse(module)
219
220    def test_return_non_existent_symbol(self):
221        # The callback returns non-existent symbol file, AddModule should fail.
222        def test_locate_module(
223            module_spec: lldb.SBModuleSpec,
224            module_file_spec: lldb.SBFileSpec,
225            symbol_file_spec: lldb.SBFileSpec,
226        ):
227            self.check_module_spec(module_spec)
228
229            symbol_file_spec.SetDirectory(str(self.input_dir))
230            symbol_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
231
232            return lldb.SBError()
233
234        self.assertTrue(
235            self.platform.SetLocateModuleCallback(test_locate_module).Success()
236        )
237
238        module = self.target.AddModule(
239            MODULE_PLATFORM_PATH,
240            MODULE_TRIPLE,
241            MODULE_UUID,
242        )
243
244        self.assertFalse(module)
245
246    def test_return_module(self):
247        # The callback returns the module file, AddModule should succeed.
248        def test_locate_module(
249            module_spec: lldb.SBModuleSpec,
250            module_file_spec: lldb.SBFileSpec,
251            symbol_file_spec: lldb.SBFileSpec,
252        ):
253            self.check_module_spec(module_spec)
254
255            module_file_spec.SetDirectory(str(self.input_dir))
256            module_file_spec.SetFilename(MODULE_FILE)
257
258            return lldb.SBError()
259
260        self.assertTrue(
261            self.platform.SetLocateModuleCallback(test_locate_module).Success()
262        )
263
264        module = self.target.AddModule(
265            MODULE_PLATFORM_PATH,
266            MODULE_TRIPLE,
267            MODULE_UUID,
268        )
269
270        self.check_module(
271            module=module, symbol_file=MODULE_FILE, symbol_kind=SYMBOL_STRIPPED
272        )
273
274    def test_return_module_with_symbol(self):
275        # The callback returns the module file and the symbol file,
276        # AddModule should succeed.
277        def test_locate_module(
278            module_spec: lldb.SBModuleSpec,
279            module_file_spec: lldb.SBFileSpec,
280            symbol_file_spec: lldb.SBFileSpec,
281        ):
282            self.check_module_spec(module_spec)
283
284            module_file_spec.SetDirectory(str(self.input_dir))
285            module_file_spec.SetFilename(MODULE_FILE)
286
287            symbol_file_spec.SetDirectory(str(self.input_dir))
288            symbol_file_spec.SetFilename(SYMBOL_FILE)
289
290            return lldb.SBError()
291
292        self.assertTrue(
293            self.platform.SetLocateModuleCallback(test_locate_module).Success()
294        )
295
296        module = self.target.AddModule(
297            MODULE_PLATFORM_PATH,
298            MODULE_TRIPLE,
299            MODULE_UUID,
300        )
301
302        self.check_module(
303            module=module, symbol_file=SYMBOL_FILE, symbol_kind=SYMBOL_UNSTRIPPED
304        )
305
306    def test_return_module_with_breakpad_symbol(self):
307        # The callback returns the module file and the breakpad symbol file,
308        # AddModule should succeed.
309        def test_locate_module(
310            module_spec: lldb.SBModuleSpec,
311            module_file_spec: lldb.SBFileSpec,
312            symbol_file_spec: lldb.SBFileSpec,
313        ):
314            self.check_module_spec(module_spec)
315
316            module_file_spec.SetDirectory(str(self.input_dir))
317            module_file_spec.SetFilename(MODULE_FILE)
318
319            symbol_file_spec.SetDirectory(str(self.input_dir))
320            symbol_file_spec.SetFilename(BREAKPAD_SYMBOL_FILE)
321
322            return lldb.SBError()
323
324        self.assertTrue(
325            self.platform.SetLocateModuleCallback(test_locate_module).Success()
326        )
327
328        module = self.target.AddModule(
329            MODULE_PLATFORM_PATH,
330            MODULE_TRIPLE,
331            MODULE_UUID,
332        )
333
334        self.check_module(
335            module=module,
336            symbol_file=BREAKPAD_SYMBOL_FILE,
337            symbol_kind=SYMBOL_UNSTRIPPED,
338        )
339