Skip to content

GDB Remote Debugging

Dimitris Panokostas edited this page Oct 16, 2026 · 2 revisions

GDB Remote Debugging

Amiberry can expose the emulated 68000-family CPU to a GDB client through the GDB remote serial protocol. The server is part of the built-in debugger. It is off unless a configuration option turns it on, and it is not started from the GUI.

The desktop builds and the libretro core both include it. The server listens on 127.0.0.1 only, accepts one client at a time, and does not authenticate. Any local process that connects can stop the CPU, read and write guest memory, and inject input. With no client attached, the only cost is a non-blocking accept once per frame; nothing traces the CPU.

It came from WinUAE. Amiberry polls it from the normal event loop. Socket code never touches emulated state.

Enabling

Add these lines to a .uae configuration:

debugging_features=gdbserver
gdb_port=2345

or pass them on the command line:

amiberry -s debugging_features=gdbserver -s gdb_port=2345

debugging_features is a comma-separated set. The tokens are segtracker, fsdebug, and gdbserver. The value replaces the previous set, so debugging_features=gdbserver enables the server and turns the other two tokens off. Combine them explicitly if you still want them: debugging_features=segtracker,gdbserver.

gdb_port defaults to 2345. Values outside 1-65535 are stored as 2345. When the server starts, the log contains WinUAE GDB: listening on 127.0.0.1:<port>.

The server is refused when cpu_threaded=true. Amiberry logs WinUAE GDB: not available with the threaded CPU (cpu_threaded=true) and does not listen. Turn threaded CPU off before enabling the server.

The same options apply to a .uae file loaded by the libretro core. There is no separate RetroArch toggle.

Connecting

Use a GDB that knows m68k, for example gdb-multiarch, m68k-elf-gdb, or m68k-amigaos-gdb:

(gdb) set endian big
(gdb) set architecture m68k
(gdb) target remote 127.0.0.1:2345

gdb-multiarch needs set endian big when no m68k executable is loaded. Without it, every register is shown byte-swapped.

The CPU stops at the next debugger boundary when a client attaches. If Amiberry is paused, unpause it first: the CPU has to run to reach that boundary. While the CPU is stopped, the Amiberry window does not update. Ctrl-C in GDB interrupts a running guest and returns to the prompt.

Registers, memory, and execution

GDB can read and write the 18 integer registers: D0-D7, A0-A7, SR, and PC. SR must fit in 16 bits. PC must be even. The m68k FPU registers are listed by GDB and read as <unavailable>.

Memory addresses are physical. Guest MMU translation is not applied.

  • RAM and ROM can be read. RAM can be written. ROM writes fail.
  • Custom chip registers at $DFF000-$DFF1FF can be read from Amiberry's saved register snapshot. Aligned word writes in that range use the debugger's hardware write path. Other I/O is not accessible.
  • info mem lists RAM and ROM regions. Because that map is present, GDB refuses addresses outside it until you allow unlisted regions:
(gdb) set mem inaccessible-by-default off
(gdb) x/2xh 0xdff004

Execution control:

  • Single step.
  • PC breakpoints (break, hbreak). The server installs these in the debugger breakpoint table. GDB must send a length of 2 and the address must be even. With 24-bit addressing, a breakpoint at or above $01000000 is rejected. There are 20 breakpoint slots, shared with the built-in debugger and with condition add.
  • CPU data watchpoints (watch, rwatch, awatch), using the debugger memwatch table. These see CPU data reads and writes only. A watchpoint can be at most 64 KiB long. The end address (address + length) must be at or below the watch limit: $01000000 when 24-bit addressing is on, otherwise $7FFF0000. They are rejected while the debugger's MMU mode is enabled. There are 20 memwatch slots, shared with the built-in debugger and with the monitor watch commands below. GDB's own watchpoints are not listed by monitor watch list.
  • Range stepping (vCont;r): execution continues until the PC leaves the range. At least one instruction runs. An empty range single-steps.

detach, or closing the client, resumes the emulation. See Detaching.

Monitor commands

Amiberry-specific operations use GDB monitor commands. GDB prints the reply as text. On the wire that text is hex-encoded. Most replies are JSON. Integers in that JSON are decimal, not hexadecimal. A slot id of 10 is the JSON number 10 and the hex argument a.

