@node Debugging
@chapter Debugging

@cindex debugging
@cindex gdb
@cindex breakpoints
@cindex watch variables
@cindex call stack
@cindex User Screen

xwpe integrates with gdb to provide a source-level debugging
environment.  You can set breakpoints, inspect variables, step through
code, view the call stack, and see program output --- all from within
the editor, without screen flicker.

This chapter was verified on 2026-06-01 with xwpe 1.6.3, gdb 17.2,
gcc 15.2, g++ 15.2, gfortran 15.2, fpc 3.2.2, OpenJDK jdb 25,
and Python pdb 3.13.

@section Quick start

@enumerate
@item
Open a source file: @command{wpe debug_test.c} (use @command{wpe},
not @command{we} --- the debugger requires programming mode).

@item
Move to a line inside @code{main()} and press @kbd{Ctrl-G B} to set
a breakpoint.  The line is highlighted.

@item
Press @kbd{Ctrl-G R} to compile, link, and start gdb.  Execution
stops at the breakpoint.

@item
Press @key{F8} to step over lines.  Press @key{F7} to step into
function calls.  The cursor follows execution in the source code.

@item
Press @kbd{Ctrl-G W}, type a variable name, press @key{Return}.
The Watch Window shows its value, updated after each step.

@item
Press @kbd{Ctrl-G K} to see the call stack.

@item
Press @kbd{Ctrl-G P} to see program output (printf, etc.).
Press any key to return to the editor.

@item
Press @kbd{Ctrl-G Q} to quit the debugger.
@end enumerate

@section Debug menu reference

All commands are available from the @samp{Debug} menu (@kbd{Alt-D})
and via @kbd{Ctrl-G} prefix shortcuts:

@multitable @columnfractions .30 .18 .18 .34
@headitem Command @tab Menu key @tab Shortcut @tab Description
@item Toggle Breakpoint @tab B @tab Ctrl-G B @tab Set/remove breakpoint at cursor
@item Remove all Breakp. @tab M @tab Ctrl-G M @tab Clear all breakpoints
@item Make Watch @tab W @tab Ctrl-G W @tab Add variable to Watch Window
@item Edit watch @tab E @tab Ctrl-G E @tab Edit a watched expression
@item Delete watch @tab D @tab Ctrl-G D @tab Remove a watched variable
@item Remove All watches @tab A @tab Ctrl-G A @tab Clear all watches
@item Show stacK @tab K @tab Ctrl-G K @tab Show call stack
@item Goto cursor @tab U @tab Ctrl-G U @tab Run until cursor line
@item Finish function @tab F @tab Ctrl-G F @tab Run until function returns
@item Trace (step into) @tab T @tab Ctrl-G T @tab Execute one line, enter functions
@item Step (step over) @tab S @tab Ctrl-G S @tab Execute one line, skip functions
@item Run/Continue @tab R @tab Ctrl-G R @tab Start or continue execution
@item Program output @tab P @tab Ctrl-G P @tab Show program's stdout
@item debugger Options @tab O @tab Ctrl-G O @tab Select debugger backend
@item Quit @tab Q @tab Ctrl-G Q @tab Stop debugger
@end multitable

@noindent
Alternative keys (when function keys are available):
Ctrl-F8 = Toggle Breakpoint, Ctrl-F7 = Make Watch, Ctrl-F6 = Stack,
F7 = Trace, F8 = Step, Ctrl-F10 = Run, Ctrl-F2 = Quit.

@section Compiling for debugging

Compile with debug symbols (@code{-g}) and no optimisation
(@code{-O0}) for best results.  xwpe's default compiler options
include @code{-g}.  To add @code{-O0}, go to
@samp{Options @result{} Compiler} and append it to Compiler Options.

@section Choosing the start symbol

@cindex start symbol
@cindex constructor
@cindex breakpoint before main

