Skip to content

Latest commit

 

History

History
884 lines (711 loc) · 34.3 KB

File metadata and controls

884 lines (711 loc) · 34.3 KB

Configuration Reference

GhostScope can be configured through command-line arguments, configuration files, and environment variables.

Configuration Priority

Configuration follows this priority order (highest to lowest):

  1. Command-line arguments
  2. Environment variables (RUST_LOG)
  3. Configuration file (~/.ghostscope/config.toml or ./ghostscope.toml)
  4. Default values

Note: GhostScope typically runs under sudo to access tracing functionality. When executed as root, $HOME points to /root by default, so the user-level config at ~/.ghostscope/config.toml will not be picked up automatically. Use ghostscope --config /home/<user>/.ghostscope/config.toml to load your personal configuration when running with sudo.

Command-Line Arguments

Target Selection

# Attach to a running process by PID
ghostscope -p <PID>
ghostscope --pid <PID>

# PID namespace aware behavior (Docker/WSL/container)
# - Enter the PID as seen in your current shell/namespace.
# - For a fuller explanation of container scenarios, see docs/container.md
# - Startup decision order:
#   1) Detect runtime environment (container/host/unknown)
#   2) Parse NSpid mapping from /proc/<pid>/status
#   3) Probe helper support and prefer bpf_get_ns_current_pid_tgid when available
#   4) Fallback to host PID mapping when helper is unavailable
# - If the PID is not visible in the current namespace, GhostScope fails fast
#   and asks you to provide a PID that exists in the current namespace.

# Specify target executable or library (with path resolution)
ghostscope -t <PATH>
ghostscope --target <PATH>

# Target path resolution order for relative paths:
# 1. Current working directory
# 2. Same directory as ghostscope executable
# 3. Converts to absolute path if not found

# Both can be used together to trace the -t module inside one running PID.
# In this form, -t wins for function/source/address target resolution and
# -p scopes runtime events and module refresh to that process.
ghostscope -t /usr/bin/myapp -p 1234

# Launch a new process
ghostscope /path/to/program
ghostscope /path/to/program arg1 arg2

# Use --args when target arguments may look like GhostScope options
ghostscope --script-file trace.gs --args /path/to/program --target-flag value
# Everything after --args is passed to the target program

Script Execution

# Run inline script
ghostscope -s 'trace main { print "Started"; }'
ghostscope --script 'trace main { print "Started"; }'

# Run script from file
ghostscope --script-file trace.gs

# Print the embedded script language reference and exit
ghostscope --script-help

# Explain value failures, display fallbacks, and capture limits offline
ghostscope --value-diagnostics-help

# Choose script-mode event stdout rendering
ghostscope --script-output pretty   # default: formatted stdout
ghostscope --script-output plain    # payload-only stdout

# Control interactive status prompts on stderr
ghostscope --status                 # default
ghostscope --no-status              # hide DWARF/script/attach status prompts

# Control timestamp style for pretty output
ghostscope --script-timestamp local # default
ghostscope --script-timestamp boot
ghostscope --script-timestamp none

# Output streams in script mode:
# - trace events stay on stdout
# - DWARF loading, script compile, and attach status prompts go to stderr
# - --script-output only controls event stdout formatting
# - --status / --no-status controls those interactive stderr status prompts
# - fatal errors still go to stderr regardless of mode
# - ANSI colors for pretty stdout and interactive stderr status can be controlled with [script].color in config.toml

# Start in TUI mode (default if no script provided)
ghostscope --tui

Debug Information

# Specify an explicit debug file for the target module (overrides auto-detection)
ghostscope -t /path/to/binary --debug-file /path/to/binary.debug
ghostscope -p 1234 --debug-file /path/to/binary.debug
#
# Binding rules:
# - With -t, the debug file is used for that target binary or shared library
# - With -p only, the debug file is used for /proc/<pid>/exe (the main executable)
# - With -p and -t, the debug file is used for the -t target module
# - CRC mismatches and available Build-ID mismatches are rejected unless
#   --allow-loose-debug-match is set