Command arguments are hexadecimal unless a command says otherwise. Write them as 1 to 8 hex digits, separated by single spaces. Do not use a 0x prefix. A command that does not parse returns an error. An unknown command is rejected.

Every command needs a stopped CPU except capabilities, execution-status, and commands that start with input . Those three can be used while the guest runs. Issuing any other monitor command while the CPU is running fails.

monitor capabilities is the command list for the running build. It omits watch, watch-range, and dma-watch while the debugger MMU mode is on. It omits checkpoint in a build without savestate support. The desktop and libretro builds include savestates, so checkpoint is listed there. The capabilities token is watch-range; the command itself is watch range.

Some replies set "truncated":true when the text would exceed half the remote packet size (32768 bytes). A truncated reply is still valid JSON. It is not an error.

Status and memory

monitor capabilities

No arguments. Works while the guest runs. Returns protocol version, CPU model, MMU model, memory_addressing (physical), the command list, and the execution modes continue, step, range-step, and step-over.

monitor execution-status

No arguments. Works while the guest runs. Fields:

Field Meaning
execution running, stopped, or host-paused
debugger_stopped true when the remote debugger has the CPU stopped
host_pause host pause flag, as a number
frame frame counter
vpos, hpos beam position
cycles cycle counter, as a decimal string

monitor memory-map

No arguments. Returns the debugger memory map. addressing is physical. truncated is true if the region table is full (64 regions). Each region has address, size, type (rom, ram, or io), chip, and name.

monitor memory-check ADDRESS LENGTH

Both arguments are hex. LENGTH must be 1 to 8 MiB (800000). The whole range must be writable RAM of one kind, with no ROM or I/O flags and no mixed sub-banks. Chip and fast RAM in the same range fail. Success is {"writable_ram":true,"memory":"chip"} or "fast". Failure is an error, not a JSON false.

Disassembly and screenshots

monitor disasm ADDRESS COUNT

ADDRESS is hex. COUNT is decimal, 1 to 100. The reply is disassembly text, not JSON. The command fails if that text would exceed the packet limit.

(gdb) monitor disasm fc00f0 8

monitor screenshot PATH

PATH is the rest of the line, a native host path. Spaces are part of the path. Quotes are not stripped. Writes a PNG to that path. It does not change screenshot preferences and does not show a status-line message. Requires a stopped CPU.

(gdb) monitor screenshot /tmp/amiberry.png

Tasks, segments, and program entry

monitor tasks

Returns Exec tasks in tasks: the current task, then the ready list, then the waiting list. Each entry has address, name, list (current, ready, or waiting), type (1 task, 13 process), state, saved_sp, stack_lower, stack_upper, and signals_wait. truncated is true if the packet limit cut the list. The reader also stops at 128 tasks.

monitor segments [ADDRESS]

ADDRESS, if given, is a longword-aligned, non-zero process address. Omitted, it reads the current process (ThisTask). The reply has process, name, command (the CLI command, or empty), and segments. Each segment has index, address (the first instruction, four bytes after the segment header), and size.

monitor process-break name NAME

Arms a one-shot stop at an AmigaDOS program entry. NAME is the rest of the line: 1 to 255 characters, ASCII 32-126. Matching is case-insensitive against the process name or the CLI command. If NAME contains no : or /, it is compared with the part of that string after the last : or /. The stop happens when the PC equals the first segment's start address and the PC is not in ROM. The stop is consumed when it hits.

(gdb) monitor process-break name myprogram
(gdb) continue

monitor process-break address ADDRESS

Same one-shot stop, but only for the process whose Exec task address is ADDRESS. The address must be longword-aligned and non-zero.

monitor process-break status

Returns armed, name, and address.

monitor process-break clear

Cancels the armed stop.

History, conditions, and step-over

monitor history on and monitor history off

history on keeps per-instruction debugger checks active so the existing debugger history buffer fills while the CPU runs. The buffer holds 500 entries. A repeated PC is not stored again. history off stops further recording. Neither command clears the buffer. Both require a stopped CPU; recording happens after you continue.

monitor history read COUNT

