Repository navigation
Guide debugging
Mirrored from docs/guides/debugging.md in the repo — that is the canonical source; edits to this wiki page are overwritten when the wiki is re-synced.
Tycho transpiles to C and hands the
.cto your systemcc, so DWARF debug info flows through for free — the only missing piece is a map from the generated C back to your.tysource. The-gflag adds that map.
-g does two things:
- Emits
#line N "src.ty"directives into the generated C, one before each statement, so the C compiler's line table attributes the code to your Tycho source instead of the.cfile. - Builds with
-O0 -g(unoptimized + DWARF) instead of the default-O3, so stepping is faithful and locals aren't optimized away.
tychoc program.ty -g -o program
Then debug the binary as if it were hand-written C, but stepping lands on
.ty lines:
Linux (gdb) — DWARF is embedded in the executable directly:
gdb ./program
(gdb) break program.ty:7 # break on a Tycho source line
(gdb) run
(gdb) step # steps through program.ty, not the generated C
macOS (lldb) — the toolchain leaves DWARF in the intermediate objects, and
a one-step compile+link discards them, so generate a .dSYM first:
tychoc program.ty -g --emit-c -o program # keep the .c
cc -O0 -g -fwrapv -pthread program.c -o program -lm
dsymutil program # writes program.dSYM
lldb ./program
(lldb) breakpoint set -f program.ty -l 7
(-g alone still produces a runnable binary on macOS; the .dSYM step is only
needed for source-level stepping.)
The emitted C is faithful but not idiomatic, so a few things read differently in a debugger:
-
Every function takes a hidden first argument
Arena *_parent— the arena that owns its return value. You'll see it on every frame; ignore it unless you're debugging allocation. -
inoutparameters are passed by pointer. Ainout int xis along *h_xin C; print*h_x, noth_x. A heapinoutalso carries anArena *_ina_xjust before it. -
Locals are prefixed
h_(h_xfor Tychox) to avoid clashing with C keywords and runtime symbols. -
Statement temporaries live in per-statement
_tarenas freed at the end of each statement; block/loop bodies get their own_b/_scopearenas. These are the arena-management lines you'll step over between your statements.
-
Single-file only.
-gemits line info for a single-file compile. A package build merges several.tyfiles into one unit and drops per-file identity, so-gis skipped there (with a note on stderr) rather than emitting wrong file/line pairs. Debug a package by reducing the failing path to a single file, or debug at the generated-C level without-g. -
Synthesized glue is unmapped. The program entry point, arena bootstrap,
and other compiler-generated scaffolding have no
.tyline; a#linedirective only anchors real statements, so stepping through the glue shows the nearest preceding source line. This is cosmetic. -
Relative paths resolve against the compile directory. If you compiled with
a relative path (
tychoc src/program.ty -g), debug from the same working directory so the debugger finds the source.
The reader docs here are mirrored from /docs in the repo — the canonical source. · tycho-lang.com · MIT licensed
- Tutorial
- The Tycho thesis: value semantics makes implicit arenas work
- Architecture & project status
- From
mallocto implicit arenas
- Tycho language reference
- Basics
- Types
- Functions and closures
- Structs and tuples
- Enums, options, and
match - Arrays and slices
- Subscripts (user-defined projections)
- Maps
- Generics
- Concurrency
- FFI (calling C)
- Packages
- Builtins
- Memory model in the self-hosted compiler
- Tycho aggregates: arrays & structs under value semantics
- Maps with arbitrary value types
m[k]as a place: in-place map-value mutation- Generics (monomorphized)
- Concurrency in Tycho
- FFI — calling C from Tycho
- Packages & modules
- corelib — Tycho's standard library
- Performance: the self-hosted transpiler vs the C one
- Debugging generated C