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