# Auto-detection searches in order:
# 1. Binary itself (.debug_info sections)
# 2. Local separate debug files by Build-ID or .gnu_debuglink
# 3. debuginfod by Build-ID, when [dwarf.debuginfod] is enabled
#
# .gnu_debugdata is not loaded currently. The default search_paths include
# /usr/lib/debug and /usr/local/lib/debug.

# Local separate-debug search paths (configurable in config.toml):
# 1. Absolute path (if .gnu_debuglink contains absolute path - rare)
# 2. <search_path>/.build-id/xx/yyyy.debug, when a Build-ID is available
# 3. User-configured search_paths + basename (GhostScope compatibility path)
# 4. Same directory as the binary + basename
# 5. .debug subdirectory next to the binary + basename
# 6. <search_path>/<absolute_binary_directory>/<basename>
#
# Note: If you override search_paths in config.toml, keep any system-wide debug
# directories that you still rely on.

Logging Configuration

# Enable file logging (default: ./ghostscope.log)
ghostscope --log

# Disable all logging
ghostscope --no-log

# Enable console logging on stderr in addition to file output
ghostscope --log-console

# Disable console stderr logging
ghostscope --no-log-console

# Set log level
ghostscope --log-level debug  # Options: error, warn, info, debug, trace

# Custom log file path
ghostscope --log-file /var/log/ghostscope.log

Debug Output Files

# Save LLVM IR files (default: enabled in debug builds)
ghostscope --save-llvm-ir
ghostscope --no-save-llvm-ir

# Save eBPF bytecode files (default: enabled in debug builds)
ghostscope --save-ebpf
ghostscope --no-save-ebpf

# Save AST files (default: enabled in debug builds)
ghostscope --save-ast
ghostscope --no-save-ast

UI Layout

# Set TUI layout mode
ghostscope --layout horizontal  # Panels side by side (default)
ghostscope --layout vertical    # Panels top to bottom

# Show/hide source panel (useful when source code is unavailable)
ghostscope --no-source-panel    # Hide source panel; keep eBPF output + command panels
ghostscope --source-panel       # Show source panel

Advanced eBPF Options

# Force PerfEventArray mode (for testing only)
# WARNING: Testing purposes only. Forces PerfEventArray even on kernels >= 5.8
ghostscope --force-perf-event-array

# Opt in to sleepable uprobes for this invocation. This overrides
# sleepable_uprobe=false in the config file.
ghostscope --sleepable-uprobe

# Standalone -t starts target-mode sysmon by default. When -t is combined with
# -p, GhostScope uses the -p watched-PID module-refresh path instead.
# WARNING: Attaches system-wide lifecycle tracepoints (exec/fork/exit) and may
# also attach map-change tracepoints (mmap/mprotect/munmap/mremap) for runtime
# module refresh. This can add overhead on hosts with high process churn or
# frequent memory-map changes. Set enable_sysmon_for_target=false in config to
# disable it; this flag can re-enable it for one run.
ghostscope --enable-sysmon-for-target

Sleepable Uprobes

Sleepable uprobes are an opt-in [ebpf] configuration because they require a Linux 5.18+ kernel and can change probe latency by allowing a user-memory page fault to be serviced during a probe hit. The default remains the regular, non-sleepable uprobe path.

[ebpf]
sleepable_uprobe = true

For a one-off run, use --sleepable-uprobe; it enables this setting even when the config file has sleepable_uprobe = false. To keep regular uprobes, omit the flag and leave the configuration at its default false.

Sleepable uprobes require RingBuf event output. Do not combine sleepable_uprobe = true (or --sleepable-uprobe) with force_perf_event_array = true (or --force-perf-event-array): the kernel does not permit sleepable BPF programs to use BPF_MAP_TYPE_PERF_EVENT_ARRAY, and GhostScope reports this configuration conflict before attaching.

When enabled, GhostScope emits uprobe.s programs. Fixed-size user-memory reads use bpf_copy_from_user_task() so pages can be faulted in; NUL-terminated string reads retain bpf_probe_read_user_str() because its early-NUL and reported-length semantics differ. Startup fails clearly if the kernel does not support the helper required by sleepable uprobe mode rather than silently falling back.

