127 lines
4 KiB
Bash
Executable file
127 lines
4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# probeReplSmoke.sh - non-interactive smoke check for mameDebug.py
|
|
# --repl mode. Pipes a canned script (`break main`, `run`, `where`,
|
|
# `quit`) into the REPL and asserts that:
|
|
# 1. The REPL parses each command without error
|
|
# 2. A breakpoint resolves through the link816 map
|
|
# 3. MAME launches with the bp installed and surfaces a BP-HIT line
|
|
# 4. `where` resolves the captured PC to a source line via DWARF
|
|
#
|
|
# Exit 0 on full pass. Exit 77 (autotools "skip") if MAME / toolchain
|
|
# missing. Exit 1 on any unexpected REPL output or missing capture.
|
|
#
|
|
# Usage: probeReplSmoke.sh [--verbose]
|
|
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
ROOT="$(cd "$HERE/.." && pwd)"
|
|
VERBOSE=0
|
|
if [ "${1:-}" = "--verbose" ]; then
|
|
VERBOSE=1
|
|
fi
|
|
|
|
CLANG="$ROOT/tools/llvm-mos-build/bin/clang"
|
|
LLVMMC="$ROOT/tools/llvm-mos-build/bin/llvm-mc"
|
|
LINK="$ROOT/tools/link816"
|
|
|
|
if [ ! -x "$CLANG" ] || [ ! -x "$LLVMMC" ] || [ ! -x "$LINK" ]; then
|
|
echo "probeReplSmoke: missing toolchain (clang/llvm-mc/link816)" >&2
|
|
exit 77
|
|
fi
|
|
if ! command -v mame >/dev/null 2>&1; then
|
|
echo "probeReplSmoke: mame not on PATH; skipping" >&2
|
|
exit 77
|
|
fi
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
CFILE="$WORK/repltest.c"
|
|
OFILE="$WORK/repltest.o"
|
|
OCRT0="$WORK/crt0.o"
|
|
OLIBGCC="$WORK/libgcc.o"
|
|
BIN="$WORK/repltest.bin"
|
|
MAP="$WORK/repltest.map"
|
|
DWARF="$WORK/repltest.dwarf"
|
|
OUT="$WORK/repl.out"
|
|
|
|
cat > "$CFILE" <<'EOF'
|
|
int gAnswer = 42;
|
|
int add(int a, int b) {
|
|
int c = a + b;
|
|
return c;
|
|
}
|
|
int main(void) {
|
|
int r = add(3, 4);
|
|
gAnswer = r;
|
|
while (1) { }
|
|
return r;
|
|
}
|
|
EOF
|
|
|
|
"$CLANG" --target=w65816 -O0 -g -ffunction-sections \
|
|
-c "$CFILE" -o "$OFILE" 2>/dev/null
|
|
"$LLVMMC" -arch=w65816 -filetype=obj \
|
|
"$ROOT/runtime/src/crt0.s" -o "$OCRT0" 2>/dev/null
|
|
"$LLVMMC" -arch=w65816 -filetype=obj \
|
|
"$ROOT/runtime/src/libgcc.s" -o "$OLIBGCC" 2>/dev/null
|
|
"$LINK" -o "$BIN" --text-base 0x1000 \
|
|
--map "$MAP" --debug-out "$DWARF" \
|
|
"$OCRT0" "$OFILE" "$OLIBGCC" >/dev/null 2>&1 || true
|
|
|
|
[ -s "$BIN" ] || { echo "probeReplSmoke: empty .bin"; exit 1; }
|
|
[ -s "$DWARF" ] || { echo "probeReplSmoke: empty DWARF sidecar"; exit 1; }
|
|
[ -s "$MAP" ] || { echo "probeReplSmoke: empty map"; exit 1; }
|
|
|
|
# Pipe the canned REPL script.
|
|
printf 'break main\nrun\nwhere\nquit\n' \
|
|
| timeout 60 python3 "$HERE/mameDebug.py" --repl \
|
|
--bin "$BIN" --map "$MAP" --dwarf "$DWARF" \
|
|
--seconds 4 > "$OUT" 2>&1 || {
|
|
echo "probeReplSmoke: mameDebug.py --repl failed" >&2
|
|
cat "$OUT" >&2
|
|
exit 1
|
|
}
|
|
|
|
if [ "$VERBOSE" -eq 1 ]; then
|
|
cat "$OUT" >&2
|
|
fi
|
|
|
|
# Required output lines:
|
|
# "(dbg) break main" - command echo
|
|
# " bp #1 at 0x...... (main)" - bp set ack
|
|
# "(dbg) run" - command echo
|
|
# " PC=0x...... ... FUNC=main ..." - where output after run
|
|
# "(dbg) where" - command echo
|
|
# " PC=0x...... ... FUNC=main ..." - where output (manual)
|
|
# "(dbg) quit" - command echo
|
|
if ! grep -q "bp #1 at 0x" "$OUT"; then
|
|
echo "probeReplSmoke: missing 'bp #1 at 0x...' breakpoint ack" >&2
|
|
cat "$OUT" >&2
|
|
exit 1
|
|
fi
|
|
if ! grep -q "FUNC=main" "$OUT"; then
|
|
echo "probeReplSmoke: missing FUNC=main in 'where' output" >&2
|
|
cat "$OUT" >&2
|
|
exit 1
|
|
fi
|
|
# The `where` command (run AFTER the `run` command) must produce
|
|
# output too — verify by counting occurrences of "PC=0x" prefix lines.
|
|
PC_HITS=$(grep -c "^ PC=0x" "$OUT" || true)
|
|
if [ "$PC_HITS" -lt 2 ]; then
|
|
echo "probeReplSmoke: expected >= 2 PC=0x lines (run + where), got $PC_HITS" >&2
|
|
cat "$OUT" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Bonus: verify the captured PC equals the map entry for `main`.
|
|
MAIN_PC=$(awk '$2 == "main" { print $1; exit }' "$MAP")
|
|
[ -n "$MAIN_PC" ] || { echo "probeReplSmoke: no 'main' symbol in map"; exit 1; }
|
|
MAIN_PC_LC=$(echo "$MAIN_PC" | tr 'A-Z' 'a-z')
|
|
if ! grep -qi "PC=$MAIN_PC_LC " "$OUT"; then
|
|
echo "probeReplSmoke: captured PC does not match map[main]=$MAIN_PC" >&2
|
|
cat "$OUT" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "probeReplSmoke: OK (bp resolved, BP-HIT captured, where decoded)"
|
|
exit 0
|