"""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