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