diff options
Diffstat (limited to 'deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py')
-rw-r--r-- | deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py | 137 |
1 files changed, 136 insertions, 1 deletions
diff --git a/deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py b/deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py index 131725f83d1..f1981ed9a84 100644 --- a/deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py +++ b/deps/v8/test/debugging/wasm/gdb-server/gdb_rsp.py @@ -1,13 +1,25 @@ -# Copyright 2019 the V8 project authors. All rights reserved. +# Copyright 2020 the V8 project authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import re import socket +import struct import subprocess import time +import xml.etree.ElementTree SOCKET_ADDR = ('localhost', 8765) +SIGTRAP = 5 +SIGSEGV = 11 +RETURNCODE_KILL = -9 + +ARCH = 'wasm32' +REG_DEFS = { + ARCH: [('pc', 'Q'), ], +} + def EnsurePortIsAvailable(addr=SOCKET_ADDR): # As a sanity check, check that the TCP port is available by binding to it @@ -21,6 +33,11 @@ def EnsurePortIsAvailable(addr=SOCKET_ADDR): sock.bind(addr) sock.close() +def RspChecksum(data): + checksum = 0 + for char in data: + checksum = (checksum + ord(char)) & 0xff + return checksum class GdbRspConnection(object): @@ -48,6 +65,40 @@ class GdbRspConnection(object): raise Exception('Could not connect to the debug stub in %i seconds' % timeout_in_seconds) + def _GetReply(self): + reply = '' + message_finished = re.compile('#[0-9a-fA-F]{2}') + while True: + data = self._socket.recv(1024) + if len(data) == 0: + raise AssertionError('EOF on socket reached with ' + 'incomplete reply message: %r' % reply) + reply += data + if message_finished.match(reply[-3:]): + break + match = re.match('\+?\$([^#]*)#([0-9a-fA-F]{2})$', reply) + if match is None: + raise AssertionError('Unexpected reply message: %r' % reply) + reply_body = match.group(1) + checksum = match.group(2) + expected_checksum = '%02x' % RspChecksum(reply_body) + if checksum != expected_checksum: + raise AssertionError('Bad RSP checksum: %r != %r' % + (checksum, expected_checksum)) + # Send acknowledgement. + self._socket.send('+') + return reply_body + + # Send an rsp message, but don't wait for or expect a reply. + def RspSendOnly(self, data): + msg = '$%s#%02x' % (data, RspChecksum(data)) + return self._socket.send(msg) + + def RspRequest(self, data): + self.RspSendOnly(data) + reply = self._GetReply() + return reply + def Close(self): self._socket.close() @@ -71,3 +122,87 @@ def KillProcess(process): else: raise process.wait() + + +class LaunchDebugStub(object): + def __init__(self, command): + self._proc = PopenDebugStub(command) + + def __enter__(self): + try: + return GdbRspConnection() + except: + KillProcess(self._proc) + raise + + def __exit__(self, exc_type, exc_value, traceback): + KillProcess(self._proc) + + +def AssertEquals(x, y): + if x != y: + raise AssertionError('%r != %r' % (x, y)) + +def DecodeHex(data): + assert len(data) % 2 == 0, data + return bytes(bytearray([int(data[index * 2 : (index + 1) * 2], 16) for index in xrange(len(data) // 2)])) + +def EncodeHex(data): + return ''.join('%02x' % ord(byte) for byte in data) + +def DecodeUInt64Array(data): + assert len(data) % 16 == 0, data + result = [] + for index in xrange(len(data) // 16): + value = 0 + for digit in xrange(7, -1, -1): + value = value * 256 + int(data[index * 16 + digit * 2 : index * 16 + (digit + 1) * 2], 16) + result.append(value) + return result + +def AssertReplySignal(reply, signal): + AssertEquals(ParseThreadStopReply(reply)['signal'], signal) + +def ParseThreadStopReply(reply): + match = re.match('T([0-9a-f]{2})thread-pcs:([0-9a-f]+);thread:([0-9a-f]+);$', reply) + if not match: + raise AssertionError('Bad thread stop reply: %r' % reply) + return {'signal': int(match.group(1), 16), + 'thread_pc': int(match.group(2), 16), + 'thread_id': int(match.group(3), 16)} + +def CheckInstructionPtr(connection, expected_ip): + ip_value = DecodeRegs(connection.RspRequest('g'))['pc'] + AssertEquals(ip_value, expected_ip) + +def DecodeRegs(reply): + defs = REG_DEFS[ARCH] + names = [reg_name for reg_name, reg_fmt in defs] + fmt = ''.join([reg_fmt for reg_name, reg_fmt in defs]) + + values = struct.unpack_from(fmt, DecodeHex(reply)) + return dict(zip(names, values)) + +def GetLoadedModules(connection): + modules = {} + reply = connection.RspRequest('qXfer:libraries:read') + AssertEquals(reply[0], 'l') + library_list = xml.etree.ElementTree.fromstring(reply[1:]) + AssertEquals(library_list.tag, 'library-list') + for library in library_list: + AssertEquals(library.tag, 'library') + section = library.find('section') + address = section.get('address') + assert long(address) > 0 + modules[long(address)] = library.get('name') + return modules + +def GetLoadedModuleAddress(connection): + modules = GetLoadedModules(connection) + assert len(modules) > 0 + return modules.keys()[0] + +def ReadCodeMemory(connection, address, size): + reply = connection.RspRequest('m%x,%x' % (address, size)) + assert not reply.startswith('E'), reply + return DecodeHex(reply) |