diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/greeneye/__init__.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/greeneye/__init__.py | 115 |
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 |
