228 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
| import lldb
 | |
| import binascii
 | |
| from lldbsuite.test.lldbtest import *
 | |
| from lldbsuite.test.decorators import *
 | |
| from gdbclientutils import *
 | |
| 
 | |
| LLDB_INVALID_ADDRESS = lldb.LLDB_INVALID_ADDRESS
 | |
| load_address = 0x400000000
 | |
| 
 | |
| def format_register_value(val):
 | |
|     """
 | |
|     Encode each byte by two hex digits in little-endian order.
 | |
|     """
 | |
|     result = ""
 | |
|     mask = 0xff
 | |
|     shift = 0
 | |
|     for i in range(0, 8):
 | |
|         x = (val & mask) >> shift
 | |
|         result += format(x, '02x')
 | |
|         mask <<= 8
 | |
|         shift += 8
 | |
|     return result
 | |
| 
 | |
| 
 | |
| class MyResponder(MockGDBServerResponder):
 | |
|     current_pc = load_address + 0x0a
 | |
| 
 | |
|     def __init__(self, obj_path, module_name = ""):
 | |
|         self._obj_path = obj_path
 | |
|         self._module_name = module_name or obj_path
 | |
|         MockGDBServerResponder.__init__(self)
 | |
| 
 | |
|     def respond(self, packet):
 | |
|         if packet == "qProcessInfo":
 | |
|             return self.qProcessInfo()
 | |
|         if packet[0:13] == "qRegisterInfo":
 | |
|             return self.qRegisterInfo(packet[13:])
 | |
|         return MockGDBServerResponder.respond(self, packet)
 | |
| 
 | |
|     def qSupported(self, client_supported):
 | |
|         return "qXfer:libraries:read+;PacketSize=1000;vContSupported-"
 | |
| 
 | |
|     def qHostInfo(self):
 | |
|         return ""
 | |
| 
 | |
|     def QEnableErrorStrings(self):
 | |
|         return ""
 | |
| 
 | |
|     def qfThreadInfo(self):
 | |
|         return "OK"
 | |
| 
 | |
|     def qRegisterInfo(self, index):
 | |
|         if (index == 0):
 | |
|             return "name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;"
 | |
|         return "E45"
 | |
| 
 | |
|     def qProcessInfo(self):
 | |
|         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"))
 | |
| 
 | |
|     def haltReason(self):
 | |
|         return "T05thread:1;"
 | |
| 
 | |
|     def readRegister(self, register):                
 | |
|         return format_register_value(self.current_pc)
 | |
| 
 | |
|     def qXferRead(self, obj, annex, offset, length):
 | |
|         if obj == "libraries":
 | |
|             xml = '<library-list><library name=\"%s\"><section address=\"%d\"/></library></library-list>' % (self._module_name, load_address)
 | |
|             return xml, False
 | |
|         else:
 | |
|             return None, False
 | |
| 
 | |
|     def readMemory(self, addr, length):
 | |
|         if addr < load_address: 
 | |
|             return "E02"
 | |
|         result = ""
 | |
|         with open(self._obj_path, mode='rb') as file:
 | |
|             file_content = bytearray(file.read())                    
 | |
|             addr_from = addr - load_address
 | |
|             addr_to = addr_from + min(length, len(file_content) - addr_from)
 | |
|             for i in range(addr_from, addr_to):
 | |
|                 result += format(file_content[i], '02x')
 | |
|             file.close()
 | |
|         return result
 | |
| 
 | |
| 
 | |
| class TestWasm(GDBRemoteTestBase):
 | |
| 
 | |
|     @skipIfAsan
 | |
|     @skipIfXmlSupportMissing
 | |
|     def test_load_module_with_embedded_symbols_from_remote(self):
 | |
|         """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with embedded DWARF symbols"""
 | |
| 
 | |
|         yaml_path = "test_wasm_embedded_debug_sections.yaml"
 | |
|         yaml_base, ext = os.path.splitext(yaml_path)
 | |
|         obj_path = self.getBuildArtifact(yaml_base)
 | |
|         self.yaml2obj(yaml_path, obj_path)
 | |
| 
 | |
|         self.server.responder = MyResponder(obj_path, "test_wasm")
 | |
| 
 | |
|         target = self.dbg.CreateTarget("")
 | |
|         process = self.connect(target)
 | |
|         lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped])
 | |
|     
 | |
|         num_modules = target.GetNumModules()
 | |
|         self.assertEquals(1, num_modules)
 | |
| 
 | |
|         module = target.GetModuleAtIndex(0)
 | |
|         num_sections = module.GetNumSections()
 | |
|         self.assertEquals(5, num_sections)
 | |
| 
 | |
|         code_section = module.GetSectionAtIndex(0)
 | |
|         self.assertEquals("code", code_section.GetName())
 | |
|         self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_info_section = module.GetSectionAtIndex(1)
 | |
|         self.assertEquals(".debug_info", debug_info_section.GetName())
 | |
