mirror of
https://github.com/xemu-project/xemu.git
synced 2026-10-21 18:19:16 +02:00
Add GDB class, which provides methods to run GDB commands and capture their output. The GDB class is a wrapper around the pygdbmi module and interacts with GDB via GDB's machine interface (MI). Acked-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org> Message-ID: <20251003141820.85278-5-gustavo.romero@linaro.org> [AJB: trimmed excess license text] Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
87 lines
2.2 KiB
Python
87 lines
2.2 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
#
|
|
# A simple interface module built around pygdbmi for handling GDB commands.
|
|
#
|
|
# Copyright (c) 2025 Linaro Limited
|
|
#
|
|
# Author:
|
|
# Gustavo Romero <gustavo.romero@linaro.org>
|
|
#
|
|
|
|
import re
|
|
|
|
|
|
class GDB:
|
|
"""Provides methods to run and capture GDB command output."""
|
|
|
|
|
|
def __init__(self, gdb_path, echo=True, suffix='# ', prompt="$ "):
|
|
from pygdbmi.gdbcontroller import GdbController
|
|
from pygdbmi.constants import GdbTimeoutError
|
|
type(self).TimeoutError = GdbTimeoutError
|
|
|
|
gdb_cmd = [gdb_path, "-q", "--interpreter=mi2"]
|
|
self.gdbmi = GdbController(gdb_cmd)
|
|
self.echo = echo
|
|
self.suffix = suffix
|
|
self.prompt = prompt
|
|
self.response = None
|
|
self.cmd_output = None
|
|
|
|
|
|
def get_payload(self, response, kind):
|
|
output = []
|
|
for o in response:
|
|
# Unpack payloads of the same type.
|
|
_type, _, payload, *_ = o.values()
|
|
if _type == kind:
|
|
output += [payload]
|
|
|
|
# Some output lines do not end with \n but begin with it,
|
|
# so remove the leading \n and merge them with the next line
|
|
# that ends with \n.
|
|
lines = [line.lstrip('\n') for line in output]
|
|
lines = "".join(lines)
|
|
lines = lines.splitlines(keepends=True)
|
|
|
|
return lines
|
|
|
|
|
|
def cli(self, cmd, timeout=32.0):
|
|
self.response = self.gdbmi.write(cmd, timeout_sec=timeout)
|
|
self.cmd_output = self.get_payload(self.response, kind="console")
|
|
if self.echo:
|
|
print(self.suffix + self.prompt + cmd)
|
|
|
|
if len(self.cmd_output) > 0:
|
|
cmd_output = self.suffix.join(self.cmd_output)
|
|
print(self.suffix + cmd_output, end="")
|
|
|
|
return self
|
|
|
|
|
|
def get_addr(self):
|
|
address_pattern = r"0x[0-9A-Fa-f]+"
|
|
cmd_output = "".join(self.cmd_output) # Concat output lines.
|
|
|
|
match = re.search(address_pattern, cmd_output)
|
|
|
|
return int(match[0], 16) if match else None
|
|
|
|
|
|
def get_log(self):
|
|
r = self.get_payload(self.response, kind="log")
|
|
r = "".join(r)
|
|
|
|
return r
|
|
|
|
|
|
def get_console(self):
|
|
r = "".join(self.cmd_output)
|
|
|
|
return r
|
|
|
|
|
|
def exit(self):
|
|
self.gdbmi.exit()
|