Snapshot of the stern-event-agent work (as of 2026-10-12): - gamelog.c: passive PAD mode logging bus events (game/ball/bonus/tilt), all named shots and all-players' scores to /dump/mode.log - pad_mode_runtime.c: the SDK runtime + a GAMELOG section (passive stock-mode and award watching, gl_award_seq()/gl_last_award_id()), a per-edge switch logger to /dump/switch.log (switch_names.inc), and a passive Insider Connected gate; docs/runtime-patch.diff shows the exact changes vs the upstream runtime - event_probe.c / event_read.py: event-bus measurement tooling for identifying bus event ids on another game - ports/king_kong_le-0.97.port: 121 verified sites, 55 named shots, 6 bus events (emulator-proven by the SDK repo authors) Deployed and verified on the machine: events, shots, stock modes and awards. The /dump/switch.log feature is implemented but NOT yet deployed or verified, and the extra-ball award id (default 13) is unconfirmed. See README.md for build/install/log usage and unfinished work. Co-Authored-By: Claude Code <noreply@anthropic.com>
53 lines
3.1 KiB
Bash
Executable File
53 lines
3.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# build_mode.sh - compile one or more modes into the mode.so a machine preloads (item 134).
|
|
#
|
|
# build_mode.sh -o mode.so my_mode.c [another_mode.c ...]
|
|
# build_mode.sh -p -o probe.so call_probe.c a porting instrument: no runtime
|
|
#
|
|
# Every mode on a card goes into ONE object with the runtime: it installs each hook once
|
|
# and keeps our modes to one at a time. Needs only arm-linux-gnueabihf-gcc (the app's
|
|
# PAD-Runtime distro has it). Nothing is linked against a libc: the handful of libc calls
|
|
# the runtime makes resolve from the game's own libc when the object loads.
|
|
set -euo pipefail
|
|
SDK=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
OUT=
|
|
RUNTIME=$SDK/pad_mode_runtime.c
|
|
while getopts "o:p" opt; do
|
|
case $opt in
|
|
o) OUT=$OPTARG ;;
|
|
p) RUNTIME= ;;
|
|
*) echo "usage: build_mode.sh -o mode.so mode.c [mode.c ...]" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
shift $((OPTIND - 1))
|
|
[ -n "$OUT" ] && [ $# -ge 1 ] || { echo "usage: build_mode.sh -o mode.so mode.c [mode.c ...]" >&2; exit 2; }
|
|
CC=${CC:-arm-linux-gnueabihf-gcc}
|
|
command -v "$CC" >/dev/null || { echo "build_mode.sh: $CC not found" >&2; exit 1; }
|
|
# -funwind-tables (PAD-381): the game ENDS a process by throwing a C++ exception through its stack
|
|
# (do_stack_unwind_exception_t), at a tilt or the end of a ball. A frame of ours on that stack - the
|
|
# runtime's magnet grab runs as a game process - must carry unwind tables, or the unwind stops there
|
|
# and the game aborts ("terminate called ..."). They cost a few bytes a function and change no code.
|
|
"$CC" -std=gnu17 -marm -mfloat-abi=hard -fno-stack-protector -fPIC -fvisibility=hidden -shared -O2 -nostdlib -funwind-tables \
|
|
-Wall -Wextra -Wno-unused-parameter -Werror=implicit-function-declaration \
|
|
-I"$SDK" -Wl,-soname,mode.so \
|
|
-o "$OUT" ${RUNTIME:+"$RUNTIME"} "$@" -lgcc
|
|
# Undefined symbols are resolved from the game's libc when the object loads - so a
|
|
# misspelt pm_ call would only fail on the machine. Refuse that here, and refuse the libc
|
|
# calls that break the rules (MODE_SDK.md, rule 2): allocation, threads, sleeping, stdio,
|
|
# processes. Plain string and memory calls (strlen, memcpy...) are fine - gcc emits some
|
|
# on its own - and resolve from the game's libc.
|
|
NM=${CC%gcc}nm
|
|
if command -v "$NM" >/dev/null; then
|
|
undefined=$("$NM" -D --undefined-only "$OUT" | awk '{print $NF}' | sed 's/@.*//')
|
|
missing=$(echo "$undefined" | grep -E '^pm_' || true)
|
|
banned=$(echo "$undefined" | grep -E '^(malloc|calloc|realloc|free|posix_memalign|memalign|valloc|_Zn[wa]|_Zd[la]|pthread_|sleep|usleep|nanosleep|select|poll|epoll_|f?printf|puts|fopen|fread|fwrite|fclose|system|popen|fork|exec|wait|signal|sigaction)' || true)
|
|
if [ -n "$missing" ] || [ -n "$banned" ]; then
|
|
rm -f "$OUT"
|
|
[ -n "$missing" ] && echo "build_mode.sh: these pad_mode calls do not exist: $(echo $missing)" >&2
|
|
[ -n "$banned" ] && echo "build_mode.sh: a mode may not call these inside the game (MODE_SDK.md rule 2): $(echo $banned)" >&2
|
|
exit 1
|
|
fi
|
|
echo "libc calls it will resolve from the game: $(echo $undefined)"
|
|
fi
|
|
echo "built $OUT ($(stat -c %s "$OUT") bytes) from: $*"
|