Add shared-session MCP source debugger adapter
This commit is contained in:
@@ -20,6 +20,7 @@ PYTHON = Path.home()/'.pyenv/shims/python'
|
||||
sys.path.insert(0, str(ROOT/'toolchain'))
|
||||
from mame_interactive import resolve
|
||||
from sdbg.server import rpc_call
|
||||
from sdbg.session import SessionError
|
||||
|
||||
|
||||
def send(process, sequence, command, arguments=None):
|
||||
@@ -89,8 +90,14 @@ def wait_event(process, buffer, event, timeout):
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--build', default=None)
|
||||
parser.add_argument('--socket', default=None,
|
||||
help='фиксированный Unix socket DAP/MCP-сеанса')
|
||||
parser.add_argument('--app-hdd', default=None)
|
||||
parser.add_argument('--launch-path', default=None)
|
||||
parser.add_argument('--mcp-python', default=None,
|
||||
help='Python 3.12 с MCP SDK 2.x для совместной живой пробы DAP/MCP')
|
||||
parser.add_argument('--clear-while-running', action='store_true',
|
||||
help='во время WAITKEY удалить личную точку; использовать с --waitkey --emulated-key')
|
||||
parser.add_argument('--exit-while-stopped', action='store_true',
|
||||
help='аварийно завершить собственный MAME на main и ждать DAP terminated')
|
||||
parser.add_argument('--stop-while-stopped', action='store_true',
|
||||
@@ -111,6 +118,8 @@ def main():
|
||||
_, buffer, _ = wait_response(process, buffer, 'initialize', 10)
|
||||
debugger = 'osx' if '--osx' in sys.argv else 'sdbg'
|
||||
launch = {'build': str(build), 'debugger': debugger, 'dssTimeout': 30}
|
||||
if options.socket:
|
||||
launch['socket'] = options.socket
|
||||
if options.app_hdd:
|
||||
launch['appHdd'] = str(Path(options.app_hdd).resolve())
|
||||
if options.launch_path:
|
||||
@@ -128,6 +137,48 @@ def main():
|
||||
frame = frame_response['body']['stackFrames'][0]
|
||||
if frame['name'] != 'main':
|
||||
raise RuntimeError('Не main: '+str(frame))
|
||||
if options.mcp_python:
|
||||
source = str(ROOT/'tests/hello/hello.c')
|
||||
send(process, 5, 'setBreakpoints', {
|
||||
'source': {'path': source}, 'breakpoints': [{'line': 31}]})
|
||||
points, buffer, _ = wait_response(process, buffer, 'setBreakpoints', 10)
|
||||
dap_point = points['body']['breakpoints'][0]
|
||||
if not dap_point['verified']:
|
||||
raise RuntimeError('DAP-точка строки 31 не подтверждена')
|
||||
probe = subprocess.run([
|
||||
options.mcp_python, str(ROOT/'tests/sdbg/run_mcp_sdk_probe.py'),
|
||||
'--socket', launched['body']['socket'], '--source', source,
|
||||
'--foreign-id', str(dap_point['id'])],
|
||||
capture_output=True, text=True, timeout=45, check=False)
|
||||
if probe.returncode:
|
||||
raise RuntimeError('MCP SDK probe: '+probe.stderr[-4000:])
|
||||
send(process, 6, 'continue')
|
||||
_, buffer, _ = wait_response(process, buffer, 'continue', 10)
|
||||
stopped, buffer = wait_event(process, buffer, 'stopped', 20)
|
||||
if not stopped:
|
||||
raise RuntimeError('После MCP DAP-точка строки 31 не сработала')
|
||||
send(process, 7, 'stackTrace')
|
||||
at_point, buffer, _ = wait_response(process, buffer, 'stackTrace', 10)
|
||||
if at_point['body']['stackFrames'][0]['line'] != 31:
|
||||
raise RuntimeError('После MCP ожидалась DAP-точка строки 31')
|
||||
send(process, 8, 'setBreakpoints', {
|
||||
'source': {'path': source}, 'breakpoints': []})
|
||||
_, buffer, _ = wait_response(process, buffer, 'setBreakpoints', 10)
|
||||
send(process, 9, 'continue')
|
||||
_, buffer, _ = wait_response(process, buffer, 'continue', 10)
|
||||
stale, buffer = wait_event(process, buffer, 'stopped', 3)
|
||||
if stale:
|
||||
raise RuntimeError('Точка MCP осталась после закрытия stdio-клиента')
|
||||
print(probe.stdout.strip(), flush=True)
|
||||
send(process, 10, 'disconnect')
|
||||
wait_response(process, buffer, 'disconnect', 10)
|
||||
if options.socket:
|
||||
deadline = time.monotonic()+10
|
||||
while Path(options.socket).exists() and time.monotonic() < deadline:
|
||||
time.sleep(.1)
|
||||
if Path(options.socket).exists():
|
||||
raise RuntimeError('После DAP disconnect остался Unix socket сессии')
|
||||
return 0
|
||||
if options.stop_while_stopped:
|
||||
mame_pid = launched['body']['mamePid']
|
||||
send(process, 5, 'disconnect')
|
||||
@@ -202,12 +253,29 @@ def main():
|
||||
before = at_getchar['body']['stackFrames'][0]
|
||||
if before['line'] != 62:
|
||||
raise RuntimeError('Остановка не на getchar: '+str(before))
|
||||
socket_path = launched['body']['socket']
|
||||
clear_point = None
|
||||
if options.clear_while_running:
|
||||
clear_point = rpc_call(socket_path, 'break_line', {
|
||||
'file': str(ROOT/'tests/hello/hello.c'), 'line': 63,
|
||||
'owner': 'probe:running-clear'})
|
||||
started = time.monotonic()
|
||||
send(process, 8, 'next')
|
||||
_, buffer, _ = wait_response(process, buffer, 'next', 3)
|
||||
response_ms = round((time.monotonic()-started)*1000, 2)
|
||||
if clear_point:
|
||||
snapshot = rpc_call(socket_path, 'snapshot', timeout=5)
|
||||
if snapshot['state'] != 'running':
|
||||
raise RuntimeError('CPU не выполняется перед очисткой точки')
|
||||
try:
|
||||
rpc_call(socket_path, 'read_memory', {'address': 0, 'length': 1})
|
||||
raise RuntimeError('Чтение памяти разрешено при running CPU')
|
||||
except SessionError as error:
|
||||
if 'остановленного CPU' not in str(error):
|
||||
raise
|
||||
rpc_call(socket_path, 'clear_breakpoint', {
|
||||
'id': clear_point['id'], 'owner': 'probe:running-clear'})
|
||||
if '--emulated-key' in sys.argv:
|
||||
socket_path = launched['body']['socket']
|
||||
first = rpc_call(socket_path, 'snapshot', timeout=5)
|
||||
time.sleep(1)
|
||||
second = rpc_call(socket_path, 'snapshot', timeout=5)
|
||||
@@ -236,7 +304,8 @@ def main():
|
||||
'at': before, 'after': after,
|
||||
'ascii': ascii_code,
|
||||
'emulated_time_advanced': second['time']-first['time'],
|
||||
'next_response_ms': response_ms},
|
||||
'next_response_ms': response_ms,
|
||||
'running_clear_verified': bool(clear_point)},
|
||||
ensure_ascii=False), flush=True)
|
||||
send(process, 10, 'disconnect')
|
||||
wait_response(process, buffer, 'disconnect', 10)
|
||||
|
||||
Reference in New Issue
Block a user