COUNT is hex, 1 to 80 (128 decimal). Returns recording (whether history on is set) and entries. Each entry has pc, frame, vpos, hpos, and registers (D0-D7, then A0-A7). If the packet limit is hit, truncated is true and the reply keeps the newest entries, listed oldest first.

monitor condition add REGISTER OPERATOR VALUE MASK SIGNED

Five hex words. Uses a free slot in the 20-entry breakpoint table, shared with GDB breakpoints and the built-in debugger. When the condition is true at a debugger check, the CPU stops. Reply is {"id":N} with a decimal id.

Word Meaning
REGISTER 0-7 = D0-D7, 8-15 = A0-A7, 17 = USP, 18 = MSP, 19 = ISP, 20 = VBR, 21 = SR. PC (16) and anything above SR are rejected.
OPERATOR 0 ==, 1 !=, 2 <=, 3 >=, 4 <, 5 >. Range operators are not accepted.
VALUE compare value
MASK applied before the compare
SIGNED 0 or 1. A signed compare treats the masked value as a byte when the mask is ff, a word when it is ffff, otherwise a long.
(gdb) monitor condition add 0 0 1 ffffffff 0

That stops when D0 equals 1.

monitor condition list

JSON array of {id, register, operator, value, mask, signed}.

monitor condition remove ID

ID is the decimal slot from condition add, written in hex. Slot 10 is a, not 10.

monitor step-over

Runs until the address after the instruction at PC, which steps over JSR and BSR. GDB reports the target as running until that stop. Requires a stopped CPU.

Exceptions

monitor exception-mask MASK

MASK is 1 to 16 hex digits. Bit N selects exception vector N. Bits 0 and 1 must be clear, so vectors 0 and 1 cannot be selected. Vectors 2 through 63 are acted on. When a selected exception is taken, Amiberry snapshots the registers before the CPU builds the exception frame, then stops at the next debugger boundary. GDB's stop reason carries the vector and the faulting instruction PC.

(gdb) monitor exception-mask c

c is bits 2 and 3: bus error and address error.

monitor exception

Returns the current mask as 16 hex digits, and last. last is null if no selected exception has been captured. Otherwise it has vector, instruction_pc, registers (D0-D7, A0-A7, SR, PC, taken before the exception frame), cpu_model, mmu_model, vbr, usp, isp, msp, and memory_fault.

memory_fault is null when the exception was not a memory fault. Otherwise it has address, access (unknown, read, write, or read-modify-write), size (or null), function_code, and mmu_status. mmu_status is a number only for vector 2 when an MMU model is configured; otherwise it is null.

Watches

These commands are rejected while the debugger MMU mode is enabled, and monitor capabilities omits them in that mode. The end of every watch (address + length) must be at or below the watch limit: $01000000 with 24-bit addressing, otherwise $7FFF0000. There are 20 memwatch slots in total.

monitor watch add ADDRESS SIZE ACCESS SOURCES VALUE-ENABLED VALUE VALUE-MASK CHANGE-ONLY LOG-ONLY

Nine hex words. This is an exact watch: the access address and width must both match. Reply is {"id":N}.

Word Meaning
ADDRESS start address, aligned to SIZE
SIZE 1, 2, or 4
ACCESS 1 read, 2 write, 3 read and write. Instruction fetch is not allowed.
SOURCES source mask from the table below. Must be non-zero, and must not include CPU instruction fetch (bit 0).
VALUE-ENABLED 0 or 1. When 1, the access value is compared with VALUE through VALUE-MASK.
VALUE compare value
VALUE-MASK bits that participate in the value compare
CHANGE-ONLY 0 or 1. Only allowed when ACCESS is 2 (write). The watched bytes must be readable RAM. A write that does not change the old value does not hit.
LOG-ONLY 0 or 1. When 1, the hit is recorded and the CPU is not stopped.
(gdb) monitor watch add 2000 2 2 4 0 0 0 0 0

Word write at $2000 by the CPU, stop on hit.

monitor watch range ADDRESS LENGTH ACCESS SOURCES VALUE-ENABLED VALUE VALUE-MASK CHANGE-ONLY LOG-ONLY