By default the debugger sets its initial breakpoint at @code{main} and
runs the program up to it.  Some code runs @emph{before} @code{main} ---
for example a function marked @code{__attribute__((constructor))}, or a
C++ global object's constructor.  To stop there instead, set the start
symbol via @samp{Options @result{} Compiler @result{} start symbol} to
the name of the function you want to break at.

The example @file{docs/examples/debug_constructor.c} has a @code{setup()}
function that runs before @code{main()}.  Set the start symbol to
@code{setup}, press @kbd{Ctrl-G R}, and execution stops in @code{setup()}
before @code{main()} is reached.

@section Program output (User Screen)

@cindex User Screen
@cindex Ctrl-G P
@cindex program output
@cindex pty

Program output (e.g.@: @code{printf}, @code{System.out.println},
@code{print()}) is appended to the Messages buffer --- no screen
switching, no flicker.  For gdb, output is captured via a
pseudoterminal (pty): the program's stdout is redirected to a pty
slave and xwpe reads the pty master.  For jdb and pdb, output is
extracted from the debugger's command pipe.

Press @kbd{Ctrl-G P} (or @samp{Debug @result{} Program output}) to
view the Messages buffer with full scroll.  The output accumulates
across steps, so you can see the complete program output at any time.

@cindex Alt-F5
A line-oriented panel cannot show a program that @emph{paints} (ANSI
colour, cursor positioning, a TUI, a progress bar).  For that, the
Borland @dfn{User Screen} on @kbd{Alt-F5} replays the program's own
full screen verbatim, then returns to the editor on any key.  This works
in the console (@command{wpe}) today; in @command{xwpe} (X11) it arrives
with the integrated terminal in a later release (until then @kbd{Alt-F5}
focuses the Messages panel).

@strong{Important}: the output appears only after the line that
produces it has been @emph{executed}.  If the cursor is on the
@code{printf} line, that line has not run yet.  Press @key{F8} once
more to step past it, then @kbd{Ctrl-G P} to see the output.

After each step, xwpe sends @code{call (void)fflush(0)} to gdb to
flush the program's stdout buffer.  This ensures output is available
immediately, even if the program uses buffered I/O.

@section Interactive programs

@cindex interactive input
@cindex stdin
@cindex Messages window input

A program that reads from standard input (@code{fgets}, @code{scanf},
@code{read}) works without any special setup: when it blocks for input,
type the answer directly in the Messages window and press @key{Enter}.
xwpe forwards your keystrokes to the program through the same
pseudoterminal it uses to capture output, so the program sees a real
terminal on stdin.

The example @file{docs/examples/interactive_test.c} prompts for a name
and blocks on @code{fgets()}.  Press @kbd{Ctrl-F9} (Run): the prompt
appears in Messages, you type a name and press @key{Enter}, and the
program greets you with UTF-8 output.  The same works under the debugger
--- step (@key{F8}) onto the @code{fgets()} line, run it, type the
answer in Messages, and continue.

@section Debugger backends

@cindex debugger selection

xwpe supports eight backends, selectable via @samp{Debug @result{}
debugger Options} (@kbd{Ctrl-G O}).  Several are auto-selected by file
type: jdb for @file{.java}, pdb for @file{.py}, a68g for interpreted
Algol 68, and the DAP client for @file{.go} (Delve), @file{.rs} (gdb) and
@file{.scala} (Bloop via @command{scala-cli}).

@quotation Note
Debugging @emph{runs} your program; for IDE features that @emph{understand}
it -- completion, hover, go-to-definition and compiler diagnostics over the
Language Server Protocol (Metals for Scala) -- see @ref{Language servers}.
@end quotation

@table @strong
@item gdb (GNU Debugger)
The default backend for C, C++, Fortran, Pascal, and native (ga68)
Algol 68.  Tested with gdb 17.2.  Supports all features: breakpoints,
stepping, watches, stack, program output capture via pty.

@item DAP client (Debug Adapter Protocol)
Backend for languages whose debuggers speak DAP -- the protocol used by
VS Code, Neovim and Emacs.  Auto-selected by file type:
@itemize
@item @file{.go}: drives Delve (@command{dlv dap}).  Requires @command{dlv}
and @command{go}, and a Go module (@file{go.mod}) in the source directory,
since @command{dlv dap} builds the package.
@item @file{.rs}: xwpe compiles the file (@command{rustc -g}) and debugs the
binary with @command{gdb --interpreter=dap} -- gdb is a first-class Rust
debugger (@command{rust-gdb} is gdb).  Requires @command{rustc} and
@command{gdb}.  The adapter is chosen in @samp{Debug @result{} debugger Options}
(@kbd{Ctrl-G O}): @samp{Auto} uses the first of gdb/lldb-dap found in @env{PATH}
(so a gdb-less macOS box selects @command{lldb-dap} automatically), or pick
@samp{gdb} / @samp{lldb} explicitly.  The choice is saved in @file{~/.xwpe/xwperc}.
@env{XWPE_DAP_ADAPTER} (e.g. @code{=lldb}) overrides it at run time for scripts
and CI.
@item @file{.scala}: debugs modern Scala (3.x/2.13) through Bloop, which hosts
the Scala Center @code{scala-debug-adapter}.  The JVM has no standalone DAP
server, so xwpe drives a short Build Server Protocol (BSP) handshake against
@command{scala-cli} (which bundles Bloop) to obtain a DAP endpoint, then
connects its DAP engine to it.  Frames arrive Scala-demangled (e.g.
@code{Factorial.main(args: Array[String]): Unit}).  Requires @command{scala-cli}
(install it with coursier: @code{cs install scala-cli}); the Debian @code{scala}
package (2.11) is too old.  It is the heaviest backend at run time (a JVM build
server plus a @file{.bsp}/@file{.scala-build} project beside the source), but the
xwpe binary gains nothing heavy -- the toolchain stays an external tool.
The Scala 3 compiler crashes at start-up on a too-new JDK (24+); when the
default @code{java} on @env{PATH} is too new and an LTS JDK (17/21) is installed,
xwpe repoints @env{JAVA_HOME} at it for Bloop before starting the build server
(and likewise for Metals), so debugging works out of the box without a
@code{//> using jvm} pin.  Set @env{JAVA_HOME} yourself to override.
@end itemize
Run/Continue (@kbd{Ctrl-G R}), Step Over (@kbd{F8}), Step Into (@kbd{F7}),
watches (@kbd{Ctrl-G W}, evaluated with the DAP @code{evaluate} request) and
Quit (@kbd{Ctrl-G Q}) all work as with gdb.

The engine carries three transports behind one API, because each adapter
dictates its own: @emph{reverse-TCP} (Delve is a server; the debuggee runs on
a pty whose output xwpe reads), @emph{stdio} (gdb and lldb speak DAP on
their own stdin/stdout, so program output arrives as DAP @code{output}
events) and @emph{TCP-client} (connect to a DAP endpoint a build server already
started, as for Scala/Bloop).  Adding a language is a one-row descriptor;
@command{lldb-dap} for C/C++ is a planned drop-in.

@item jdb (Java Debugger)
Backend for Java.  Auto-selected for @file{.java} files.  Uses
@code{poll()} for async JVM startup.  Breakpoints, stepping,
program output capture all work.  Tested with OpenJDK 25.

@item pdb (Python Debugger)
Backend for Python.  Auto-selected for @file{.py} files.
Breakpoints, F8 stepping, and program output capture work.
Automatically skips internal @code{<string>} frames.
Tested with Python 3.13.

@item sdb (Symbolic Debugger)
Legacy UNIX debugger.  Not available on modern Linux.

@item dbx
Berkeley UNIX debugger.  Available on some BSD systems.

@item xdb
HP-UX debugger.  Historical compatibility only.
@end table

@section Debugging C++ programs

gdb handles C++ natively.  xwpe selects @command{g++} as the compiler
for @file{.cpp} files and @command{gdb} as the debugger.  All debug
features work: breakpoints in member functions, stepping through
constructors, watching @code{this->member} expressions.

@section Debugging Fortran programs

gdb supports Fortran.  xwpe selects @command{gfortran} for
@file{.f90} files.  Set breakpoints on subroutine entries, step
through loops, watch local variables.  Array inspection is limited
by gdb's Fortran support.

@section Debugging Pascal programs

gdb has basic Free Pascal support.  Compile with @command{fpc -g}
(xwpe's default).  Breakpoints and stepping work.  Variable
inspection may be limited for Pascal-specific types (strings, sets).

@section Debugging Java programs

@cindex Java debugging
@cindex jdb

xwpe auto-selects jdb when opening a @file{.java} file.  No manual
configuration is needed.  If gdb was previously selected, xwpe
switches to jdb automatically with an informational message.

jdb differences from gdb:

@itemize @bullet
@item
@strong{Slower startup}: the JVM takes 2--3 seconds to initialise.
xwpe uses @code{poll()} with a 10-second timeout to wait without
consuming CPU.

@item
@strong{Breakpoints are deferred}: jdb sets breakpoints after the
class is loaded.  You see ``Deferring breakpoint'' in the Messages
window -- this is normal.

@item
@strong{Program output}: captured from jdb's pipe (not via pty like
gdb).  View with @kbd{Ctrl-G P}.

@item
@strong{No redirect}: jdb does not support @code{> /dev/pts/N}
redirection.  xwpe handles this transparently.
@end itemize

Requires @command{default-jdk} (Debian/Ubuntu) or equivalent JDK
package that provides @command{javac} and @command{jdb}.

@section Debugging Python programs

@cindex Python debugging
@cindex pdb

xwpe auto-selects pdb when opening a @file{.py} file.  No manual
configuration is needed.

pdb differences from gdb:

@itemize @bullet
@item
@strong{No compilation step}: @kbd{Ctrl-G R} invokes
@code{python3 -m pdb} directly on the source file.

@item
@strong{Frame skipping}: pdb starts in the @code{<string>} wrapper
frame.  xwpe automatically skips this frame so the cursor lands on
your first line of code.

@item
@strong{Program output}: captured from pdb's pipe and shown via
@kbd{Ctrl-G P} (same as gdb and jdb).

@item
@strong{Breakpoints}: set with @kbd{Ctrl-G B} before starting pdb.
xwpe sends @code{break file:line} commands to pdb.
@end itemize

Requires @command{python3} (Debian/Ubuntu).

@section Debugging Algol 68 programs

@cindex Algol 68 debugging
@cindex ga68
@cindex a68g
@cindex Algol 68 Genie monitor

Algol 68 has two toolchains, and xwpe debugs a @file{.a68}/@file{.alg}
file with whichever matches the file's dialect (the same content
detection used for compiling, @pxref{Compiling}).  No manual
configuration is needed; the first time you start the debugger xwpe
shows a short notice of the backend it chose (press @key{Return}).

