Delve — Structure#
Layout pattern#
Standard Go Layout (cmd/internal/pkg) with service layer extension
Delve uses the standard cmd/ + pkg/ layout, augmented with a top-level service/ directory that houses the protocol and server layer. This is a disciplined single-binary project: there is one binary (dlv), and the entire codebase is organized around the vertical slices of that binary’s responsibility. The pkg/ vs service/ split cleanly separates reusable process-control libraries from the networking/protocol layer.
Directory map#
delve/
├── cmd/
│ └── dlv/ # Single binary entry point
│ ├── main.go # Thin launcher: telemetry init, CGO flags, cobra exec
│ ├── dlv_test.go # Integration tests for the dlv command
│ ├── tools.go # tooling imports (go:generate etc.)
│ └── cmds/ # Cobra command tree
│ ├── commands.go # All subcommands: debug, test, exec, attach, dap, ...
│ └── helphelpers/ # Auto-generated CLI help text
│
├── pkg/ # Reusable, importable packages
│ ├── proc/ # CORE: process abstraction + debugger engine (56 files)
│ │ ├── native/ # OS debugging backend (ptrace / Windows APIs) (58 files)
│ │ ├── gdbserial/ # GDB remote protocol client backend (6 files)
│ │ ├── core/ # Core dump reader backend (5 files)
│ │ ├── internal/
│ │ │ └── ebpf/ # eBPF non-stop tracing backend (6 Go files + C code)
│ │ │ ├── bpf/ # C source: trace.bpf.c (compiled via Docker)
│ │ │ └── build/ # Docker build scripts for eBPF objects
│ │ ├── amd64util/ # x86-64 instruction utilities
│ │ ├── linutil/ # Linux-specific utilities (9 files)
│ │ ├── fbsdutil/ # FreeBSD-specific utilities
│ │ ├── macutil/ # macOS-specific utilities
│ │ ├── winutil/ # Windows-specific utilities
│ │ ├── evalop/ # Expression evaluation opcodes (3 files)
│ │ ├── debuginfod/ # debuginfod server client for remote DWARF
│ │ └── test/ # Test helpers (protest pkg) for proc tests
│ │
│ ├── dwarf/ # Custom DWARF parser (Go-aware extensions)
│ │ ├── godwarf/ # Go-specific DWARF type reading (7 files)
│ │ ├── frame/ # .debug_frame / .eh_frame parser (5 files)
│ │ ├── line/ # .debug_line (line number table) parser (5 files)
│ │ ├── op/ # DWARF expression evaluator (4 files)
│ │ ├── leb128/ # LEB128 integer encoding (5 files)
│ │ ├── loclist/ # .debug_loc location lists
│ │ ├── reader/ # Incremental DWARF entry reader
│ │ ├── regnum/ # DWARF register number mappings per arch (6 files)
│ │ └── dwarfbuilder/ # DWARF builder (for test fixtures)
│ │
│ ├── terminal/ # Interactive CLI / REPL (15 files)
│ │ └── starbind/ # Starlark script binding for terminal (5 files)
│ ├── config/ # .delverc config file loading
│ ├── logflags/ # Structured logging flags
│ ├── gobuild/ # Go build integration (compile + gcflags)
│ ├── locspec/ # Location spec parsing ("file:line", "func")
│ ├── astutil/ # Go AST utilities for expression parsing
│ ├── goversion/ # Go runtime version detection
│ ├── debugdetect/ # Detect debugger presence (7 files, platform-specific)
│ ├── elfwriter/ # ELF file writer (for DWARF injection)
│ ├── version/ # Delve version constants
│ └── internal/ # pkg-internal shared utilities
│
├── service/ # Protocol servers and high-level debugger API
│ ├── api/ # Shared JSON-serializable types (8 files)
│ ├── debugger/ # Debugger struct: high-level ops (launch, attach, ...) (4 files)
│ ├── rpc2/ # JSON-RPC 2.0 server and client
│ ├── dap/ # Debug Adapter Protocol server (8 files)
│ │ └── daptest/ # DAP test client helpers
│ ├── rpccommon/ # Shared RPC utilities
│ ├── internal/
│ │ └── sameuser/ # Security: verify client is same OS user (4 files)
│ ├── test/ # Integration tests for the service layer
│ ├── server.go # Server start-up and listener management
│ ├── client.go # RPC2 client implementation
│ ├── config.go # Service-level config types
│ ├── listenerpipe.go # In-process listener for headless mode
│ └── rpccallback.go # RPC callback interface
│
├── _fixtures/ # Test fixture Go source files (compiled during tests)
│ └── <many subdirs> # One dir per special test scenario (cgo, plugins, asm, etc.)
├── _scripts/ # Go-based build helper scripts (make.go)
├── Documentation/ # User and internal documentation
│ ├── api/ # JSON-RPC / DAP API docs and how-to guides
│ ├── cli/ # Auto-generated CLI reference
│ ├── internal/ # Porting notes, architecture docs
│ ├── installation/ # Platform install guides
│ ├── usage/ # User-facing usage guides
│ └── AI/ # AI/IDE integration guidance
├── assets/ # Logo and static assets
└── vendor/ # Vendored dependenciesEntry points#
| Binary | Path | Purpose |
|---|---|---|
dlv | cmd/dlv/main.go | Single entry point for the Delve debugger. Initializes Go telemetry, sets CGO_CFLAGS=-O0 -g (disable optimizations on debugged programs), then delegates to Cobra command tree via cmds.New(false).Execute(). |
There is exactly one binary. All debugger modes (interactive, headless, DAP server, attach, exec, trace, eBPF) are subcommands of dlv.
Package organization#
Internal packages#
| Package | Purpose |
|---|---|
pkg/proc/internal/ebpf | eBPF tracing backend; internal prevents external import of this unstable backend |
pkg/internal | Shared utility types used across pkg/ only |
service/internal/sameuser | Security helper ensuring RPC clients share the OS user; not part of the public API |
Public packages (pkg/)#
| Package | Purpose |
|---|---|
pkg/proc | Core process abstraction: Process, ProcessInternal, Target, TargetGroup, Thread, Goroutine, variable evaluation, breakpoint management |
pkg/proc/native | OS-native debugging backend: ptrace (Linux), mach exception ports (macOS), Windows debug APIs |
pkg/proc/gdbserial | GDB remote serial protocol client; enables debugging under LLDB, rr, and hardware targets |
pkg/proc/core | Core dump (ELF/Mach-O) reader; read-only process backend for post-mortem analysis |
pkg/proc/internal/ebpf | eBPF-based non-stop function tracing; unique backend that never halts the target |
pkg/dwarf/* | Custom DWARF parser family: Go-specific type reading, frame/line/loc parsers, expression evaluator, register number tables |
pkg/terminal | Interactive REPL: command dispatch, history, Starlark scripting, output formatting |
pkg/locspec | Location specification parser: "file:line", "package.Function", "*addr" |
pkg/gobuild | Invokes the Go toolchain to compile target programs with debug flags |
pkg/config | Reads and writes .delverc user configuration files |
pkg/logflags | Structured logger setup (used for internal Delve debug logging) |
pkg/goversion | Detects and parses the Go runtime version of the target process |
pkg/debugdetect | Detects whether the process is running under a debugger (anti-debug detection for tests) |
pkg/elfwriter | Writes ELF files with injected DWARF sections (used for test fixture generation) |
pkg/astutil | Go AST helpers for parsing expressions typed by the user |
pkg/version | Version string constants for the dlv binary |
Layering#
The package dependency graph flows strictly top-down:
cmd/dlv (CLI)
└── service/debugger → service/api
├── service/rpc2 (JSON-RPC 2.0 server)
└── service/dap (DAP server)
└── pkg/proc (process abstraction)
├── pkg/proc/native
├── pkg/proc/gdbserial
├── pkg/proc/core
├── pkg/proc/internal/ebpf
└── pkg/dwarf/*This is clean layered architecture: upper layers never import lower-layer internals. pkg/proc and pkg/dwarf are entirely self-contained with no dependency on service/. There are no circular imports.
Build system#
- Build tool:
make(delegating togo run _scripts/make.go) + standardgo build - Key targets:
make build— produces thedlvbinary viago run _scripts/make.go buildmake install— installsdlvto$GOPATH/binmake test— runsgo vetthengo run _scripts/make.go testmake vendor— updates vendored dependenciesmake build-ebpf-image— builds Docker image with clang-12 for eBPF compilationmake build-ebpf-object— compilespkg/proc/internal/ebpf/bpf/trace.bpf.cinside Docker to produce architecture-specific.ofiles
- Docker: Yes, but only for the eBPF backend. The eBPF C code must be compiled with clang-12 (newer versions produce BPF bytecode that fails the kernel verifier). The Docker image pins this exact version. The rest of Delve builds with standard
go build. - Vendoring: Yes — a
vendor/directory is present and maintained.
Notable structural decisions#
Single binary, multiple modes: All functionality (interactive, headless RPC, DAP server, eBPF tracer, core dump reader) lives in one
dlvbinary. There are no separatedlv-server/dlv-clientbinaries. The subcommand tree (cmds/commands.go) determines the mode at runtime.Four pluggable backends under one interface:
pkg/proc/native,pkg/proc/gdbserial,pkg/proc/core, andpkg/proc/internal/ebpfall satisfy the sameProcessInternalinterface. This is a textbook application of the strategy pattern at the package level — thepkg/proclayer is completely backend-agnostic.Custom DWARF parser as a standalone sub-library:
pkg/dwarf/is large enough to be its own library (~30+ files across 9 sub-packages). Rather than vendoring a third-party DWARF library, Delve built its own because stock Go DWARF tooling (evendebug/dwarf) doesn’t handle Go-specific extensions (goroutine metadata, interface types, generics). This is a deliberate bet on correctness over convenience.Platform-specific code isolated at filename level only: There are no
if runtime.GOOSswitches in the generic files. Instead, every platform-specific implementation is in a file named*_linux.go,*_darwin.go,*_windows.go,*_freebsd.go,regs_amd64.go, etc. This makes portability explicit, readable, and compilable by the toolchain without runtime overhead._fixtures/as compilable test programs (not binaries): Test fixtures are Go source files that are compiled during test execution usingpkg/gobuild. This means fixtures are always compiled with the Go version under test, ensuring correct DWARF output for each Go release. Pre-compiled binaries would immediately become stale.eBPF backend requires Docker for reproducibility: The eBPF C code compilation is containerized to pin clang-12, since the kernel BPF verifier rejects bytecode from newer clang versions. This is an unusual but pragmatic decision that trades build simplicity for correctness.