Skip to content

memrec ​

Tool tools/live/memrec.py (program, The running game). Read a running game's memory from outside: snapshots to diff, and recordings of named values.

Run it with ./gameframe run memrec ARGS or python3 tools/live/memrec.py. Source on GitHub.

Its own help ​

This is the help text in the tool itself, as ./gameframe tool memrec prints it.

text
Read a running game's memory from outside: snapshots to diff, and recordings of named values.

Usage: memrec.py snap   PROCESS --out DIR
       memrec.py record PROCESS SPEC [--rate HZ] [--seconds S] [--wait ADDR=VALUE[:TYPE]]
                        [--out FILE]
       memrec.py read   PROCESS ADDR [TYPE] [COUNT]

  PROCESS        --pid PID, or --name TEXT: the process whose program holds TEXT (Wine names
                 a game's process after its EXE), else one whose arguments hold it, never a
                 shell or launcher that started the game. Found again on every poll, so a game
                 that restarts is followed
  --proc DIR     where the process folders are (default /proc); tests use a folder of their own
  snap           copy every writable mapping (rw in /proc/PID/maps) to DIR/0xSTART.bin and list
                 them. Take one, change the value in the game, take another, then compare them
                 with tools/triage/memscan.py DUMP:RULE ... --base 0xSTART
  record         sample the values SPEC names, RATE times a second (default 10), for S seconds
                 (default: until the process ends or Ctrl-C), as JSON Lines in FILE (default
                 stdout): {"t": seconds, "n": sample, "NAME": value or [values], ...}
  --wait         start recording only when ADDR holds VALUE (a phase, a level number)
  read           print COUNT values (default 1) of TYPE (default u32) at ADDR

SPEC is a text file, one value a line: `NAME ADDRESS TYPE [COUNT [STRIDE]]`, with # comments.
TYPE is u8 i8 u16 i16 u32 i32 u64 i64 f32 f64; COUNT values STRIDE bytes apart (default the
type's size) make an array, such as eight cars' x positions: `car_x 0x61aad0 i32 8 0x558`.

Why: a port that must behave like the original needs a reference run. The simplest recorder
reads the game's memory from outside. Nothing is injected. The game is not changed or slowed.
Values are kept as raw integers, so 16.16 fixed point is not rounded. A sample is not atomic.
The values are read one after another while the game runs, so one sample can straddle frames.
At 10 Hz an outside reader sees about one frame in eight
(docs/knowhow/record-a-run-from-memory.md).

It reads /proc/PID/mem, so it runs where the game runs on Linux: Wine on Linux, or Wine inside
a Linux VM. Reading another process's memory needs root, or the same user with
kernel.yama.ptrace_scope set to 0. It does not run on macOS or Windows. It never writes to the
process. Standard library only.

Named by ​

Skills: re-observe, re-verify.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.