Long DWARF bt traces normally use a tail-call step program. GhostScope probes that sleepable tail-call path at startup; on kernels that do not allow a sleepable program to use BPF_MAP_TYPE_PROG_ARRAY, it compiles the trace with the inline limit of five frames instead and prints a warning. This preserves a working sleepable trace rather than failing eBPF verification.

Enable this only when fault-capable reads are worth the added latency and kernel requirement. Set sleepable_uprobe = false (the default) to use regular uprobes again.

BPFFS Maintenance

GhostScope uses bpffs because some runtime state must be shared across the userspace process layer, the loader, and the eBPF programs themselves. In practice, maps such as proc_module_offsets and allowed_pids are pinned into bpffs so later stages can reopen and reuse the same kernel maps by path instead of recreating them. GhostScope places these pins under a per-instance pid-starttime directory to avoid collisions between concurrent runs.

GhostScope stores per-instance pinned maps under /sys/fs/bpf/ghostscope/<pid-starttime>/.

  • Normal tracing runs do not sweep /sys/fs/bpf/ghostscope globally on startup.
  • On normal exit, GhostScope removes the current instance directory automatically.
  • Residual directories usually indicate abnormal termination, such as a crash or SIGKILL.
  • Global cleanup is an explicit maintenance action via the bpffs prune subcommand.
# Remove stale pid-starttime directories only
ghostscope bpffs prune

# Preview without deleting anything
ghostscope bpffs prune --dry-run

# Remove one specific instance directory
ghostscope bpffs prune --instance 1234-567890

# Remove all pid-starttime directories, including live instances
ghostscope bpffs prune --all --force

# Emit machine-readable output
ghostscope bpffs prune --dry-run --json

Behavior:

  • Default prune removes only stale pid-starttime directories.
  • --instance targets one explicit pid-starttime directory.
  • --all --force removes all pid-starttime directories, including live ones.
  • Legacy numeric directories are ignored.

Native DWARF Indexes

When the ELF file containing DWARF also contains .debug_names, .gdb_index, or a complete .debug_gnu_pubnames / .debug_gnu_pubtypes pair, GhostScope uses that native index to select compilation units for on-demand parsing. The preference order is .debug_names, .gdb_index, then the GNU pubnames pair. Otherwise, it performs its normal full DWARF scan. An unusable or incomplete index is reported in CLI/TUI startup status before falling back.

Complete Command Reference

Option Short Description Default
--pid <PID> -p Process ID to attach to None
--target <PATH> -t Target executable or library. With -p, this scopes trace target resolution while -p supplies PID filtering. None
--script <SCRIPT> -s Inline script to execute None
--script-file <PATH> Script file to execute None
--script-help Print the embedded script language reference and exit Off
--value-diagnostics-help Print the embedded value diagnostics guide and exit Off
--script-output <MODE> Script event stdout mode: pretty, plain pretty
--backtrace-depth <N> Max DWARF-unwound frames captured by each bt/backtrace instruction (1..=128) 128
--no-backtrace-runtime-modules Disable compact-CFI loading for newly mapped bt/backtrace modules; events still render with available symbols, module offsets, or raw addresses Off
--backtrace-runtime-modules-max <N> Maximum distinct runtime modules whose CFI GhostScope will try to resolve (1..=1024) 32
--backtrace-runtime-module-timeout-ms <MS> Per-module runtime CFI loading timeout (100..=600000) 5000
--dry-run Compile the script, resolve trace targets, and exit without attaching uprobes. Requires the same eBPF privileges and kernel capabilities as a real run. Off
--dry-run-details Include source, inline, and variable diagnostics in dry-run output; requires --dry-run Off
--status Enable interactive DWARF/script/attach stderr status prompts On
--no-status Disable interactive DWARF/script/attach stderr status prompts Off override
--script-timestamp <FORMAT> Pretty output timestamp: local, boot, none local
--debug-file <PATH> -d Explicit debug info file for the target module Auto-detect
--debuginfod <MODE> debuginfod mode: off, on, ask off
--debuginfod-url <URL> debuginfod server URL; may be repeated None
--debuginfod-cache-dir <DIR> debuginfod cache directory debuginfod-compatible default
--debuginfod-timeout-secs <SECONDS> debuginfod request timeout; 0 disables timeout 5
--debuginfod-max-size <BYTES> debuginfod maximum response size; 0 disables cap 0
--tui Start in TUI mode Auto
--log Enable file logging Script: off, TUI: on
--no-log Disable all logging -
--log-console Enable console stderr logging Off
--no-log-console Disable console stderr logging -
--log-level <LEVEL> Set log level warn
--log-file <PATH> Log file path ./ghostscope.log
--save-llvm-ir Save LLVM IR files Debug: on, Release: off
--no-save-llvm-ir Don't save LLVM IR -
--save-ebpf Save eBPF bytecode Debug: on, Release: off
--no-save-ebpf Don't save eBPF -
--save-ast Save AST files Debug: on, Release: off
--no-save-ast Don't save AST -
--layout <MODE> TUI layout mode horizontal
--no-source-panel Hide source panel (two-panel layout) Off
--source-panel Show source panel On
--config <PATH> Custom config file Auto-detect
--force-perf-event-array Force PerfEventArray (testing) Off
--sleepable-uprobe Enable sleepable uprobes for this run; overrides a false config value Off
--enable-sysmon-for-target Re-enable target-mode sysmon for standalone -t when config disables it. Standalone -t enables target-mode sysmon by default; -t -p uses the -p watched-PID module-refresh path instead. Off
[BINARY] [ARGS...] Launch target program with positional arguments None
--args <PROGRAM> [ARGS...] Separate GhostScope options from target program arguments None

