1import lldb 2import binascii 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test.decorators import * 5from lldbsuite.test.gdbclientutils import * 6from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase 7 8LLDB_INVALID_ADDRESS = lldb.LLDB_INVALID_ADDRESS 9load_address = 0x400000000 10 11 12def format_register_value(val): 13 """ 14 Encode each byte by two hex digits in little-endian order. 15 """ 16 result = "" 17 mask = 0xFF 18 shift = 0 19 for i in range(0, 8): 20 x = (val & mask) >> shift 21 result += format(x, "02x") 22 mask <<= 8 23 shift += 8 24 return result 25 26 27class MyResponder(MockGDBServerResponder): 28 current_pc = load_address + 0x0A 29 30 def __init__(self, obj_path, module_name=""): 31 self._obj_path = obj_path 32 self._module_name = module_name or obj_path 33 MockGDBServerResponder.__init__(self) 34 35 def respond(self, packet): 36 if packet[0:13] == "qRegisterInfo": 37 return self.qRegisterInfo(packet[13:]) 38 return MockGDBServerResponder.respond(self, packet) 39 40 def qSupported(self, client_supported): 41 return "qXfer:libraries:read+;PacketSize=1000;vContSupported-" 42 43 def qHostInfo(self): 44 return "" 45 46 def QEnableErrorStrings(self): 47 return "" 48 49 def qfThreadInfo(self): 50 return "OK" 51 52 def qRegisterInfo(self, index): 53 if index == 0: 54 return "name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;" 55 return "E45" 56 57 def qProcessInfo(self): 58 return "pid:1;ppid:1;uid:1;gid:1;euid:1;egid:1;name:%s;triple:%s;ptrsize:4" % ( 59 hex_encode_bytes("lldb"), 60 hex_encode_bytes("wasm32-unknown-unknown-wasm"), 61 ) 62 63 def haltReason(self): 64 return "T05thread:1;" 65 66 def readRegister(self, register): 67 return format_register_value(self.current_pc) 68 69 def qXferRead(self, obj, annex, offset, length): 70 if obj == "libraries": 71 xml = ( 72 '<library-list><library name="%s"><section address="%d"/></library></library-list>' 73 % (self._module_name, load_address) 74 ) 75 return xml, False 76 else: 77 return None, False 78 79 def readMemory(self, addr, length): 80 if addr < load_address: 81 return "E02" 82 result = "" 83 with open(self._obj_path, mode="rb") as file: 84 file_content = bytearray(file.read()) 85 addr_from = addr - load_address 86 addr_to = addr_from + min(length, len(file_content) - addr_from) 87 for i in range(addr_from, addr_to): 88 result += format(file_content[i], "02x") 89 file.close() 90 return result 91 92 93class TestWasm(GDBRemoteTestBase): 94 @skipIfAsan 95 @skipIfXmlSupportMissing 96 def test_load_module_with_embedded_symbols_from_remote(self): 97 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with embedded DWARF symbols""" 98 99 yaml_path = "test_wasm_embedded_debug_sections.yaml" 100 yaml_base, ext = os.path.splitext(yaml_path) 101 obj_path = self.getBuildArtifact(yaml_base) 102 self.yaml2obj(yaml_path, obj_path) 103 104 self.server.responder = MyResponder(obj_path, "test_wasm") 105 106 target = self.dbg.CreateTarget("") 107 process = self.connect(target) 108 lldbutil.expect_state_changes( 109 self, self.dbg.GetListener(), process, [lldb.eStateStopped] 110 ) 111 112 num_modules = target.GetNumModules() 113 self.assertEqual(1, num_modules) 114 115 module = target.GetModuleAtIndex(0) 116 num_sections = module.GetNumSections() 117 self.assertEqual(5, num_sections) 118 119 code_section = module.GetSectionAtIndex(0) 120 self.assertEqual("code", code_section.GetName()) 121 self.assertEqual( 122 load_address | code_section.GetFileOffset(), 123 code_section.GetLoadAddress(target), 124 ) 125 126 debug_info_section = module.GetSectionAtIndex(1) 127 self.assertEqual(".debug_info", debug_info_section.GetName()) 128 self.assertEqual( 129 load_address | debug_info_section.GetFileOffset(), 130 debug_info_section.GetLoadAddress(target), 131 ) 132 133 debug_abbrev_section = module.GetSectionAtIndex(2) 134 self.assertEqual(".debug_abbrev", debug_abbrev_section.GetName()) 135 self.assertEqual( 136 load_address | debug_abbrev_section.GetFileOffset(), 137 debug_abbrev_section.GetLoadAddress(target), 138 ) 139 140 debug_line_section = module.GetSectionAtIndex(3) 141 self.assertEqual(".debug_line", debug_line_section.GetName()) 142 self.assertEqual( 143 load_address | debug_line_section.GetFileOffset(), 144 debug_line_section.GetLoadAddress(target), 145 ) 146 147 debug_str_section = module.GetSectionAtIndex(4) 148 self.assertEqual(".debug_str", debug_str_section.GetName()) 149 self.assertEqual( 150 load_address | debug_line_section.GetFileOffset(), 151 debug_line_section.GetLoadAddress(target), 152 ) 153 154 @skipIfAsan 155 @skipIfXmlSupportMissing 156 def test_load_module_with_stripped_symbols_from_remote(self): 157 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with symbols stripped into a separate Wasm file""" 158 159 sym_yaml_path = "test_sym.yaml" 160 sym_yaml_base, ext = os.path.splitext(sym_yaml_path) 161 sym_obj_path = self.getBuildArtifact(sym_yaml_base) + ".wasm" 162 self.yaml2obj(sym_yaml_path, sym_obj_path) 163 164 yaml_path = "test_wasm_external_debug_sections.yaml" 165 yaml_base, ext = os.path.splitext(yaml_path) 166 obj_path = self.getBuildArtifact(yaml_base) + ".wasm" 167 self.yaml2obj(yaml_path, obj_path) 168 169 self.server.responder = MyResponder(obj_path, "test_wasm") 170 171 folder, _ = os.path.split(obj_path) 172 self.runCmd( 173 "settings set target.debug-file-search-paths " + os.path.abspath(folder) 174 ) 175 176 target = self.dbg.CreateTarget("") 177 process = self.connect(target) 178 lldbutil.expect_state_changes( 179 self, self.dbg.GetListener(), process, [lldb.eStateStopped] 180 ) 181 182 num_modules = target.GetNumModules() 183 self.assertEqual(1, num_modules) 184 185 module = target.GetModuleAtIndex(0) 186 num_sections = module.GetNumSections() 187 self.assertEqual(5, num_sections) 188 189 code_section = module.GetSectionAtIndex(0) 190 self.assertEqual("code", code_section.GetName()) 191 self.assertEqual( 192 load_address | code_section.GetFileOffset(), 193 code_section.GetLoadAddress(target), 194 ) 195 196 debug_info_section = module.GetSectionAtIndex(1) 197 self.assertEqual(".debug_info", debug_info_section.GetName()) 198 self.assertEqual( 199 LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target) 200 ) 201 202 debug_abbrev_section = module.GetSectionAtIndex(2) 203 self.assertEqual(".debug_abbrev", debug_abbrev_section.GetName()) 204 self.assertEqual( 205 LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target) 206 ) 207 208 debug_line_section = module.GetSectionAtIndex(3) 209 self.assertEqual(".debug_line", debug_line_section.GetName()) 210 self.assertEqual( 211 LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target) 212 ) 213 214 debug_str_section = module.GetSectionAtIndex(4) 215 self.assertEqual(".debug_str", debug_str_section.GetName()) 216 self.assertEqual( 217 LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target) 218 ) 219 220 @skipIfAsan 221 @skipIfXmlSupportMissing 222 def test_load_module_from_file(self): 223 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module from a file""" 224 225 yaml_path = "test_wasm_embedded_debug_sections.yaml" 226 yaml_base, ext = os.path.splitext(yaml_path) 227 obj_path = self.getBuildArtifact(yaml_base) 228 self.yaml2obj(yaml_path, obj_path) 229 230 self.server.responder = MyResponder(obj_path) 231 232 target = self.dbg.CreateTarget("") 233 process = self.connect(target) 234 lldbutil.expect_state_changes( 235 self, self.dbg.GetListener(), process, [lldb.eStateStopped] 236 ) 237 238 num_modules = target.GetNumModules() 239 self.assertEqual(1, num_modules) 240 241 module = target.GetModuleAtIndex(0) 242 num_sections = module.GetNumSections() 243 self.assertEqual(5, num_sections) 244 245 code_section = module.GetSectionAtIndex(0) 246 self.assertEqual("code", code_section.GetName()) 247 self.assertEqual( 248 load_address | code_section.GetFileOffset(), 249 code_section.GetLoadAddress(target), 250 ) 251 252 debug_info_section = module.GetSectionAtIndex(1) 253 self.assertEqual(".debug_info", debug_info_section.GetName()) 254 self.assertEqual( 255 LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target) 256 ) 257 258 debug_abbrev_section = module.GetSectionAtIndex(2) 259 self.assertEqual(".debug_abbrev", debug_abbrev_section.GetName()) 260 self.assertEqual( 261 LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target) 262 ) 263 264 debug_line_section = module.GetSectionAtIndex(3) 265 self.assertEqual(".debug_line", debug_line_section.GetName()) 266 self.assertEqual( 267 LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target) 268 ) 269 270 debug_str_section = module.GetSectionAtIndex(4) 271 self.assertEqual(".debug_str", debug_str_section.GetName()) 272 self.assertEqual( 273 LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target) 274 ) 275