summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/greeneye/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/greeneye/__init__.py')
-rw-r--r--debug/risc-v-gsp-rm-vm/greeneye/__init__.py115
1 files changed, 115 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/greeneye/__init__.py b/debug/risc-v-gsp-rm-vm/greeneye/__init__.py
new file mode 100644
index 0000000..8b1c1e5
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/greeneye/__init__.py
@@ -0,0 +1,115 @@
+"""green-eye: Frida-like runtime instrumentation for GSP/uproc firmware in a
+RISC-V QEMU VM.
+
+green-eye talks to QEMU's gdbstub directly (no GDB dependency) and layers a
+scriptable instrumentation API on top: breakpoints, hooks, watchpoints,
+memory inspection, structure decoding, session recording and post-run analysis.
+
+Public API (stable-ish for v0.1):
+
+ import greeneye as ge
+ s = ge.launch(kernel="firmware/uproc_demo/build/uproc_demo.elf")
+ fn = s.symbols.lookup("rpc_sum")
+ h = s.hook(fn, on_enter=lambda hit: print(hit))
+ s.run(duration=2.0)
+ s.close()
+
+Everything is development tooling; see docs/00-OVERVIEW.md.
+"""
+from __future__ import annotations
+
+__version__ = "0.1.0"
+
+from .errors import ( # noqa: F401
+ GreenEyeError,
+ RspError,
+ RspTimeout,
+ RspProtocolError,
+ SymbolNotFound,
+ TargetError,
+ StructError,
+)
+from .rsp import RspClient, StopReply, Register # noqa: F401
+from .elf import FirmwareImage, Segment, ElfSymbol, load_elf # noqa: F401
+from .symbols import Symbol, SymbolDB # noqa: F401
+from .memory import Memory # noqa: F401
+from .structs import Field, Schema, decode, schema_from_json # noqa: F401
+from .record import Recorder, NullRecorder, load_events # noqa: F401
+from .session import Session, Hit, HookHandle, Breakpoint, Watchpoint # noqa: F401
+from .target import QemuTarget # noqa: F401
+
+__all__ = [
+ "attach",
+ "launch",
+ "Session",
+ "Hit",
+ "HookHandle",
+ "Breakpoint",
+ "Watchpoint",
+ "QemuTarget",
+ "RspClient",
+ "SymbolDB",
+ "Symbol",
+ "Memory",
+ "Recorder",
+]
+
+
+def attach(
+ host: str = "127.0.0.1",
+ port: int = 4444,
+ *,
+ timeout: float = 10.0,
+ record: str | None = None,
+ symbols: SymbolDB | None = None,
+ name: str = "attach",
+) -> Session:
+ """Attach to an already-running QEMU gdbstub and return a Session."""
+ client = RspClient(host, port, timeout=timeout)
+ client.connect()
+ client.sync()
+ return Session(client=client, symbols=symbols, record=record, name=name)
+
+
+def launch(
+ *,
+ kernel: str | None = None,
+ machine: str = "virt",
+ memory_mb: int = 256,
+ gdb_port: int = 0,
+ bios: str = "none",
+ extra_args: list[str] | None = None,
+ timeout: float = 10.0,
+ record: str | None = None,
+ symbols: SymbolDB | None = None,
+ name: str = "session",
+ load_symbols: bool = True,
+ keep_alive: bool = False,
+) -> Session:
+ """Launch QEMU (paused), attach, and return a ready Session.
+
+ The target starts paused at its reset vector; use Session.load_image() to
+ load an ELF (which also sets PC), or QemuTarget.run_kernel() style helper
+ launch with kernel= for the fast `-kernel` path.
+ """
+ target = QemuTarget(
+ machine=machine,
+ memory_mb=memory_mb,
+ gdb_port=gdb_port,
+ bios=bios,
+ extra_args=extra_args,
+ kernel=kernel,
+ )
+ if keep_alive:
+ target.keep_alive = True
+ target.start(paused=True)
+ client = RspClient(target.host, target.port, timeout=timeout)
+ client.connect()
+ client.sync()
+
+ symdb = symbols or SymbolDB()
+ sess = Session(client=client, target=target, symbols=symdb, record=record, name=name)
+ if kernel:
+ image = load_elf(kernel)
+ sess.load_image(image, load_symbols=load_symbols)
+ return sess