Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/golang/go/llms.txt

Use this file to discover all available pages before exploring further.

The debug package provides debugging facilities for Go programs. It contains subpackages for examining binaries, reading DWARF debugging information, and runtime debugging.

Subpackages

debug/dwarf

Access to DWARF debugging information from executable files.
import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
)

func readDWARF(filename string) error {
    // Open ELF file
    f, err := elf.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    // Get DWARF data
    dwarfData, err := f.DWARF()
    if err != nil {
        return err
    }
    
    // Read entries
    reader := dwarfData.Reader()
    for {
        entry, err := reader.Next()
        if err != nil {
            return err
        }
        if entry == nil {
            break
        }
        
        if entry.Tag == dwarf.TagSubprogram {
            name := entry.Val(dwarf.AttrName)
            fmt.Printf("Function: %v\n", name)
        }
    }
    
    return nil
}

debug/elf

Access to ELF (Executable and Linkable Format) object files.
import "debug/elf"

func examineELF(filename string) error {
    f, err := elf.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    fmt.Printf("Class: %v\n", f.Class)
    fmt.Printf("Data: %v\n", f.Data)
    fmt.Printf("Machine: %v\n", f.Machine)
    fmt.Printf("Type: %v\n", f.Type)
    
    // List sections
    for _, section := range f.Sections {
        fmt.Printf("Section: %s (type %v)\n", section.Name, section.Type)
    }
    
    // List symbols
    symbols, err := f.Symbols()
    if err != nil {
        return err
    }
    
    for _, sym := range symbols {
        fmt.Printf("Symbol: %s\n", sym.Name)
    }
    
    return nil
}

debug/macho

Access to Mach-O object files (macOS and iOS).
import "debug/macho"

func examineMachO(filename string) error {
    f, err := macho.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    fmt.Printf("CPU: %v\n", f.Cpu)
    fmt.Printf("Type: %v\n", f.Type)
    
    // List sections
    for _, section := range f.Sections {
        fmt.Printf("Section: %s\n", section.Name)
    }
    
    return nil
}

debug/pe

Access to PE (Portable Executable) files (Windows).
import "debug/pe"

func examinePE(filename string) error {
    f, err := pe.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    fmt.Printf("Machine: %v\n", f.Machine)
    
    // List sections
    for _, section := range f.Sections {
        fmt.Printf("Section: %s\n", section.Name)
    }
    
    // List imported DLLs
    imports, err := f.ImportedLibraries()
    if err != nil {
        return err
    }
    
    for _, dll := range imports {
        fmt.Printf("Import: %s\n", dll)
    }
    
    return nil
}

debug/plan9obj

Access to Plan 9 a.out object files.
import "debug/plan9obj"

func examinePlan9(filename string) error {
    f, err := plan9obj.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    fmt.Printf("Magic: %v\n", f.Magic)
    
    // List sections
    for _, section := range f.Sections {
        fmt.Printf("Section: %s\n", section.Name)
    }
    
    return nil
}

debug/buildinfo

Read build information embedded in Go binaries.
import (
    "debug/buildinfo"
    "fmt"
)

func readBuildInfo(filename string) error {
    info, err := buildinfo.ReadFile(filename)
    if err != nil {
        return err
    }
    
    fmt.Printf("Go version: %s\n", info.GoVersion)
    fmt.Printf("Path: %s\n", info.Path)
    fmt.Printf("Main module: %s %s\n", info.Main.Path, info.Main.Version)
    
    // List dependencies
    for _, dep := range info.Deps {
        fmt.Printf("Dependency: %s %s\n", dep.Path, dep.Version)
    }
    
    // Build settings
    for _, setting := range info.Settings {
        fmt.Printf("%s=%s\n", setting.Key, setting.Value)
    }
    
    return nil
}

Runtime Debugging

runtime/debug Package

import (
    "fmt"
    "runtime/debug"
)

// Print stack trace
func printStack() {
    debug.PrintStack()
}