|         self.assertEquals(load_address | debug_info_section.GetFileOffset(), debug_info_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_abbrev_section = module.GetSectionAtIndex(2)
 | |
|         self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName())
 | |
|         self.assertEquals(load_address | debug_abbrev_section.GetFileOffset(), debug_abbrev_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_line_section = module.GetSectionAtIndex(3)
 | |
|         self.assertEquals(".debug_line", debug_line_section.GetName())
 | |
|         self.assertEquals(load_address | debug_line_section.GetFileOffset(), debug_line_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_str_section = module.GetSectionAtIndex(4)
 | |
|         self.assertEquals(".debug_str", debug_str_section.GetName())
 | |
|         self.assertEquals(load_address | debug_line_section.GetFileOffset(), debug_line_section.GetLoadAddress(target))
 | |
| 
 | |
|         
 | |
|     @skipIfAsan
 | |
|     @skipIfXmlSupportMissing
 | |
|     def test_load_module_with_stripped_symbols_from_remote(self):
 | |
|         """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module with symbols stripped into a separate Wasm file"""
 | |
| 
 | |
|         sym_yaml_path = "test_sym.yaml"
 | |
|         sym_yaml_base, ext = os.path.splitext(sym_yaml_path)
 | |
|         sym_obj_path = self.getBuildArtifact(sym_yaml_base) + ".wasm"
 | |
|         self.yaml2obj(sym_yaml_path, sym_obj_path)
 | |
| 
 | |
|         yaml_path = "test_wasm_external_debug_sections.yaml"
 | |
|         yaml_base, ext = os.path.splitext(yaml_path)
 | |
|         obj_path = self.getBuildArtifact(yaml_base) + ".wasm"
 | |
|         self.yaml2obj(yaml_path, obj_path)
 | |
| 
 | |
|         self.server.responder = MyResponder(obj_path, "test_wasm")
 | |
| 
 | |
|         folder, _ = os.path.split(obj_path)
 | |
|         self.runCmd("settings set target.debug-file-search-paths " + os.path.abspath(folder))
 | |
| 
 | |
|         target = self.dbg.CreateTarget("")
 | |
|         process = self.connect(target)
 | |
|         lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped])
 | |
|     
 | |
|         num_modules = target.GetNumModules()
 | |
|         self.assertEquals(1, num_modules)
 | |
| 
 | |
|         module = target.GetModuleAtIndex(0)
 | |
|         num_sections = module.GetNumSections()
 | |
|         self.assertEquals(5, num_sections)
 | |
| 
 | |
|         code_section = module.GetSectionAtIndex(0)
 | |
|         self.assertEquals("code", code_section.GetName())
 | |
|         self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_info_section = module.GetSectionAtIndex(1)
 | |
|         self.assertEquals(".debug_info", debug_info_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_abbrev_section = module.GetSectionAtIndex(2)
 | |
|         self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_line_section = module.GetSectionAtIndex(3)
 | |
|         self.assertEquals(".debug_line", debug_line_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_str_section = module.GetSectionAtIndex(4)
 | |
|         self.assertEquals(".debug_str", debug_str_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target))
 | |
| 
 | |
| 
 | |
|     @skipIfAsan
 | |
|     @skipIfXmlSupportMissing
 | |
|     def test_load_module_from_file(self):
 | |
|         """Test connecting to a WebAssembly engine via GDB-remote and loading a Wasm module from a file"""
 | |
| 
 | |
|         yaml_path = "test_wasm_embedded_debug_sections.yaml"
 | |
|         yaml_base, ext = os.path.splitext(yaml_path)
 | |
|         obj_path = self.getBuildArtifact(yaml_base)
 | |
|         self.yaml2obj(yaml_path, obj_path)
 | |
| 
 | |
|         self.server.responder = MyResponder(obj_path)
 | |
| 
 | |
|         target = self.dbg.CreateTarget("")
 | |
|         process = self.connect(target)
 | |
|         lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped])
 | |
|     
 | |
|         num_modules = target.GetNumModules()
 | |
|         self.assertEquals(1, num_modules)
 | |
| 
 | |
|         module = target.GetModuleAtIndex(0)
 | |
|         num_sections = module.GetNumSections()
 | |
|         self.assertEquals(5, num_sections)
 | |
| 
 | |
|         code_section = module.GetSectionAtIndex(0)
 | |
|         self.assertEquals("code", code_section.GetName())
 | |
|         self.assertEquals(load_address | code_section.GetFileOffset(), code_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_info_section = module.GetSectionAtIndex(1)
 | |
|         self.assertEquals(".debug_info", debug_info_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_info_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_abbrev_section = module.GetSectionAtIndex(2)
 | |
|         self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_abbrev_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_line_section = module.GetSectionAtIndex(3)
 | |
|         self.assertEquals(".debug_line", debug_line_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target))
 | |
| 
 | |
|         debug_str_section = module.GetSectionAtIndex(4)
 | |
|         self.assertEquals(".debug_str", debug_str_section.GetName())
 | |
|         self.assertEquals(LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target))
 | |
| 
 |