ERR/E3.0 (slice 3e rung 2): iOS-simulator stepping verified
Closes out E3's stepping-verification ladder to the extent possible headlessly. - Verified `sx build --target ios-sim --emit-obj` produces an arm64-ios-simulator Mach-O that runs under `simctl spawn` and steps in lldb (the backtrace shows a dyld_sim frame — the sim runtime). - Verified the device-applicable .dSYM path: dsymutil collects the DWARF, and after removing the .o lldb still resolves source via the .dSYM. - debug_stepping_smoke.sh gains an optional iOS-sim rung that reuses an already-booted simulator (never boots one — single-sim policy) and exercises the .dSYM path; skips cleanly when no sim is booted. - docs/debugger.md: rungs 1-2 marked verified; the iOS-device rung is documented as a manual checklist (needs hardware + get-task-allow signing) — no compiler gap, --emit-obj + standard Apple tools suffice. E3 is functionally complete and verified across macOS + iOS-simulator.
This commit is contained in:
@@ -403,18 +403,33 @@ Source-level stepping is verified manually/interactively (it needs
|
||||
provisioning profile — not a `run_examples.sh` test). Climb cheapest-first;
|
||||
the device run is the final sign-off:
|
||||
|
||||
1. **macOS native ✅** — `sx build --emit-obj` → drive `lldb --batch` (the
|
||||
debug map resolves to the kept `.o`; no `dsymutil` needed locally).
|
||||
Checked in as `tests/debug_stepping_smoke.sh`: breakpoint on a sx function,
|
||||
`run`, assert it stops at the right `.sx:line`, `next`/`stepi` advance,
|
||||
`bt` is source-mapped. The automatable rung (a checked-in smoke script).
|
||||
2. **iOS simulator** — bundle the `.app`, install to a booted simulator
|
||||
(`simctl`), launch under lldb, repeat the checks. No device, no signing.
|
||||
3. **iOS device (capstone)** — `--debug`: emit DWARF → `dsymutil` `.dSYM`,
|
||||
debug-sign with `get-task-allow`, install via `devicectl`, launch under
|
||||
`debugserver`, attach `lldb`, single-step sx source on the phone. If
|
||||
stepping works *here* — the most locked-down target — the DWARF story
|
||||
is proven everywhere.
|
||||
1. **macOS native ✅ verified** — `sx build --emit-obj` → drive `lldb --batch`
|
||||
(the debug map resolves to the kept `.o`; no `dsymutil` needed locally).
|
||||
Checked in as `tests/debug_stepping_smoke.sh`: file:line breakpoint resolves
|
||||
to `.sx:line` + a source-mapped `bt`. The automatable rung.
|
||||
2. **iOS simulator ✅ verified** — `sx build --target ios-sim --emit-obj`
|
||||
produces an `arm64-ios-simulator` Mach-O that runs under `simctl spawn` and
|
||||
steps in `lldb` (the backtrace shows a `dyld_sim` frame — proof it's the sim
|
||||
runtime). The `tests/debug_stepping_smoke.sh` rung-2 exercises this *against
|
||||
an already-booted sim* (it never boots one itself — use a single simulator);
|
||||
it also collects a `.dSYM` via `dsymutil`, removes the `.o`, and confirms
|
||||
lldb still resolves via the `.dSYM` — proving the device-applicable artifact
|
||||
path. Skipped when no sim is booted.
|
||||
3. **iOS device (capstone) — manual, needs hardware + Apple signing.** Every
|
||||
*technical* piece is already verified above (DWARF, the `.dSYM` workflow,
|
||||
stepping under the sim runtime); the device rung adds only Apple-toolchain
|
||||
steps that require a phone + a development identity, so it's a checklist, not
|
||||
a compiler deliverable:
|
||||
1. `sx build --target ios --emit-obj …` (DWARF in the kept `.o`).
|
||||
2. `dsymutil <binary> -o <App>.app.dSYM` (the `.app` ships no `.o`).
|
||||
3. bundle the `.app` (existing `--bundle` path) + debug-sign with a
|
||||
provisioning profile carrying **`get-task-allow`**.
|
||||
4. `xcrun devicectl device install app …` then launch under `debugserver`.
|
||||
5. attach `lldb` (it finds the adjacent `.dSYM`) and single-step sx source.
|
||||
|
||||
No new compiler code is required — `--emit-obj` + standard Apple tools
|
||||
suffice. (A `--debug` convenience flag that chains 1–4 could be added later,
|
||||
but should be built with a device in hand to verify it.)
|
||||
|
||||
Independently, **Tier-0 always works with no debugger**: a plain on-device
|
||||
run still prints the embedded-`Frame` trace to stderr/`os_log`.
|
||||
@@ -443,8 +458,9 @@ a Mach-O debug map, never register JIT DWARF.
|
||||
| Comptime resolver (`func_id, ir_offset` → location) | ✅ done — slice 3b |
|
||||
| Source snippet + `^` caret | ✅ done — slice 3c (line embedded in `Frame`) |
|
||||
| `--emit-obj` artifact plumbing | ✅ done — slice 3d |
|
||||
| Stepping verification: macOS lldb | ✅ done — slice 3e rung 1 (`tests/debug_stepping_smoke.sh`) |
|
||||
| Stepping verification: iOS simulator → device | ⏳ planned — slice 3e rungs 2–3 (capstone) |
|
||||
| Stepping verification: macOS lldb | ✅ done — 3e rung 1 (`tests/debug_stepping_smoke.sh`) |
|
||||
| Stepping verification: iOS simulator + `.dSYM` path | ✅ done — 3e rung 2 (verified; smoke skips if no booted sim) |
|
||||
| Stepping verification: iOS device | 📋 manual checklist — needs hardware + signing (no compiler gap) |
|
||||
| DWARF variable info (`DILocalVariable`, for `p x`) | ⏳ optional follow-on |
|
||||
|
||||
The active plan and step breakdown live in `current/PLAN-ERR.md`
|
||||
|
||||
@@ -39,16 +39,37 @@ out=$(cd "$ROOT_DIR" && lldb --batch \
|
||||
-o "breakpoint set --file dbg_smoke.sx --line 3" \
|
||||
-o "run" -o "bt" -o "quit" "$BIN" 2>&1)
|
||||
|
||||
rm -f "$SRC" "$BIN" "$TMP/main.o"
|
||||
|
||||
fail=0
|
||||
echo "$out" | grep -q "dbg_smoke.sx:3" || { echo "FAIL: breakpoint did not resolve to dbg_smoke.sx:3"; fail=1; }
|
||||
echo "$out" | grep -q "add at dbg_smoke.sx:3" || { echo "FAIL: stopped frame not source-mapped"; fail=1; }
|
||||
echo "$out" | grep -q "main at dbg_smoke.sx:6" || { echo "FAIL: caller frame not source-mapped"; fail=1; }
|
||||
echo "$out" | grep -q "dbg_smoke.sx:3" || { echo "FAIL[macos]: breakpoint did not resolve to dbg_smoke.sx:3"; fail=1; }
|
||||
echo "$out" | grep -q "add at dbg_smoke.sx:3" || { echo "FAIL[macos]: stopped frame not source-mapped"; fail=1; }
|
||||
echo "$out" | grep -q "main at dbg_smoke.sx:6" || { echo "FAIL[macos]: caller frame not source-mapped"; fail=1; }
|
||||
[[ $fail -eq 0 ]] && echo "ok[macos]: lldb stepped sx source (debug map -> kept .o)"
|
||||
|
||||
if [[ $fail -eq 0 ]]; then
|
||||
echo "ok: lldb stepped sx source (breakpoint + backtrace resolved via DWARF)"
|
||||
exit 0
|
||||
# Rung 2 (iOS simulator) — runs ONLY against an ALREADY-booted simulator; it
|
||||
# never boots one itself (use a single sim — boot one yourself if you want this
|
||||
# rung). Builds for ios-sim, collects a .dSYM (the device-applicable artifact),
|
||||
# and steps in the sim. Skipped if no booted sim / no ios-sim SDK.
|
||||
sim_booted=$(xcrun simctl list devices booted 2>/dev/null | grep -c Booted || true)
|
||||
if [[ "${sim_booted:-0}" -gt 0 ]] && xcrun --sdk iphonesimulator --show-sdk-path >/dev/null 2>&1; then
|
||||
"$SX" build --target ios-sim --emit-obj "$SRC" -o "$BIN" >/dev/null 2>&1 || { echo "FAIL[ios-sim]: build"; fail=1; }
|
||||
dsymutil "$BIN" -o "$BIN.dSYM" >/dev/null 2>&1 # the .app ships a .dSYM, not the .o
|
||||
rm -f "$TMP/main.o" # force resolution via the .dSYM
|
||||
sout=$(cd "$ROOT_DIR" && timeout 120 lldb --batch \
|
||||
-o "breakpoint set --file dbg_smoke.sx --line 3" \
|
||||
-o "run" -o "bt" -o "quit" "$BIN" 2>&1)
|
||||
if echo "$sout" | grep -q "add at dbg_smoke.sx:3" && echo "$sout" | grep -q "main at dbg_smoke.sx:6"; then
|
||||
echo "ok[ios-sim]: lldb stepped sx source in the simulator (via .dSYM)"
|
||||
else
|
||||
echo "FAIL[ios-sim]: lldb did not resolve in the simulator"; fail=1
|
||||
echo "--- ios-sim lldb output ---"; echo "$sout"
|
||||
fi
|
||||
rm -rf "$BIN" "$BIN.dSYM"
|
||||
else
|
||||
echo "skip[ios-sim]: no booted simulator (boot one to exercise this rung)"
|
||||
fi
|
||||
echo "--- lldb output ---"; echo "$out"
|
||||
|
||||
# Rung 3 (iOS device) is a documented manual checklist — see docs/debugger.md.
|
||||
|
||||
rm -f "$SRC" "$BIN" "$TMP/main.o"
|
||||
[[ $fail -eq 0 ]] && exit 0
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user