@table @strong
@item ga68 (modern stropping)
A native compiler, so xwpe debugs the compiled binary with @strong{gdb}
-- the ordinary source-level debugger described above.  The one
wrinkle: ga68's user entry point is @code{__algol68_main}, not
@code{main}, so xwpe breaks there to stop at the start of your program
(a plain @code{break main} would land in the C runtime).  Breakpoints,
single-stepping, watches and the call stack all work as for C.

@item a68g (classic stropping)
An interpreter with a built-in, gdb-class source-level monitor
(@code{a68g --monitor}), which xwpe drives directly -- there is no
separate compile-and-link step.  Its commands differ from gdb's, as
described next.
@end table

a68g differences from gdb:

@itemize @bullet
@item
@strong{No compilation step}: @kbd{Ctrl-G R} runs
@code{a68g --monitor} on the source file.  (Make / @key{F9} still runs
@code{a68g --norun} as a standalone syntax check.)

@item
@strong{Break at start}: a68g automatically breaks at the first line,
like gdb stopping at @code{main}.  @kbd{Ctrl-G R} then continues to your
first breakpoint (or to the end of the program).

@item
@strong{Breakpoints}: set with @kbd{Ctrl-G B}.  xwpe sends
@code{breakpoint @var{line}} (and @code{breakpoint @var{line} clear} to
remove one).  Because Algol 68 is recursive, a breakpoint inside a
procedure is re-hit on every recursive call.

