Docs/Tools

Debugging

Stack traces, debug builds, and a debugger.

On this page

Every panic names the file and line it came from. A debug build adds a stack trace and the information a debugger such as gdb or lldb needs.

Panic messages#

Valk
fn pick(items: Array[int], index: uint) int {
    return items.get(index) !!
}

fn main() {
    let items = Array[int]{ 1, 2 }
    println(pick(items, 5))
}
Text
Unhandled error 'LookupError.missing' at src/main.valk:2

panic("message"), an error left unhandled by !!, an index out of bounds and a division by zero all print a message with the location, relative to the package root, and exit with status 1. A location inside a library ends with in package <name>.

Debug builds#

Terminal
valk build src -d -o app

With -d (or --debug), a panic also prints every call that led to it:

Text
Unhandled error 'LookupError.missing' at src/main.valk:2
Stack trace:
  at main.pick (src/main.valk:2)
  at main.main (src/main.valk:7)

A crash, such as a segmentation fault or a stack overflow, prints the trace too. Debug builds are slower and use more memory, so don't ship them.

Use a debugger#

A debug build carries DWARF debug info (a .pdb file on Windows), so gdb, lldb and Visual Studio show functions, source lines, arguments and local variables.

Terminal
valk build src -d -o app
gdb ./app
(gdb) break main.valk:2
(gdb) run
Breakpoint 1, main.pick (items=0x5555555a7348, index=5) at src/main.valk:2
(gdb) print index
$1 = 5
(gdb) bt

Functions appear as namespace.name, such as main.pick, and methods as Type.method, so break main.pick works as well as a file and line.