Subcommands:

Subcommand Description
bpffs prune Explicitly inspect or remove per-instance bpffs pin directories

Configuration File

GhostScope looks for configuration files in this order:

  1. Path specified with --config
  2. ~/.ghostscope/config.toml (user-level)
  3. ./ghostscope.toml (project-level)

Configuration File Format

# ~/.ghostscope/config.toml or ./ghostscope.toml

[general]
# Default log file path
log_file = "ghostscope.log"

# Default TUI mode when no script provided
default_tui_mode = true

# Enable/disable file logging
enable_logging = false

# Enable/disable console stderr logging
enable_console_logging = false

# Log level: error, warn, info, debug, trace
log_level = "warn"

[script]
# Event stdout rendering for non-TUI script mode
# pretty: timestamp + TraceID/PID/TID header + indented payload
# plain: payload lines only
output = "pretty"

# Interactive DWARF/script/attach status prompts on stderr
status = true

# Timestamp format for pretty script output: local, boot, none
timestamp = "local"

# ANSI color mode for pretty stdout and interactive stderr status:
# - auto: enable colors only when the corresponding stream is a TTY
# - always: force ANSI colors even when redirected
# - never: disable ANSI colors entirely
color = "auto"

[dwarf]
# Global directories for local separate debug information.
# GhostScope uses these roots for Build-ID and .gnu_debuglink discovery.
#
# The --debug-file/-d CLI option points directly at one debug file and bypasses
# this search list for the selected target module.
#
# Search order (highest priority first):
# 1. Absolute path (if .gnu_debuglink contains an absolute path - rare)
# 2. <search_path>/.build-id/xx/yyyy.debug, when a Build-ID is available
# 3. User-configured search_paths + basename (GhostScope compatibility path)
# 4. Same directory as the binary + basename
# 5. .debug subdirectory next to the binary + basename
# 6. <search_path>/<absolute_binary_directory>/<basename>
#
# For each user-configured path, GhostScope also checks the existing flat paths:
#   - <path>/debug_filename
#   - <path>/.debug/debug_filename
# Standard GDB directory layouts are checked as well:
#   - <path>/.build-id/xx/yyyy.debug
#   - <path>/<absolute_binary_directory>/debug_filename
#
# Features:
# - Home directory expansion: "~/" is replaced with your home directory
# - Duplicate paths are automatically removed to avoid redundant checks
# - Paths are tried in order until a matching debug file is found
#
# Note: .gnu_debuglink typically uses basename (relative path), but absolute
# paths are also supported. The default config includes /usr/lib/debug and
# /usr/local/lib/debug; if you replace search_paths, keep any system-wide debug
# directories that you still rely on.
#
# Examples:
search_paths = [
    "/usr/lib/debug",           # System debug symbols (for installed packages)
    "/usr/local/lib/debug",     # Local debug symbols
    "~/.local/lib/debug",       # User debug symbols (~ expands to home)
    "/opt/debug-symbols"        # Custom debug symbol server
]

