Skip to content

Fix Rosetta x86 debugging through debugserver#25935

Open
0verflowme wants to merge 1 commit into
radareorg:masterfrom
0verflowme:codex/fix-mac-rosetta-breakpoints
Open

Fix Rosetta x86 debugging through debugserver#25935
0verflowme wants to merge 1 commit into
radareorg:masterfrom
0verflowme:codex/fix-mac-rosetta-breakpoints

Conversation

@0verflowme

Copy link
Copy Markdown
Member

Summary

Fixes the Apple Silicon Rosetta x86 debugging path by treating translated x86 processes as LLDB/debugserver remote targets instead of trying to drive them through the native XNU/smach debugger path.

The old architecture mixed three assumptions that do not hold for Rosetta:

  • native XNU task/thread state is the Apple Silicon translated state, not the x86 architectural state users expect
  • software breakpoints patched through the old Mach path can fail when page protections/cache behavior differ from regular writable mappings
  • the GDB/LLDB client did not fully sync target architecture, target XML register profiles, or LLDB stop-packet registers before the first dr/ds/breakpoint operation

This PR rewrites that boundary so Rosetta x86 debugging goes through Apple debugserver/OAH, then synchronizes r2's debug backend, asm arch/bits, register profile, and stop-register cache from the remote target.

What Changed

  • Detect translated x86 processes on Apple Silicon and route spawned/attached Rosetta targets through debugserver + the gdb backend.
  • Prefer /Library/Apple/usr/libexec/oah/debugserver for Rosetta when available, with fallback debugserver discovery.
  • Teach the GDB client to handle LLDB attach flow without GNU extended-mode assumptions.
  • Parse qProcessInfo CPU type to set the target architecture/bits.
  • Read LLDB target XML after attach and sync the r2 debug/analysis register profile before first register reads.
  • Cache LLDB T stop-packet registers and prefer those over per-register pN reads, because OAH exposes the expected x86 architectural state in stop replies.
  • Fix LLDB register buffer sizing: XML register offsets/sizes are bit-based, so register cache packing now converts them to bytes explicitly.
  • Rework Mach memory writes to protect only the required target region/page range, restore original permissions, and flush the instruction cache after writes.
  • Update breakpoint plugin/size when asm.arch changes.
  • Add an r2r regression for asm.arch updating the active breakpoint plugin and default breakpoint size.

Impact

For end users debugging x86_64 Mach-O binaries on Apple Silicon, initial register state, stepping, disassembly at PC, and software breakpoints now operate on the x86 view instead of the translated ARM state. This makes Rosetta debugging usable from r2 instead of landing at ARM trampoline bytes or missing breakpoint traps.

For maintainers, the key design change is that Rosetta is no longer treated as a special case inside native XNU debugging. It is a remote LLDB/debugserver target with explicit architecture/profile synchronization. That keeps the architecture boundary clearer and avoids leaking Rosetta-specific behavior into the native smach path.

Validation

  • make -C libr/io clean > /dev/null && make -C libr/core clean > /dev/null && make -C libr/debug clean > /dev/null && make -j > /dev/null
  • R2R_RADARE2=$PWD/binr/radare2/radare2 R2R_RASM2=$PWD/binr/rasm2/rasm2 ./binr/r2r/r2r test/db/cmd/cmd_bp test/db/cmd/cmd_dr test/db/cmd/cmd_dr_equal test/db/cmd/cmd_regs test/db/cmd/cmd_dh test/db/cmd/cmd_ds
  • R2R_RADARE2=$PWD/binr/radare2/radare2 R2R_RASM2=$PWD/binr/rasm2/rasm2 ./binr/r2r/r2r test/db/io/write test/db/io/maps test/db/io/cache
  • R2R_RADARE2=$PWD/binr/radare2/radare2 R2R_RASM2=$PWD/binr/rasm2/rasm2 ./binr/r2r/r2r test/db/asm/x86_64 test/db/asm/arm_64 test/db/esil/x86_64
  • Rosetta x86 spawn smoke: asm.arch=x86, asm.bits=64, rip points at x86 dyld code, pd decodes x86, and ds advances rip.
  • Software breakpoint smoke at Rosetta x86 rip+3 stops at the expected x86 address.
  • git diff --check

Notes from local validation: native arm64 smach attach is blocked on this machine by unsigned local r2/macOS ptrace restrictions, and LLDB itself fails to attach to an independently running Rosetta /bin/sleep here with attach failed: lost connection. The spawned Rosetta flow, which is the bug path this PR targets, is validated end to end.

@0verflowme 0verflowme marked this pull request as ready for review May 9, 2026 02:07
@trufae

trufae commented May 9, 2026

Copy link
Copy Markdown
Collaborator

Lets split this pr because its currently affecting so many different parts and each change is isolated from the others its hard to review as a whole. Make a separate pr only wirh the code that affects the gdb protocol pls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants