#!/usr/bin/env bash # mameDebug.sh - source-level breakpoint+step driver for a W65816 .bin # under MAME. # # Workflow: # 1. Build with `-g` and link with `--debug-out FOO.dwarf --map FOO.map`. # 2. Run this script with the binary + a breakpoint (function name or # source line) + optional step commands. # 3. Each hit prints `PC=0xNNNN FILE=foo.c LINE=N FUNC=bar` resolved # via pc2line.py. # # Usage: # scripts/mameDebug.sh [--break FUNC] [--break FILE:LINE] # [--steps N] # # Without --break, runs until the program halts (BRK or wild jump). # --break FUNC sets a breakpoint at the function's entry; --break FILE:LINE # resolves the line to a PC via pc2line.py and breaks there. # --steps N single-steps N times after the first break, printing the # source location at each step. set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" BIN="" MAP="" DWARF="" BREAKS=() STEPS=0 while [ $# -gt 0 ]; do case "$1" in --break) BREAKS+=("$2"); shift 2;; --steps) STEPS="$2"; shift 2;; *) if [ -z "$BIN" ]; then BIN="$1" elif [ -z "$MAP" ]; then MAP="$1" elif [ -z "$DWARF" ]; then DWARF="$1" else echo "unexpected arg: $1" >&2; exit 2 fi shift ;; esac done if [ -z "$BIN" ] || [ -z "$MAP" ] || [ -z "$DWARF" ]; then echo "usage: $0 [--break SYM_or_FILE:LINE]... [--steps N]" >&2 exit 2 fi # Resolve each --break argument to a PC. FUNC -> map lookup; FILE:LINE -> # pc2line.py --dump | grep. resolveBreak() { local spec="$1" if [[ "$spec" == *:* ]]; then local file="${spec%:*}" local line="${spec##*:}" python3 "$SCRIPT_DIR/pc2line.py" --sidecar "$DWARF" --map "$MAP" --dump | awk -v f="$file" -v l="$line" ' $2 == (f":" l) { print $1; exit } ' else awk -v s="$spec" '$2 == s { print $1; exit }' "$MAP" fi } BP_PCS=() for spec in "${BREAKS[@]+"${BREAKS[@]}"}"; do pc=$(resolveBreak "$spec") if [ -z "$pc" ]; then echo "mameDebug: can't resolve breakpoint '$spec'" >&2 exit 1 fi BP_PCS+=("$pc") echo "[mameDebug] break $spec -> $pc" done # Build a Lua script that MAME runs. Halts at the first breakpoint, # prints PC, single-steps STEPS times printing each PC, then exits. LUA_FILE=$(mktemp --suffix=.lua) trap 'rm -f "$LUA_FILE"' EXIT cat > "$LUA_FILE" <&1 | grep -E '^\[mameDebug-lua\]|^PC=' | tee /tmp/mameDebug.trace # Resolve each PC line in the trace. echo "[mameDebug] done; trace saved at /tmp/mameDebug.trace"