# Allow non-strict debug file matching (CRC/Build-ID)
# Default: false (strict). When true, GhostScope will allow using a separate
# debug file even if CRC or Build-ID does not match exactly. Loose debuglink
# candidates are still reported as debuglink when they contain usable
# .debug_info. This is useful for ad-hoc environments or partially repackaged
# symbols, but may cause inaccurate symbol/line information. Prefer leaving
# this off unless you know what you are doing.
allow_loose_debug_match = false

# Load compact CFI only for modules referenced by observed bt/backtrace frames,
# in the background. Full debug indexes are not retained for these modules, and
# current events are never held while CFI is loaded.
backtrace_runtime_modules = true

# Bound distinct runtime-module attempts. Once reached, backtraces keep
# rendering with available symbols, module offsets, or raw addresses.
backtrace_runtime_modules_max = 32

# Per-module time budget. A timeout disables further automatic runtime CFI
# loading for the session, while tracing and raw-address rendering continue.
backtrace_runtime_module_timeout_ms = 5000

[dwarf.debuginfod]
# Optional debuginfod fallback for separate debug information.
# Modes follow GDB's model:
#   - "off": never use debuginfod and do not read debuginfod environment variables
#   - "on": allow debuginfod after embedded DWARF and local debug files fail
#   - "ask": reserved for future TUI confirmation support (currently not used)
#
# Default: "off" (no network access unless explicitly enabled)
enabled = "off"

# Server URLs. When enabled and this list is empty, GhostScope falls back to
# DEBUGINFOD_URLS. Values are whitespace-separated in the environment but are
# configured as a TOML array here.
urls = [
    # "https://debuginfod.ubuntu.com",
    # "https://debuginfod.archlinux.org",
]

# Cache directory for downloaded debuginfo/source artifacts.
# Leave unset to use:
#   1. DEBUGINFOD_CACHE_PATH
#   2. $XDG_CACHE_HOME/debuginfod_client
#   3. ~/.cache/debuginfod_client
# cache_dir = "~/.cache/debuginfod_client"

# Request timeout in seconds. Priority:
# CLI > config file > DEBUGINFOD_TIMEOUT > built-in default (5).
# Use 0 for no request timeout.
timeout_secs = 5

# Maximum response size in bytes. Priority:
# CLI > config file > DEBUGINFOD_MAXSIZE. Use 0 for no explicit cap.
max_size_bytes = 0

[value_adapters]
# Maximum semantic child edges below the root value, including ordinary Rust
# structs traversed to reach adapted fields. This does not affect native inline
# DWARF formatting for fields without semantic captures.
# Valid range: 1 to 16. Default: 4.
max_nesting_depth = 4

# Maximum semantic child elements captured for each nested sequence node.
# mem_dump_cap can reduce the effective count below this value.
# Valid range: 1 to 16. Default: 4.
max_sequence_elements = 4

[files]
# Save LLVM IR files
[files.save_llvm_ir]
debug = true
release = false

# Save eBPF bytecode files
[files.save_ebpf]
debug = true
release = false

# Save AST files
[files.save_ast]
debug = true
release = false

[ui]
# TUI layout mode: Horizontal or Vertical (capitalized)
layout = "Horizontal"

# Default focused panel: Source, EbpfInfo, or InteractiveCommand
default_focus = "InteractiveCommand"

# Show or hide the source panel (can also be controlled via CLI --source-panel/--no-source-panel,
# or via UI command 'ui source on/off')
show_source_panel = true

# Panel size ratios [Source, EbpfInfo, InteractiveCommand]
# Must be 3 positive (non-zero) integers
panel_ratios = [4, 3, 3]

# Two-panel ratios [EbpfInfo, InteractiveCommand] used when source panel is hidden
# If not set, it falls back to the last two values of panel_ratios (e.g., 4:3:3 -> 3:3)
# two_panel_ratios = [3, 3]

