summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/greeneye/target.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 11:44:31 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 11:44:31 -0400
commit1c99bfbeffff04529f6f669601fdf835a73778da (patch)
tree5867bab46e5848541df36c703f6fd8d6d0256e54 /debug/risc-v-gsp-rm-vm/greeneye/target.py
parent2fd653044127a665e4677a2cdfb58120d7b3e16b (diff)
downloadopen-iov-1c99bfbeffff04529f6f669601fdf835a73778da.tar.gz
open-iov-1c99bfbeffff04529f6f669601fdf835a73778da.zip
rename (cosmetic): green-eye -> risc-v-gsp-rm-debugger in user-facing names, docs, CLI, launcher and CI workflow; internal greeneye package/module identifiers unchanged (includes in-flight greeneye module edits present in the tree)
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/greeneye/target.py')
-rw-r--r--debug/risc-v-gsp-rm-vm/greeneye/target.py35
1 files changed, 23 insertions, 12 deletions
diff --git a/debug/risc-v-gsp-rm-vm/greeneye/target.py b/debug/risc-v-gsp-rm-vm/greeneye/target.py
index 273f216..669a55d 100644
--- a/debug/risc-v-gsp-rm-vm/greeneye/target.py
+++ b/debug/risc-v-gsp-rm-vm/greeneye/target.py
@@ -1,4 +1,4 @@
-"""QEMU target lifecycle for green-eye.
+"""QEMU target lifecycle for risc-v-gsp-rm-debugger.
Owns the ``qemu-system-riscv64`` process, the gdbstub endpoint, the serial
capture and the QEMU trace log. Both firmware paths are supported:
@@ -76,8 +76,10 @@ class QemuTarget:
os.makedirs(self.workdir, exist_ok=True)
self.uart_log = uart_log or os.path.join(self.workdir, "uart.log")
self.qemu_log = qemu_log or os.path.join(self.workdir, "qemu.log")
+ self.stderr_log = os.path.join(self.workdir, "qemu.stderr.log")
self.keep_alive = keep_alive
self.process: subprocess.Popen | None = None
+ self._stderr_fh = None
self._segment_files: list[str] = []
self._cmd: list[str] = []
@@ -118,15 +120,19 @@ class QemuTarget:
def start(self, paused: bool = True, timeout: float = 15.0) -> "QemuTarget":
self._cmd = self._build_command(paused)
+ # Never use an undrained stderr=PIPE: a chatty QEMU would block once
+ # the pipe buffer fills and then stop answering the gdbstub.
+ self._stderr_fh = open(self.stderr_log, "ab")
try:
self.process = subprocess.Popen(
self._cmd,
stdout=subprocess.DEVNULL,
- stderr=subprocess.PIPE,
+ stderr=self._stderr_fh,
cwd=self.workdir,
start_new_session=True,
)
except OSError as exc:
+ self._close_stderr()
raise TargetError(f"cannot start QEMU: {exc}") from exc
try:
self.wait_for_port(timeout=timeout)
@@ -140,11 +146,11 @@ class QemuTarget:
while time.monotonic() < deadline:
if self.process is not None and self.process.poll() is not None:
stderr = b""
- if self.process.stderr is not None:
- try:
- stderr = self.process.stderr.read() or b""
- except OSError:
- pass
+ try:
+ with open(self.stderr_log, "rb") as fh:
+ stderr = fh.read()
+ except OSError:
+ pass
raise TargetError(
f"QEMU exited early rc={self.process.returncode}: "
f"{stderr.decode('utf-8', 'replace')[-2000:]}"
@@ -159,8 +165,17 @@ class QemuTarget:
def alive(self) -> bool:
return self.process is not None and self.process.poll() is None
+ def _close_stderr(self) -> None:
+ if self._stderr_fh is not None:
+ try:
+ self._stderr_fh.close()
+ except OSError:
+ pass
+ self._stderr_fh = None
+
def kill(self, timeout: float = 5.0) -> None:
if self.process is None:
+ self._close_stderr()
return
if self.process.poll() is None:
try:
@@ -181,11 +196,7 @@ class QemuTarget:
except ProcessLookupError:
pass
self.process.wait(timeout=timeout)
- if self.process.stderr is not None:
- try:
- self.process.stderr.close()
- except OSError:
- pass
+ self._close_stderr()
self.process = None
# -- observation -------------------------------------------------------