probegen
Tool
tools/pe/probegen.py(program, Windows PE). Write a probe library: a stand-in for a DLL a game imports, which logs every call it gets.
Run it with ./gameframe run probegen ARGS or python3 tools/pe/probegen.py. Source on GitHub.
Its own help
This is the help text in the tool itself, as ./gameframe tool probegen prints it.
text
Write a probe library: a stand-in for a DLL a game imports, which logs every call it gets.
Usage: probegen.py GAME.EXE DLL OUT_DIR [--words N] [--stdcall NAME=BYTES ...] [--log FILE]
GAME.EXE the 32-bit Windows program (or DLL) that imports DLL
DLL the library to stand in for, as the import table names it (glide2x.dll, S3DTKW.DLL)
OUT_DIR where to write NAME.c, NAME.def and build.sh
--words N for an import whose argument size is unknown, log N stack words (default 4)
--stdcall NAME=BYTES the import NAME is __stdcall and takes BYTES of arguments (the callee
removes them). Decorated names (_grDrawTriangle@12) say this already; undecorated
ones (S3DTK_InitLib) need it, or the game's stack goes wrong after the call
--log FILE the log file the probe writes, in the game's folder (default probe-NAME.log)
Then `sh OUT_DIR/build.sh` builds NAME.dll with `zig cc -target x86-windows-gnu`. Put it beside
the game in place of the real library and run the game (in Wine or a VM). Each call appends one
line to the log: the import's name, then each argument word in hex. A pointer argument shows
as an address. Every stub returns 0.
Why: before a replacement library can draw anything, you need to know which calls the game
makes, in which order, and with what arguments. A probe answers that from the running game,
with no SDK and no headers. POD settled the layouts of two card APIs this way
(docs/hardware/replacement-libraries.md, "Start with a probe").
The exports are exactly the import table's names, through the .def file, so decorated
stdcall names such as `_grGlideInit@0` match. Imports by ordinal are exported at the same
ordinal. The probe uses only kernel32 (CreateFileA, WriteFile, CloseHandle): no C runtime.
It does not read through pointers, return useful values, or keep a game running past the
first call whose result it checks. Standard library and pefile.