# Maximum number of eBPF trace messages to keep in the output panel
# Older messages are automatically discarded when this limit is reached
# Minimum value: 100
# Recommended values:
#   - Low-frequency tracing: 1000-2000
#   - Medium-frequency tracing: 2000-5000 (default: 2000)
#   - High-frequency tracing: 5000-10000
# Note: Larger values consume more memory
ebpf_max_messages = 2000

[ui.history]
# Enable command history
enabled = true

# Maximum history entries
max_entries = 5000

[ebpf]
# RingBuf map size in bytes (must be power of 2)
# Controls the size of the ring buffer for transferring trace events from kernel to userspace
# Valid range: 4096 (4KB) to 16777216 (16MB)
ringbuf_size = 262144  # 256KB (default)

# Recommended values:
#   - Low-frequency tracing: 131072 (128KB)
#   - Medium-frequency tracing: 262144 (256KB)
#   - High-frequency tracing: 524288 (512KB) or 1048576 (1MB)

# PerfEventArray page count per CPU (for older kernels < 5.8)
# Number of memory pages allocated per CPU for PerfEventArray buffers
# Each page is typically 4KB, so 64 pages = 256KB per CPU
# Must be a power of 2. Valid range: 8 to 1024 pages
perf_page_count = 64  # Default (256KB per CPU)

# Recommended values:
#   - Low-frequency tracing: 32 pages (~128KB per CPU)
#   - Medium-frequency tracing: 64 pages (~256KB per CPU)
#   - High-frequency tracing: 128-256 pages (512KB-1MB per CPU)

# Maximum number of (pid, module) offset entries for ASLR translation
# Stores runtime address offsets for each loaded module in each process
# Valid range: 64 to 65536
proc_module_offsets_max_entries = 4096  # Default

# Per-argument memory dump cap for extended format specifiers ({:x}/{:s}).
# Requests beyond this cap are truncated.
mem_dump_cap = 256

# Compare cap for built-in comparisons (strncmp/starts_with/memcmp).
# Controls the maximum number of bytes compared per call.
# Effective compare length is min(max(len, 0), compare_cap).
# Default: 64 bytes.
compare_cap = 64

# Maximum size of a single trace event (bytes). The protocol envelope requires
# at least 48 bytes; each script's instructions require additional space.
max_trace_event_size = 32768

# Recommended values:
#   - Simple prints: 16384
#   - General use: 32768
#   - Large formatted prints: 65536

# Max DWARF-unwound frames captured by each bt/backtrace instruction.
# Can be overridden for one run with --backtrace-depth.
# Valid range: 1 to 128.
backtrace_depth = 128

# Fixed capacity for compact DWARF unwind rows used by bt/backtrace.
# Runtime module refresh can append rows for newly loaded modules until this
# capacity is reached. Valid range: 1024 to 1048576 rows.
backtrace_unwind_rows_max_entries = 65536

# Force use of PerfEventArray instead of RingBuf (TESTING ONLY)
# WARNING: This is for testing purposes only. Set to true to force PerfEventArray
# even on kernels that support RingBuf (>= 5.8). PerfEventArray has performance
# overhead compared to RingBuf and should only be used for compatibility testing.
force_perf_event_array = false  # Default (auto-detect based on kernel version)

# Opt-in sleepable uprobes. Requires Linux 5.18+.
# Fixed-size user-memory reads use bpf_copy_from_user_task().
# NUL-terminated string reads retain bpf_probe_read_user_str() semantics.
# Long DWARF bt uses tail calls when the kernel allows them; otherwise it is
# limited to five inline frames and GhostScope prints a warning.
sleepable_uprobe = false  # Default

# Start sysmon eBPF for standalone -t targets.
# Maintains ASLR offsets for late-start processes and runtime module refresh for
# processes that map the target or other backtrace modules later.
# When -t is combined with -p, GhostScope uses the -p watched-PID module-refresh
# path instead of target-mode sysmon.
# This enables system-wide lifecycle tracepoints and may also enable map-change
# tracepoints, so it may impact performance when process churn or memory-map
# churn is high.
enable_sysmon_for_target = true  # Default

Value Adapter Limits