Same nine words. Any access that overlaps the range matches. LENGTH is 1 to 10000 (64 KiB). ACCESS is 1 to 7: bit 0 read, bit 1 write, bit 2 instruction fetch. The instruction-fetch bit and CPU instruction fetch in SOURCES must both be set or both be clear. If ACCESS includes a read or a write, SOURCES must include something other than CPU instruction fetch. A value compare is allowed only when LENGTH is 1, 2, or 4. CHANGE-ONLY has the same write-only and readable-RAM rules as watch add.

(gdb) monitor watch range c00000 100 3 6 0 0 0 0 1

Log CPU data reads and writes that overlap $C00000 for $100 bytes, without stopping.

monitor watch list

JSON array of predicate watches (watch add and watch range). Fields: id, address, size, access, sources, value (null if value matching is off), mask, change_only, log_only, range.

monitor watch remove ID

ID is the decimal slot, written in hex. The slot must be a predicate watch.

monitor watch events

Up to 64 recorded hits, oldest first, plus dropped (hits overwritten in the ring). Each hit has sequence, id, address, size, access, source, register, instruction_pc, value, and old_value (null when the old value was not read).

monitor watch last

The newest hit, or null.

monitor watch clear-events

Clears the ring, including dropped, and returns the empty snapshot.

monitor dma-watch add ADDRESS LENGTH MODE MASK

Four hex words. LENGTH is 1 to 10000. MODE is 1 read, 2 write, or 3 both. MASK is a DMA source mask: it must be non-zero and must not include the CPU bits (bits 0-2). An identical DMA watch that already exists is returned instead of allocating another slot. The reply is the decimal slot id as plain text, not a JSON object.

(gdb) monitor dma-watch add 0 1000 1 200

Copper reads in the first $1000 bytes of chip memory. 200 is the copper source bit.

monitor dma-watch list

JSON array of {id, address, length, mode, mask}.

monitor dma-watch remove ID

Hex slot id. The slot must be a DMA watch.

Source mask bits, shared by SOURCES and DMA MASK:

Bit Hex Source
0 1 CPU instruction fetch. Not valid in a DMA mask or in watch add.
1 2 CPU data read. Not valid in a DMA mask.
2 4 CPU data write. Not valid in a DMA mask.
3 8 Blitter A
4 10 Blitter B
5 20 Blitter C
6 40 Blitter D, normal
7 80 Blitter D, line
8 100 Blitter D, fill
9 200 Copper
10 400 Disk
11 800 Audio channel 0
12 1000 Audio channel 1
13 2000 Audio channel 2
14 4000 Audio channel 3
15-22 8000 through 400000 Bitplanes 0-7
23-30 800000 through 40000000 Sprites 0-7

Combine bits in one hex word. CPU data read and write together is 6.

Guest output

monitor guest-output on|off|read|clear

Captures strings written by uaelib function 86. The guest calls that function with a C string pointer as the argument. Amiberry also writes the same text to the host log as DBG: .... The uaelib call returns 1 when the address is valid, otherwise 0.

Capture happens only while output is enabled, including while the CPU is running. Enable it while stopped, continue, then stop again to read. off disables capture and keeps the records. clear drops the records and leaves capture enabled. read only reports. All four commands return the same snapshot: enabled, dropped, and records. Each record has id, text, and truncated.

The buffer keeps at most 64 records and 4096 bytes. Each string is cut at 1024 bytes; that record's truncated flag is then true. dropped counts records discarded to stay inside those limits.

(gdb) monitor guest-output on
(gdb) continue
(gdb) monitor guest-output read

The last command needs the CPU stopped again.

Checkpoints

monitor checkpoint save PATH and monitor checkpoint restore PATH

PATH is the rest of the line, a native host path. Spaces are part of the path. Neither command returns until it finishes. Both fail if a savestate is already in progress, the emulator is quitting, input recording or playback is active, or the configuration cannot be saved.

save checks that the file can be created, runs to the next frame start (state files are only valid there), writes the state, and stops. A stop before that frame start cancels the save.

restore requires a file whose header is ASF . It follows the normal reset and restore path and keeps the GDB connection. Before the state is loaded it clears remote breakpoints, GDB watchpoints, watch add / watch range watches, DMA watches, conditions, the exception mask, the process-break, range stepping, history recording, captured guest output, the watch event log, and injected input. Breakpoints and watchpoints set from Amiberry's own debugger stay.

