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