[value_adapters] controls recursive source-language semantic adapters:

  • max_nesting_depth counts semantic child edges below the root value, including ordinary Rust structs traversed to reach adapted fields and active enum payload transitions. It does not count the root itself and is independent of the depth-32 limit for native inline DWARF structure formatting.
  • max_sequence_elements limits the semantic children statically emitted for each nested sequence node and the captured buckets that receive repeated key/value sidecars in a nested hash table. It is a per-node width limit, not a recursion depth.

Both settings default to 4 and accept values from 1 through 16. The effective collection width is also bounded by the runtime sequence length or hash-table capacity and the argument's ebpf.mem_dump_cap. Increasing either setting can increase generated eBPF program size, event size, and probe overhead.

Configuration Examples

Development Configuration

# Development setup with verbose logging and debug output
[general]
log_level = "debug"
enable_logging = true
enable_console_logging = true

[files]
[files.save_llvm_ir]
debug = true
[files.save_ebpf]
debug = true
[files.save_ast]
debug = true

Production Configuration

# Production setup with minimal overhead
[general]
log_level = "error"
enable_logging = true
enable_console_logging = false
log_file = "/var/log/ghostscope.log"

[files]
[files.save_llvm_ir]
debug = false
release = false
[files.save_ebpf]
debug = false
release = false

UI-Focused Configuration

# Optimized for interactive debugging
[ui]
layout = "Horizontal"
default_focus = "Source"
panel_ratios = [5, 2, 3]  # Larger source panel

[ui.history]
enabled = true
max_entries = 10000

High-Frequency Tracing Configuration

# Optimized for high-frequency event tracing
[ebpf]
ringbuf_size = 1048576  # 1MB buffer for high event rates
mem_dump_cap = 4096     # Larger per-arg dump
compare_cap = 64        # Max bytes for built-in compares (strncmp/memcmp)
max_trace_event_size = 65536  # Larger event size for big formatted prints
backtrace_depth = 128   # Default full DWARF backtrace cap
proc_module_offsets_max_entries = 8192  # Support many modules

[general]
log_level = "info"  # Reduce logging overhead
enable_console_logging = false

Low-Overhead Configuration

# Minimal resource usage for production
[ebpf]
ringbuf_size = 131072  # 128KB minimal buffer
mem_dump_cap = 512
compare_cap = 32       # Smaller compare cap for minimal overhead
max_trace_event_size = 16384
backtrace_depth = 32
proc_module_offsets_max_entries = 1024  # Single process only
enable_sysmon_for_target = false        # Disable standalone -t lifecycle tracking

[general]
log_level = "error"
enable_logging = false

[files]
[files.save_llvm_ir]
debug = false
release = false
[files.save_ebpf]
debug = false
release = false

Environment Variables

RUST_LOG

Controls the final tracing filter whenever it is set. If RUST_LOG is unset, GhostScope uses the effective --log-level/config log_level value instead. RUST_LOG does not enable logging by itself. In script mode, pass --log or set [general].enable_logging = true; TUI mode enables file logging by default.

# Script mode: enable logging and set the filter via environment
export RUST_LOG=debug
ghostscope -p 1234 --script-file trace.gs --log

# Module-specific logging
export RUST_LOG=ghostscope=debug,ghostscope_compiler=trace
ghostscope -p 1234 --script-file trace.gs --log

Filter selection: RUST_LOG when set; otherwise the effective log_level. For non-default CLI levels, --log-level overrides the config file. warn is also the built-in fallback level, so use the config file when you need to make warn explicit over a different configured value.

LLVM_SYS_*_PREFIX

GhostScope requires LLVM 22.1.x. Specify its installation path if it is not found automatically:

export LLVM_SYS_221_PREFIX=/usr/lib/llvm-22

Default Behaviors

Logging Defaults

  • TUI Mode: File logging enabled, console logging disabled
  • Script Mode: All logging disabled by default
  • Log Level: warn if not specified
  • Log File: ./ghostscope.log in current directory

Startup Load Report

During startup, GhostScope can report how DWARF was loaded before traces attach. On an interactive terminal, when CLI status output is enabled and console stderr logging is inactive, the CLI script runner prints a final load report with the target summary, debug source counts (embedded, explicit, debuglink, debuginfod, missing), and per-module function/variable/type counts. The TUI loading screen shows the same source categories in its progress and completion views.