(gdb) monitor checkpoint save /tmp/amiberry-stop.uss

Input

Input commands work while the guest runs. They fail while Amiberry is recording or playing back input. input event also fails while a sequence is running.

monitor input event KIND PORT CODE VALUE

Four hex words.

| KIND | PORT | CODE | VALUE | | 0 keyboard | must be 0 | Amiga raw keycode, 00 to 67 | 0 up, 1 down | | 1 relative mouse | 0 or 1 | 0 horizontal, 1 vertical | signed count, -127 to 127 | | 2 joystick | 0 or 1 | 0 left, 1 right, 2 up, 3 down, 4 fire, 5 second button, 6 third button | 0 release, 1 press |

Mouse counts bypass host scaling and window coordinates. A negative count is the 8-bit value sign-extended to 32 bits: -1 is ffffffff, -127 is ffffff81. -128 is rejected.

Keyboard codes are Amiga raw keycodes, not host scancodes. Common values: space 40, backspace 41, tab 42, enter 43, return 44, escape 45, delete 46, cursor up 4c, down 4d, right 4e, left 4f, help 5f, left shift 60, right shift 61, caps lock 62, control 63, left Alt 64, right Alt 65, left Amiga 66, right Amiga 67. A is 20. Digits 1 to 9 are 01 to 09, and 0 is 0a.

(gdb) monitor input event 0 0 44 1
(gdb) monitor input event 2 1 4 1

Return down, then joystick port 1 fire down.

monitor input sequence STEPS

STEPS is one or more groups of five hex words, separated by ; with no space after the semicolon:

DELAY KIND PORT CODE VALUE;DELAY KIND PORT CODE VALUE

DELAY is the number of frames to wait before that event, added to the previous step's due time. The first step waits DELAY frames from the start. A delay of 0 fires on the first frame check. Kind 3 with port, code, and value all 0 is a delay with no input. Kind 3 is not valid in input event.

At most 256 steps. The sum of the delays must be at most 3600 frames (e10 in hex). The command fails if a sequence is already running or if a key or joystick button injected by these commands is still held. A trailing semicolon is an error. The reply is the same status object as input status.

(gdb) monitor input sequence 0 0 0 40 1;5 0 0 40 0

Space down immediately, space up after 5 frames.

monitor input status

Returns held (keys and joystick buttons still down, each {kind, port, code}) and sequence: id, state (idle, running, completed, or cancelled), elapsed_frames, next, and total.

monitor input release

Cancels a running sequence, releases keys and joystick buttons injected by these commands, and returns the same status object. Relative mouse counts are not held.

Examples

Connect, allow custom-register reads, and stop on a program entry:

(gdb) set endian big
(gdb) set architecture m68k
(gdb) target remote 127.0.0.1:2345
(gdb) set mem inaccessible-by-default off
(gdb) x/2xh 0xdff004
(gdb) monitor tasks
(gdb) monitor process-break name myprogram
(gdb) continue

After that stop, the PC is the first instruction of the program's first hunk. monitor segments with no address describes that process.

A hardware breakpoint and a CPU write watch:

(gdb) hbreak *0x4000
(gdb) monitor watch add 2000 4 2 4 1 ffffffff ffffffff 1 0
(gdb) continue

The watch stops on a CPU long write at $2000 whose value, through the mask, equals $FFFFFFFF, and only when the old RAM value changes.

Detaching

detach, or closing the client, resumes the emulation. It removes PC breakpoints and watchpoints the client installed, including watch add, watch range, and dma-watch entries, and it clears conditions, the exception mask, the process-break, history recording, captured guest output, the watch event log, and injected input. Breakpoints and watchpoints set from Amiberry's own debugger stay.

A reset of the emulated machine closes the connection. A checkpoint restore is the exception: that reset keeps the client connected.

IPC

The same monitor commands can be run over the IPC socket with MONITOR <text>, without a GDB client attached. See IPC Socket Support - Debugger Monitor for command syntax, reply framing, execution rules, native stop reasons in DEBUG_STATUS, and the ownership rules between IPC and GDB.

Clone this wiki locally