xref: /llvm-project/lldb/test/API/python_api/sbplatform/TestLocateModuleCallback.py (revision 43b9d62018fe53278dfcd2c46f4937a1664745bd)
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(
53            MODULE_PLATFORM_PATH, Path(module_spec.GetFileSpec().fullpath).as_posix()
54        )
55
56    def check_module(self, module: lldb.SBModule, symbol_file: str, symbol_kind: str):
57        self.assertTrue(module.IsValid())
58
59        self.assertEqual(
60            MODULE_UUID,
61            module.GetUUIDString(),
62        )
63
64        self.assertEqual(MODULE_RESOLVED_TRIPLE, module.GetTriple())
65
66        self.assertEqual(
67            MODULE_PLATFORM_PATH, Path(module.GetPlatformFileSpec().fullpath).as_posix()
68        )
69
70        self.assertTrue(
71            (self.input_dir / MODULE_FILE)
72            .resolve()
73            .samefile(Path(module.GetFileSpec().fullpath).resolve())
74        )
75
76        self.assertTrue(
77            (self.input_dir / symbol_file)
78            .resolve()
79            .samefile(Path(module.GetSymbolFileSpec().fullpath).resolve())
80        )
81
82        sc_list = module.FindFunctions(MODULE_FUNCTION, lldb.eSymbolTypeCode)
83        self.assertEqual(1, sc_list.GetSize())
84        sc_list = module.FindFunctions(MODULE_HIDDEN_FUNCTION, lldb.eSymbolTypeCode)
85        self.assertEqual(0 if symbol_kind == SYMBOL_STRIPPED else 1, sc_list.GetSize())
86
87    def test_set_non_callable(self):
88        # The callback should be callable.
89        non_callable = "a"
90
91        with self.assertRaises(TypeError, msg="Need a callable object or None!"):
92            self.platform.SetLocateModuleCallback(non_callable)
93
94    def test_set_wrong_args(self):
95        # The callback should accept 3 argument.
96        def test_args2(a, b):
97            pass
98
99        with self.assertRaises(TypeError, msg="Expected 3 argument callable object"):
100            self.platform.SetLocateModuleCallback(test_args2)
101
102    def test_default(self):
103        # The default behavior is to locate the module with LLDB implementation
104        # and AddModule should fail.
105        module = self.target.AddModule(
106            MODULE_PLATFORM_PATH,
107            MODULE_TRIPLE,
108            MODULE_UUID,
109        )
110
111        self.assertFalse(module)
112
113    def test_set_none(self):
114        # SetLocateModuleCallback should succeed to clear the callback with None.
115        # and AddModule should fail.
116        self.assertTrue(self.platform.SetLocateModuleCallback(None).Success())
117
118        module = self.target.AddModule(
119            MODULE_PLATFORM_PATH,
120            MODULE_TRIPLE,
121            MODULE_UUID,
122        )
123
124        self.assertFalse(module)
125
126    def test_return_error(self):
127        # The callback fails, AddModule should fail.
128        def test_locate_module(
129            module_spec: lldb.SBModuleSpec,
130            module_file_spec: lldb.SBFileSpec,
131            symbol_file_spec: lldb.SBFileSpec,
132        ):
133            self.check_module_spec(module_spec)
134            return lldb.SBError("locate module callback failed")
135
136        self.assertTrue(
137            self.platform.SetLocateModuleCallback(test_locate_module).Success()
138        )
139
140        module = self.target.AddModule(
141            MODULE_PLATFORM_PATH,
142            MODULE_TRIPLE,
143            MODULE_UUID,
144        )
145
146        self.assertFalse(module)
147
148    def test_return_no_files(self):
149        # The callback succeeds but not return any files, AddModule should fail.
150        def test_locate_module(
151            module_spec: lldb.SBModuleSpec,
152            module_file_spec: lldb.SBFileSpec,
153            symbol_file_spec: lldb.SBFileSpec,
154        ):
155            self.check_module_spec(module_spec)
156            return lldb.SBError()
157
158        self.assertTrue(
159            self.platform.SetLocateModuleCallback(test_locate_module).Success()
160        )
161
162        module = self.target.AddModule(
163            MODULE_PLATFORM_PATH,
164            MODULE_TRIPLE,
165            MODULE_UUID,
166        )
167
168        self.assertFalse(module)
169
170    def test_return_non_existent_module(self):
171        # The callback returns non-existent module file, AddModule should fail.
172        def test_locate_module(
173            module_spec: lldb.SBModuleSpec,
174            module_file_spec: lldb.SBFileSpec,
175            symbol_file_spec: lldb.SBFileSpec,
176        ):
177            self.check_module_spec(module_spec)
178
179            module_file_spec.SetDirectory(str(self.input_dir))
180            module_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
181
182            return lldb.SBError()
183
184        self.assertTrue(
185            self.platform.SetLocateModuleCallback(test_locate_module).Success()
186        )
187
188        module = self.target.AddModule(
189            MODULE_PLATFORM_PATH,
190            MODULE_TRIPLE,
191            MODULE_UUID,
192        )
193
194        self.assertFalse(module)
195
196    def test_return_module_with_non_existent_symbol(self):
197        # The callback returns a module and non-existent symbol file,
198        # AddModule should fail.
199        def test_locate_module(
200            module_spec: lldb.SBModuleSpec,
201            module_file_spec: lldb.SBFileSpec,
202            symbol_file_spec: lldb.SBFileSpec,
203        ):
204            self.check_module_spec(module_spec)
205
206            module_file_spec.SetDirectory(str(self.input_dir))
207            module_file_spec.SetFilename(MODULE_FILE)
208
209            symbol_file_spec.SetDirectory(str(self.input_dir))
210            symbol_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
211
212            return lldb.SBError()
213
214        self.assertTrue(
215            self.platform.SetLocateModuleCallback(test_locate_module).Success()
216        )
217
218        module = self.target.AddModule(
219            MODULE_PLATFORM_PATH,
220            MODULE_TRIPLE,
221            MODULE_UUID,
222        )
223
224        self.assertFalse(module)
225
226    def test_return_non_existent_symbol(self):
227        # The callback returns non-existent symbol file, AddModule should fail.
228        def test_locate_module(
229            module_spec: lldb.SBModuleSpec,
230            module_file_spec: lldb.SBFileSpec,
231            symbol_file_spec: lldb.SBFileSpec,
232        ):
233            self.check_module_spec(module_spec)
234
235            symbol_file_spec.SetDirectory(str(self.input_dir))
236            symbol_file_spec.SetFilename(MODULE_NON_EXISTENT_FILE)
237
238            return lldb.SBError()
239
240        self.assertTrue(
241            self.platform.SetLocateModuleCallback(test_locate_module).Success()
242        )
243
244        module = self.target.AddModule(
245            MODULE_PLATFORM_PATH,
246            MODULE_TRIPLE,
247            MODULE_UUID,
248        )
249
250        self.assertFalse(module)
251
252    def test_return_module(self):
253        # The callback returns the module file, AddModule should succeed.
254        def test_locate_module(
255            module_spec: lldb.SBModuleSpec,
256            module_file_spec: lldb.SBFileSpec,
257            symbol_file_spec: lldb.SBFileSpec,
258        ):
259            self.check_module_spec(module_spec)
260
261            module_file_spec.SetDirectory(str(self.input_dir))
262            module_file_spec.SetFilename(MODULE_FILE)
263
264            return lldb.SBError()
265
266        self.assertTrue(
267            self.platform.SetLocateModuleCallback(test_locate_module).Success()
268        )
269
270        module = self.target.AddModule(
271            MODULE_PLATFORM_PATH,
272            MODULE_TRIPLE,
273            MODULE_UUID,
274        )
275
276        self.check_module(
277            module=module, symbol_file=MODULE_FILE, symbol_kind=SYMBOL_STRIPPED
278        )
279
280    def test_return_module_with_symbol(self):
281        # The callback returns the module file and the symbol file,
282        # AddModule should succeed.
283        def test_locate_module(
284            module_spec: lldb.SBModuleSpec,
285            module_file_spec: lldb.SBFileSpec,
286            symbol_file_spec: lldb.SBFileSpec,
287        ):
288            self.check_module_spec(module_spec)
289
290            module_file_spec.SetDirectory(str(self.input_dir))
291            module_file_spec.SetFilename(MODULE_FILE)
292
293            symbol_file_spec.SetDirectory(str(self.input_dir))
294            symbol_file_spec.SetFilename(SYMBOL_FILE)
295
296            return lldb.SBError()
297
298        self.assertTrue(
299            self.platform.SetLocateModuleCallback(test_locate_module).Success()
300        )
301
302        module = self.target.AddModule(
303            MODULE_PLATFORM_PATH,
304            MODULE_TRIPLE,
305            MODULE_UUID,
306        )
307
308        self.check_module(
309            module=module, symbol_file=SYMBOL_FILE, symbol_kind=SYMBOL_UNSTRIPPED
310        )
311
312    def test_return_module_with_breakpad_symbol(self):
313        # The callback returns the module file and the breakpad symbol file,
314        # AddModule should succeed.
315        def test_locate_module(
316            module_spec: lldb.SBModuleSpec,
317            module_file_spec: lldb.SBFileSpec,
318            symbol_file_spec: lldb.SBFileSpec,
319        ):
320            self.check_module_spec(module_spec)
321
322            module_file_spec.SetDirectory(str(self.input_dir))
323            module_file_spec.SetFilename(MODULE_FILE)
324
325            symbol_file_spec.SetDirectory(str(self.input_dir))
326            symbol_file_spec.SetFilename(BREAKPAD_SYMBOL_FILE)
327
328            return lldb.SBError()
329
330        self.assertTrue(
331            self.platform.SetLocateModuleCallback(test_locate_module).Success()
332        )
333
334        module = self.target.AddModule(
335            MODULE_PLATFORM_PATH,
336            MODULE_TRIPLE,
337            MODULE_UUID,
338        )
339
340        self.check_module(
341            module=module,
342            symbol_file=BREAKPAD_SYMBOL_FILE,
343            symbol_kind=SYMBOL_UNSTRIPPED,
344        )
345