missing means the module was mapped and loaded, but GhostScope did not find usable DWARF for that module. This includes .gnu_debuglink files that match the binary but contain no .debug_info. Use --log --log-level debug --log-file <path> for the full paths and lower-level resolution details. RUST_LOG=debug can be used instead of --log-level debug when logging is enabled.

Debug Output Defaults

  • Debug Builds: Save LLVM IR, eBPF bytecode, and AST files
  • Release Builds: Don't save any debug files

UI Defaults

  • Layout: Horizontal (panels side by side)
  • Panel Ratios: 4:3:3 (Source:EbpfInfo:Command)
  • Default Focus: InteractiveCommand panel
  • eBPF Max Messages: 2000 messages
  • History: Enabled with 5000 entry limit

File Output Naming

Debug files are saved with this naming convention:

gs_{pid}_{exec}_{func}_{index}.{ext}

Where:

  • pid: Process ID
  • exec: Executable name
  • func: Function name
  • index: Unique index for multiple traces
  • ext: File extension (.ll for LLVM IR, .ebpf for bytecode, .ast for AST)

Example: gs_1234_myapp_main_0.ll

Validation

GhostScope validates configuration at startup:

  1. PID Validation: Checks if specified PID exists (via /proc/<PID> on Linux)
  2. File Validation: Verifies target, script, and debug files exist
  3. Target Path Resolution: Converts relative paths to absolute paths
  4. Panel Ratios: Ensures all 3 values are positive (non-zero) integers
  5. Log Level: Validates against allowed values (error, warn, info, debug, trace)
  6. Layout Mode: Validates against allowed values (Horizontal, Vertical - capitalized)
  7. UI Configuration:
    • ebpf_max_messages: Must be at least 100
  8. Value Adapter Configuration:
    • max_nesting_depth: Must be in range 1-16
    • max_sequence_elements: Must be in range 1-16
  9. eBPF Configuration:
    • ringbuf_size: Must be power of 2, range 4096-16777216 bytes
    • perf_page_count: Must be power of 2, range 8-1024 pages
    • proc_module_offsets_max_entries: Must be in range 64-65536
    • backtrace_depth: Must be in range 1-128 frames
    • backtrace_unwind_rows_max_entries: Must be in range 1024-1048576 rows
    • max_trace_event_size: Must be at least 48 bytes; individual scripts may require more.
    • mem_dump_cap, compare_cap, and max_trace_event_size are runtime caps; max_trace_event_size may be clamped by the selected event transport.

Invalid configuration will produce clear error messages with suggestions for fixes.

Common Validation Errors

  • "Process with PID X is not running": Target process not found. Use ps -p <PID> to verify.
  • "Target file does not exist": Specified target path not found. Check the file path.
  • "Script file does not exist": Specified script file not found.
  • "Invalid log level": Use one of: error, warn, info, debug, trace.
  • "ringbuf_size must be a power of 2": Use values like 131072, 262144, 524288, etc.
  • "ringbuf_size X is out of reasonable range": Must be between 4KB and 16MB.
  • "perf_page_count must be a power of 2": Use values like 32, 64, 128, 256, etc.
  • "perf_page_count X is out of reasonable range": Must be between 8 and 1024 pages.
  • "proc_module_offsets_max_entries X is out of reasonable range": Must be between 64 and 65536.
  • "ebpf_max_messages X is too small": Must be at least 100. Increase the value in your config file.

Best Practices

  1. Use Configuration Files: Store common settings in ~/.ghostscope/config.toml
  2. Environment-Specific Configs: Keep separate configs for development and production
  3. Log Rotation: Configure external log rotation for long-running sessions
  4. Debug Output: Disable debug file saving in production for performance
  5. Panel Layout: Use horizontal layout for wide screens, vertical for narrow displays
  6. eBPF Tuning:
    • Start with default ringbuf_size (256KB) and increase if events are dropped
    • Monitor kernel memory usage when using large ringbuf sizes
    • Use smaller proc_module_offsets_max_entries for single-process debugging
    • Increase buffer size for high-frequency tracing scenarios