1import lldb 2import binascii 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test.decorators import * 5from gdbclientutils import * 6 7LLDB_INVALID_ADDRESS = lldb.LLDB_INVALID_ADDRESS 8load_address = 0x400000000 9 10def format_register_value(val): 11 """ 12 Encode each byte by two hex digits in little-endian order. 13 """ 14 result = "" 15 mask = 0xff 16 shift = 0 17 for i in range(0, 8): 18 x = (val & mask) >> shift 19 result += format(x, '02x') 20 mask <<= 8 21 shift += 8 22 return result 23 24 25class MyResponder(MockGDBServerResponder): 26 current_pc = load_address + 0x0a 27 28 def __init__(self, obj_path, module_name = ""): 29 self._obj_path = obj_path 30 self._module_name = module_name or obj_path 31 MockGDBServerResponder.__init__(self) 32 33 def respond(self, packet): 34 if packet == "qProcessInfo": 35 return self.qProcessInfo() 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" % (hex_encode_bytes("lldb"), hex_encode_bytes("wasm32-unknown-unknown-wasm")) 59 60 def haltReason(self): 61 return "T05thread:1;" 62 63 def readRegister(self, register): 64 return format_register_value(self.current_pc) 65 66 def qXferRead(self, obj, annex, offset, length): 67 if obj == "libraries": 68 xml = '<library-list><library name=\"%s\"><section address=\"%d\"/></library></library-list>' % (self._module_name, load_address) 69 return xml, False 70 else: 71 return None, False 72 73 def readMemory(self, addr, length): 74 if addr < load_address: 75 return "E02" 76 result = "" 77 with open(self._obj_path, mode='rb') as file: 78 file_content = bytearray(file.read()) 79 addr_from = addr - load_address 80 addr_to = addr_from + min(length, len(file_content) - addr_from) 81 for i in range(addr_from, addr_to): 82 result += format(file_content[i], '02x') 83 file.close() 84 return result 85 86 87class TestWasm(GDBRemoteTestBase): 88 89 def setUp(self): 90 super(TestWasm, self).setUp() 91 self._initial_platform = lldb.DBG.GetSelectedPlatform() 92 93 def tearDown(self): 94 lldb.DBG.SetSelectedPlatform(self._initial_platform) 95 super(TestWasm, self).tearDown() 96 97 @skipIfXmlSupportMissing 98 def test_load_module_with_embedded_symbols_from_remote(self): 99 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with embedded DWARF symbols""" 100 101 yaml_path = "test_wasm_embedded_debug_sections.yaml" 102 yaml_base, ext = os.path.splitext(yaml_path) 103 obj_path = self.getBuildArtifact(yaml_base) 104 self.yaml2obj(yaml_path, obj_path) 105 106 self.server.responder = MyResponder(obj_path, "test_wasm") 107 108 target = self.dbg.CreateTarget("") 109 process = self.connect(target) 110 lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped]) 111 112 num_modules = target.GetNumModules() 113 self.assertEquals(1, num_modules) 114 115 module = target.GetModuleAtIndex(0) 116 num_sections = module.GetNumSections() 117 self.assertEquals(5, num_sections) 118 119 code_section = module.GetSectionAtIndex(0) 120 self.assertEquals("code", code_section.GetName()) 121 self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target)) 122 123 debug_info_section = module.GetSectionAtIndex(1) 124 self.assertEquals(".debug_info", debug_info_section.GetName()) 125 self.assertEquals(load_address | debug_info_section.GetFileOffset(), debug_info_section.GetLoadAddress(target)) 126 127 debug_abbrev_section = module.GetSectionAtIndex(2) 128 self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName()) 129 self.assertEquals(load_address | debug_abbrev_section.GetFileOffset(), debug_abbrev_section.GetLoadAddress(target)) 130 131 debug_line_section = module.GetSectionAtIndex(3) 132 self.assertEquals(".debug_line", debug_line_section.GetName()) 133 self.assertEquals(load_address | debug_line_section.GetFileOffset(), debug_line_section.GetLoadAddress(target)) 134 135 debug_str_section = module.GetSectionAtIndex(4) 136 self.assertEquals(".debug_str", debug_str_section.GetName()) 137 self.assertEquals(load_address | debug_line_section.GetFileOffset(), debug_line_section.GetLoadAddress(target)) 138 139 140 @skipIfXmlSupportMissing 141 def test_load_module_with_stripped_symbols_from_remote(self): 142 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with symbols stripped into a separate Wasm file""" 143 144 sym_yaml_path = "test_sym.yaml" 145 sym_yaml_base, ext = os.path.splitext(sym_yaml_path) 146 sym_obj_path = self.getBuildArtifact(sym_yaml_base) + ".wasm" 147 self.yaml2obj(sym_yaml_path, sym_obj_path) 148 149 yaml_path = "test_wasm_external_debug_sections.yaml" 150 yaml_base, ext = os.path.splitext(yaml_path) 151 obj_path = self.getBuildArtifact(yaml_base) + ".wasm" 152 self.yaml2obj(yaml_path, obj_path) 153 154 self.server.responder = MyResponder(obj_path, "test_wasm") 155 156 folder, _ = os.path.split(obj_path) 157 self.runCmd("settings set target.debug-file-search-paths " + os.path.abspath(folder)) 158 159 target = self.dbg.CreateTarget("") 160 process = self.connect(target) 161 lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped]) 162 163 num_modules = target.GetNumModules() 164 self.assertEquals(1, num_modules) 165 166 module = target.GetModuleAtIndex(0) 167 num_sections = module.GetNumSections() 168 self.assertEquals(5, num_sections) 169 170 code_section = module.GetSectionAtIndex(0) 171 self.assertEquals("code", code_section.GetName()) 172 self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target)) 173 174 debug_info_section = module.GetSectionAtIndex(1) 175 self.assertEquals(".debug_info", debug_info_section.GetName()) 176 self.assertEquals(LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target)) 177 178 debug_abbrev_section = module.GetSectionAtIndex(2) 179 self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName()) 180 self.assertEquals(LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target)) 181 182 debug_line_section = module.GetSectionAtIndex(3) 183 self.assertEquals(".debug_line", debug_line_section.GetName()) 184 self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target)) 185 186 debug_str_section = module.GetSectionAtIndex(4) 187 self.assertEquals(".debug_str", debug_str_section.GetName()) 188 self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target)) 189 190 191 @skipIfXmlSupportMissing 192 def test_load_module_from_file(self): 193 """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module from a file""" 194 195 yaml_path = "test_wasm_embedded_debug_sections.yaml" 196 yaml_base, ext = os.path.splitext(yaml_path) 197 obj_path = self.getBuildArtifact(yaml_base) 198 self.yaml2obj(yaml_path, obj_path) 199 200 self.server.responder = MyResponder(obj_path) 201 202 target = self.dbg.CreateTarget("") 203 process = self.connect(target) 204 lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped]) 205 206 num_modules = target.GetNumModules() 207 self.assertEquals(1, num_modules) 208 209 module = target.GetModuleAtIndex(0) 210 num_sections = module.GetNumSections() 211 self.assertEquals(5, num_sections) 212 213 code_section = module.GetSectionAtIndex(0) 214 self.assertEquals("code", code_section.GetName()) 215 self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target)) 216 217 debug_info_section = module.GetSectionAtIndex(1) 218 self.assertEquals(".debug_info", debug_info_section.GetName()) 219 self.assertEquals(LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target)) 220 221 debug_abbrev_section = module.GetSectionAtIndex(2) 222 self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName()) 223 self.assertEquals(LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target)) 224 225 debug_line_section = module.GetSectionAtIndex(3) 226 self.assertEquals(".debug_line", debug_line_section.GetName()) 227 self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target)) 228 229 debug_str_section = module.GetSectionAtIndex(4) 230 self.assertEquals(".debug_str", debug_str_section.GetName()) 231 self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target)) 232 233