@item
@strong{Watches}: @kbd{Ctrl-G W} sends @code{evaluate @var{expr}} and
shows a68g's typed value, e.g.@: @code{(INT) +5}.  The expression is
@emph{not} quoted -- type @code{n}, not @code{"n"}.

@item
@strong{Call stack}: @kbd{Ctrl-G K} sends @code{calls}.

@item
@strong{Program output}: captured from a68g's single stream and shown
via @kbd{Ctrl-G P} (Messages) and the @kbd{Alt-F5} User Screen, the same
as gdb.

@item
@strong{Program end}: a68g prints @samp{Genie finished} and exits when
the program completes; xwpe detects this and ends the session cleanly.
@end itemize

Requires @command{algol68g} (Debian/Ubuntu).

@section Languages without an integrated debugger

Not every language xwpe compiles has a debugger backend.  These compile
and run (F9 / @kbd{Ctrl-F9}) but @kbd{Ctrl-G R} has no debugger to drive:

@itemize @bullet
@item @strong{Perl} -- run and syntax-check only.  Use @code{perl -d}
in a terminal for interactive debugging.
@item @strong{COBOL} -- GnuCOBOL builds a native executable that gdb can
debug from the command line, but xwpe does not auto-select gdb for COBOL.
@item @strong{LaTeX} -- a document processor, not a program to step
through.
@end itemize

@section Example session: C with factorial

@example
$ wpe debug_test.c
@end example

@enumerate
@item
Move cursor to line 9 (@code{int x = 5;}).  Press @kbd{Ctrl-G B}.
The line is highlighted as a breakpoint.

@item
Press @kbd{Ctrl-G R}.  xwpe compiles with @code{gcc -c -g},
links, starts gdb, and stops at the breakpoint.

@item
Press @kbd{Ctrl-G W}, type @code{x}, @key{Return}.  Watch Window
shows @code{x = 5}.

@item
Press @key{F8} three times.  The cursor advances through:
@code{int result = factorial(x)} @result{} @code{printf(...)}
@result{} next line.

@item
Press @kbd{Ctrl-G P}.  The User Screen shows:
@example
--- Program output ---
factorial(5) = 120
--- Press any key to return to editor ---
@end example

@item
Press any key to return.  Press @kbd{Ctrl-G K} to see the stack.

@item
Press @kbd{Ctrl-G Q} to quit the debugger.
@end enumerate

@section Known issues

@itemize @bullet
@item
Debugging leaks memory.  The exact source is unknown (present since
the Payne era).

@item
The sdb and dbx backends are untested on modern systems.

@item
Use @command{wpe} (not @command{we}) for debugging.  The editor-only
binary does not include debugger support.

@item
On keyboards where Ctrl+Function keys are not transmitted (e.g.@:
Keychron with multimedia F-keys), use the @kbd{Ctrl-G} prefix
shortcuts instead.

@item
Program output capture requires @code{libutil} (for @code{openpty}).
This is part of @code{libc6-dev} on Debian and is always available.
@end itemize

@noindent
Verified on 2026-06-01 with xwpe @value{VERSION}, gdb 17.2, jdb 25,
and pdb 3.13.
