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