Debugging

cuarzo dap is a debug adapter: it speaks the Debug Adapter Protocol over standard input and output, so an editor can run a Cuarzo program under a debugger and show it as Cuarzo. It needs one of:

  • GDB 14 or later, whose adapter is gdb -i=dap (Linux, Windows with MinGW's GDB, the BSDs);
  • LLDB's lldb-dap (macOS, where Xcode has it, and anywhere LLVM is installed).

The adapter builds the program with --debug, starts the debugger's own adapter, and passes the editor's messages through it, making Cuarzo of what is about the program's code.

What it does

  • Breakpoints in .cz files, with conditions written in Cuarzo (n > 0 and not done), hit counts (5, >= 5, % 3), and log messages (total is {total}), which print without stopping.
  • Function breakpoints by Cuarzo name: area, or Point.length for a method.
  • Stopping on runtime errors: the Runtime errors exception filter, on by default, stops the program where an error happens, before it ends, with the message.
  • Stepping over, into, and out of the program's functions; a step never stops in the runtime's C.
  • The call stack of the program's frames, named as Cuarzo names them; the program's top-level code is (program).
  • Variables of each frame by their Cuarzo names, and the constants and shared variables of the program's files, shown as Cuarzo values: text, true and false, characters, arrays with their items, maps with their entries, structs with their fields, enums by member, Option, Result, and other enums with what their member carries, and tuples. Arrays and maps show their first 100 items.
  • Watches and hovers: names, fields (p.x), tuple items (pair.0), indexes (names[i + 1]), len(...), numbers, and the operators of numbers and comparisons, with and, or, and not. In the debug console, text after a backquote goes to the debugger as a command: `info registers.
  • Launching and attaching to a running program built with --debug.

The editor's configuration

In Visual Studio Code, a debugger contribution names the command, and a launch configuration the program:

{
    "type": "cuarzo",
    "request": "launch",
    "name": "Run notes",
    "program": "${workspaceFolder}/src/notes.cz",
    "args": ["--verbose"],
    "cwd": "${workspaceFolder}"
}
Launch
program the program's .cz file (required)
args, cwd, env the program's arguments, folder, and environment
stopOnEntry stop at the program's first line
debugger gdb or lldb; LLDB on macOS and GDB elsewhere unless given
debuggerPath where the debugger's adapter is, when it is not on the PATH
Attach
processId the program's process
program its .cz file, which was built with --debug
debugger, debuggerPath as for launching

A program in a project is built with the constants of the debug profile.

Building for a debugger

cuarzo build --debug builds a program as the adapter does, for any debugger: with symbols, unoptimized, and with #line directives in its C that put each statement at its line of its .cz file, so GDB, LLDB, and others show the Cuarzo source and stop at its lines. The code of the runtime keeps the lines of the C file. Beside the program is its debug table, program.debug.json: its functions, with the variables of each, their types, and the C that reads them, and how each type is kept in C. --debug does not go with --release.