// Get stack trace as string
func getStack() string {
    return string(debug.Stack())
}

// Control garbage collector
func controlGC() {
    // Disable GC
    debug.SetGCPercent(-1)
    
    // Re-enable with 100% target
    debug.SetGCPercent(100)
    
    // Force GC
    debug.FreeOSMemory()
}

// Read GC stats
func readGCStats() {
    var stats debug.GCStats
    debug.ReadGCStats(&stats)
    
    fmt.Printf("Last GC: %v\n", stats.LastGC)
    fmt.Printf("Num GC: %d\n", stats.NumGC)
    fmt.Printf("Pause total: %v\n", stats.PauseTotal)
}

// Read memory stats
func readMemStats() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    
    fmt.Printf("Alloc: %d MB\n", m.Alloc/1024/1024)
    fmt.Printf("TotalAlloc: %d MB\n", m.TotalAlloc/1024/1024)
    fmt.Printf("Sys: %d MB\n", m.Sys/1024/1024)
    fmt.Printf("NumGC: %d\n", m.NumGC)
}

Build Info at Runtime

import "runtime/debug"

func printRuntimeBuildInfo() {
    info, ok := debug.ReadBuildInfo()
    if !ok {
        fmt.Println("Build info not available")
        return
    }
    
    fmt.Printf("Go version: %s\n", info.GoVersion)
    fmt.Printf("Main module: %s\n", info.Main.Path)
    
    for _, dep := range info.Deps {
        fmt.Printf("%s@%s\n", dep.Path, dep.Version)
    }
}

Practical Examples

Crash Recovery with Stack Trace

import "runtime/debug"

func recoverFromPanic() {
    if r := recover(); r != nil {
        fmt.Printf("Panic: %v\n", r)
        fmt.Printf("Stack trace:\n%s\n", debug.Stack())
    }
}

func riskyOperation() {
    defer recoverFromPanic()
    
    // Code that might panic
    panic("something went wrong")
}

Memory Profiling

import (
    "os"
    "runtime/pprof"
)

func profileMemory(filename string) error {
    f, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    
    runtime.GC() // Run GC before profiling
    if err := pprof.WriteHeapProfile(f); err != nil {
        return err
    }
    
    return nil
}

Extract Version Information

import "debug/buildinfo"

func getVersion(binaryPath string) (string, error) {
    info, err := buildinfo.ReadFile(binaryPath)
    if err != nil {
        return "", err
    }
    
    // Look for version in build settings
    for _, setting := range info.Settings {
        if setting.Key == "vcs.revision" {
            return setting.Value[:7], nil // Short commit hash
        }
    }
    
    return "unknown", nil
}

Binary Analysis

func analyzeBinary(filename string) error {
    // Try to open as different formats
    if f, err := elf.Open(filename); err == nil {
        defer f.Close()
        fmt.Println("Format: ELF")
        return examineELF(filename)
    }
    
    if f, err := pe.Open(filename); err == nil {
        defer f.Close()
        fmt.Println("Format: PE")
        return examinePE(filename)
    }
    
    if f, err := macho.Open(filename); err == nil {
        defer f.Close()
        fmt.Println("Format: Mach-O")
        return examineMachO(filename)
    }
    
    return fmt.Errorf("unknown binary format")
}

Common Use Cases

  • Binary inspection: Examine compiled binaries and their structure
  • Debugging information: Extract debug symbols and line information
  • Dependency analysis: List dependencies of a compiled binary
  • Version tracking: Embed and extract version information
  • Memory debugging: Track memory usage and garbage collection
  • Crash analysis: Capture and analyze stack traces
  • Build validation: Verify build settings and dependencies

Best Practices

  1. Always close file handles - Use defer f.Close() when opening binaries
  2. Handle format variations - Different platforms use different executable formats
  3. Check error returns - Binary parsing can fail in various ways
  4. Use runtime/debug for production - Safer than debug/elf etc. at runtime
  5. Embed build info - Use -ldflags to embed version information during build