Skip to content

processes: queryable guest process-tree plugin + bulk OSI walk (epic B slice 1) - #897

Open
lacraig2 wants to merge 3 commits into
mainfrom
workspace/proctree-ux
Open

processes: queryable guest process-tree plugin + bulk OSI walk (epic B slice 1)#897
lacraig2 wants to merge 3 commits into
mainfrom
workspace/proctree-ux

Conversation

@lacraig2

Copy link
Copy Markdown
Collaborator

What

Slice 1 of the "system cartography" epic (epic B): a genuinely usable way for both users and the MCP agent to engage with the guest's process tree. Inspired by #699 (Proctree) but a cleaner, DB-backed design.

Two surfaces

AI / MCP — stable, documented, JSON-serializable live query API (portal generators, yield from):

  • processes.get(pid) → flat record or None
  • processes.tree(){"roots": [node, …]} (nested)
  • processes.snapshot(){"processes": […], "tree": {…}}

These read the whole process set in one kernel-side bulk walk (osi.get_all_procsHYPER_OP_OSI_PROC_ALL) — one RCU-consistent snapshot instead of 1 + N per-pid get_proc reads that could tear.

Users — a legible artifact. Lifecycle is recorded to the event DB and system_map.yaml is materialized at teardown: structured per-process records plus an embedded ASCII tree.

schema_version: 1
generated_by: processes
process_count: 72
processes: [{pid, ppid, name, create_time, uid…, exec_count, exit}, …]
tree: |
  init (1)
  `- httpd (400)
     `- status.cgi (517)  [exit: 0]

Persistence (DB-backed)

  • exec_eventProcStart (identity/genealogy: pid, ppid, create_time, comm, ids). argv/env stay on the existing Exec event.
  • exit / exit_groupProcExit. Identity comes off syscall.pid / syscall.create_time (denormalized by the driver) — zero portal round-trips, no read of the dying task.
  • system_map.yaml = ProcStart LEFT JOIN ProcExit on (pid, create_time), re-exec coalesced. Because plugins unload in reverse load order (this plugin's uninit runs before the DB's final flush), teardown calls a new synchronous DB.flush() then DB.query().

Supporting changes

  • osi.get_all_procs() — paginated decode of the slim osi_proc_node array.
  • pengutils.events — lean ProcStart / ProcExit.
  • loggers/db.py — synchronous flush() + query().

Driver-side safety

Live walk + exit path touch only kernel task_struct (comm, skip !mm); never access_remote_vm on userspace, so nothing faults on an exiting/stopped context.

Tests (host-side, penguin.testing; no PANDA/guest)

  • tests/unit/test_processes.py — event→DB emission, DB→render, live tree/get/snapshot join (via doubles).
  • tests/unit/test_osi_bulk.py — real-ISF ABI roundtrip of get_all_procs (skips unless pointed at a driver build carrying the op).
  • tests/unit/test_db.pyflush() / query().

Full tests/unit suite green.

Live validation

Booted an armel/6.13 guest with the driver from rehosting/igloo_driver#88: system_map.yaml captured 72 real processes with correct genealogy, re-exec, and exit codes (proving the syscall_event.pid path), and a probe exercised get_all_procs/snapshot() live through HYPER_OP_OSI_PROC_ALL.

Dependency

Requires rehosting/igloo_driver#88 (HYPER_OP_OSI_PROC_ALL + syscall_event.pid). The live query API needs that driver; the DB-backed system_map.yaml works today. Follow-up: bump IGLOO_DRIVER_VERSION once #88 is released (then test_osi_bulk runs unskipped in CI).

Scope / follow-ons

Slice 1 only. Deferred: thread/kernel-thread enumeration, fd/peer graph, maps/lib inventory, CPU/scheduling, get_ptregs.

@lacraig2
lacraig2 force-pushed the workspace/proctree-ux branch from eb7cb17 to a0c521a Compare July 18, 2026 14:12
lacraig2 added 2 commits July 30, 2026 14:32
…B slice 1)

Adds a `processes` analysis plugin giving users and the MCP agent a model of
the guest process tree, with two surfaces:

- Live query API (portal generators, MCP-shaped stable returns): get(pid),
  tree() -> {roots:[...]}, snapshot(). Built on a single kernel-side bulk walk
  (osi.get_all_procs -> HYPER_OP_OSI_PROC_ALL) rather than 1+N per-pid reads.
- DB-backed lifecycle -> derived artifact: exec_event -> ProcStart,
  exit/exit_group -> ProcExit (identity read off syscall.pid, denormalized by
  the driver -- zero round-trips, no read of the dying task). At teardown the
  plugin flushes + queries the DB and renders system_map.yaml
  (ProcStart LEFT JOIN ProcExit on (pid, create_time); structured records +
  an ASCII tree literal block).

Supporting changes:
- osi.get_all_procs(): paginated decode of the slim osi_proc_node array.
- pengutils.events: lean ProcStart / ProcExit event types.
- loggers/db.py: synchronous flush() + query() (plugins unload in reverse load
  order, so a consumer's uninit runs before the DB's own final flush).

Tests (host-side, penguin.testing harness): test_processes.py (event->DB,
DB->render, live join via doubles), test_osi_bulk.py (real-ISF ABI roundtrip,
skips unless a driver build with the op is provided), test_db.py flush/query.

Depends on rehosting/igloo_driver#88 (HYPER_OP_OSI_PROC_ALL + syscall_event
pid). The live query API needs that driver; the DB-backed system_map works
today. Bump IGLOO_DRIVER_VERSION once #88 is released.
test_osi_bulk now FAILS (not skips) when the pinned driver ISF lacks the op --
a host plugin calling an op its pinned driver doesn't carry is a real
incompatibility, and a silent skip reads as green. The testing harness now
version-keys the ISF cache (.isf_cache/<version>/...) so a driver-pin bump
can't be masked by a stale cached ISF. Documents the release-ordered ABI-test
rule in PYPLUGIN_COVERAGE_PLAN.md. (Driver pin itself now rides main: 0.0.93.)
@lacraig2
lacraig2 force-pushed the workspace/proctree-ux branch from a0c521a to f36f7d2 Compare July 30, 2026 18:34
Add exit_monitor (surfaces the do_exit kprobe's exit_event over
IGLOO_HYP_PROC_EXIT, decoding wait(2)-status) and wire processes to it
behind an opt-in `use_do_exit`. When enabled it is the single exit
source: it captures fatal-signal deaths (SIGSEGV/SIGKILL/...) that the
exit/exit_group syscall hooks miss -- those die via do_exit and issue no
exit syscall -- with the real exit code, and supersedes both the syscall
hooks (now not even registered, so no redundant per-exit firing) and the
host-side signal heuristic (no caught-signal false positives). Disabled
by default; the driver arms the kprobe lazily on enable, so an
un-opted-in run pays nothing.

Bumps IGLOO_DRIVER_VERSION to the release carrying the hook and adds
test_exit_hook_abi as a forcing function (fails until the pinned ISF
carries HYPER_OP_REGISTER_EXIT_HOOK / IGLOO_HYP_PROC_EXIT / exit_event),
mirroring test_osi_bulk. Unit suite 691 passing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant