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