Add shared-session MCP source debugger adapter
This commit is contained in:
@@ -116,6 +116,13 @@ class SessionController:
|
||||
self.poller.join(timeout=1)
|
||||
self.session.bridge.close()
|
||||
|
||||
@staticmethod
|
||||
def _owner(arguments: dict) -> str:
|
||||
owner = arguments.get('owner', 'cli')
|
||||
if not isinstance(owner, str) or not owner or len(owner) > 128:
|
||||
raise SessionError('owner должен быть непустой строкой до 128 символов')
|
||||
return owner
|
||||
|
||||
def call(self, method: str, arguments: dict) -> object:
|
||||
if method == 'events':
|
||||
after = int(arguments.get('after', 0))
|
||||
@@ -131,6 +138,9 @@ class SessionController:
|
||||
with self.lock:
|
||||
if self.closed:
|
||||
raise SessionError('Сессия закрыта или инвалидирована')
|
||||
if self.running and method in ('where', 'registers', 'read_memory',
|
||||
'read_variable', 'break_line', 'break_function'):
|
||||
raise SessionError('Операция требует остановленного CPU; сначала Pause')
|
||||
if method == 'status':
|
||||
return {**self.attached, 'running': self.running,
|
||||
'event_sequence': self.sequence}
|
||||
@@ -151,16 +161,52 @@ class SessionController:
|
||||
mapping = self.session.refresh()
|
||||
return {'generation': mapping.generation, 'registers': mapping.registers,
|
||||
'bank_pages': mapping.bank_pages}
|
||||
if method == 'read_memory':
|
||||
address = int(arguments['address'])
|
||||
length = int(arguments['length'])
|
||||
if address < 0 or address > 0xffff or length < 1 or length > 256 or \
|
||||
address + length > 0x10000:
|
||||
raise SessionError('Чтение памяти: адрес 0..65535, длина 1..256 без выхода за 64 КБ')
|
||||
mapping = self.session.refresh()
|
||||
data = self.session.bridge.request('memory', address=address, length=length)
|
||||
return {'address': address, 'length': length, 'hex': data['hex'],
|
||||
'generation': mapping.generation, 'bank_pages': mapping.bank_pages}
|
||||
if method == 'variables':
|
||||
return self.session.model.variables
|
||||
if method == 'read_variable':
|
||||
return self.session.read_variable(arguments['name'], arguments.get('module'))
|
||||
if method == 'break_line':
|
||||
return self.session.break_line(arguments['file'], int(arguments['line']))
|
||||
owner = self._owner(arguments)
|
||||
item = self.session.break_line(arguments['file'], int(arguments['line']))
|
||||
self.breakpoint_info[item['id']] = {
|
||||
'kind': 'stop', 'message': None, 'locations': item['locations'],
|
||||
'hits': 0, 'owner': owner}
|
||||
return item
|
||||
if method == 'break_function':
|
||||
return self.session.break_function(arguments['name'])
|
||||
owner = self._owner(arguments)
|
||||
item = self.session.break_function(arguments['name'])
|
||||
self.breakpoint_info[item['id']] = {
|
||||
'kind': 'stop', 'message': None, 'locations': item['locations'],
|
||||
'hits': 0, 'owner': owner}
|
||||
return item
|
||||
if method == 'clear_breakpoint':
|
||||
return self.session.clear_breakpoint(int(arguments['id']))
|
||||
identifier = int(arguments['id'])
|
||||
owner = arguments.get('owner')
|
||||
if owner is not None and self.breakpoint_info.get(identifier, {}).get('owner') != owner:
|
||||
raise SessionError('Точка не принадлежит этому клиенту')
|
||||
result = self.session.clear_breakpoint(identifier)
|
||||
self.breakpoint_info.pop(identifier, None)
|
||||
return result
|
||||
if method == 'clear_owned_breakpoints':
|
||||
owner = arguments.get('owner')
|
||||
if not isinstance(owner, str) or not owner:
|
||||
raise SessionError('Для очистки точек требуется owner')
|
||||
identifiers = [identifier for identifier, info in self.breakpoint_info.items()
|
||||
if info.get('owner') == owner]
|
||||
for identifier in identifiers:
|
||||
self.session.clear_breakpoint(identifier)
|
||||
self.breakpoint_info.pop(identifier, None)
|
||||
return {'cleared': identifiers}
|
||||
if method == 'set_source_breakpoints':
|
||||
specifications = arguments.get('breakpoints')
|
||||
if specifications is None:
|
||||
|
||||
Reference in New Issue
Block a user