Stacktraces and Runtime Metadata

Updated

September 8, 2026

Stacktraces and Runtime Metadata

Overview

A stack trace is not magic: the compiler and linker freeze metadata into the binary; the runtime unwinds live frames using that data. Reflect uses a sibling idea—type descriptors instead of PC→func maps.

Companion read: Internals for Interns — Stacktraces.

Diagram: build time vs run time

regions: build time | run time
flow:
  [Unwind]
       |
       v
  [Meta]

  [Unwind]
       |
       v
  [Frames]

Who prints stacks

Trigger Behavior
panic dump (controlled by GOTRACEBACK)
runtime.Stack buffer of current or all Gs
pprof goroutine stacks of live Gs
SIGQUIT (often) all-G dump
GOTRACEBACK=all ./app

Inlining and wrappers

Optimized binaries inline functions; traces may show fewer frames or wrapper names. Disable inlining for forensics:

go build -gcflags='-l' .

Relation to profiling

CPU profiles sample stacks with the same unwinding family of mechanisms (222).

Experiment

package main

import (
    "fmt"
    "runtime"
)

func deep(n int) {
    if n == 0 {
        buf := make([]byte, 4096)
        k := runtime.Stack(buf, false)
        fmt.Printf("%s", buf[:k])
        return
    }
    deep(n - 1)
}

func main() { deep(5) }

What to notice: Frames list deep repeatedly with decreasing depth.

Try next: Compare stacks with and without -gcflags=-l.