The underlying eBPF mechanism requires elevated privileges to access kernel tracing infrastructure. Root access or CAP_BPF/CAP_SYS_ADMIN capabilities are needed.
Both uprobe and GDB modify target process instructions (inserting breakpoints). Using them together may lead to conflicts and unpredictable behavior.
Although eBPF technically supports modifying process behavior to some extent, GhostScope is designed as a read-only tool and cannot modify program state, variable values, or control flow. This ensures safety in production environments.
Currently only supports Linux operating system due to its core dependency on eBPF and uprobe.
Primary focus is on C language, which currently has the best end-to-end support. C++ and Rust are supported in a more limited, DWARF-layout-oriented way: GhostScope can automatically demangle function names and global/static symbols, but most language-specific features are not modeled yet. In practice, simple C-like layouts work best, while advanced Rust and C++ features still require substantial future work.
For interpreted languages (Lua, Python, Ruby, etc.), only the interpreter itself can be traced (since interpreters are typically implemented in compiled languages). Tracing script code is technically feasible but requires substantial development time. JIT language support is an even more distant goal.
Currently only supports x86_64 (AMD64) architecture. Other platforms (such as ARM64) are technically feasible but require time for adaptation and testing.
In traditional non-sleepable probe paths, helpers such as bpf_probe_read_user cannot resolve user-space page faults, so reads from a target virtual address may still fail if the page is not resident or otherwise faults on access.
This is no longer an absolute eBPF limitation. Linux now supports sleepable uprobes (uprobe.s / uretprobe.s), and sleepable programs can use helpers such as bpf_copy_from_user_task() for fault-capable user-memory reads. GhostScope currently emits regular uprobe programs, so this remains a practical limitation today, but it is better described as a soft implementation limitation rather than a fundamental design limit of eBPF.
References:
- https://lists.iovisor.org/g/iovisor-dev/topic/accessing_user_memory_and/21386221
- https://docs.kernel.org/bpf/libbpf/program_types.html
- https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
Based on uprobe implementation, each probe trigger incurs a context switch overhead plus eBPF program execution time. If probes are set on hot paths, they may significantly impact the monitored process performance. Use with caution.
Uses ring buffer to pass events between eBPF programs and userspace. If event generation rate exceeds userspace consumption capacity, the kernel will drop events, leading to trace data loss. GhostScope's error reporting is not yet comprehensive (will learn from bpftrace's approach in the future); avoid setting too many probes on high-frequency paths.
Primarily tested and validated with DWARF 5 format. Theoretically supports DWARF 2-5, but other versions may have compatibility issues. Some DWARF expression instructions are not yet supported for conversion to eBPF (purely due to implementation not being completed yet) and will provide clear error messages when encountered.
Compiler optimizations (-O2, -O3) can cause variables to be optimized away or generate complex DWARF expressions. GhostScope will attempt to parse them, including inline function support, but some variables may be inaccessible (shown as OptimizedOut) because the compiler optimized them away.
GhostScope scans /proc/PID/maps at startup to obtain loaded dynamic library information. As long as GhostScope is started after dlopen, tracing works normally. Future plans include dynamically monitoring process dlopen behavior for better user experience.
- Executable targets: When
-tpoints to an executable (-t /path/to/app), GhostScope treats that binary as the primary module and globals are supported by default. - Shared-library targets (existing processes): If GhostScope starts after the library has already been mapped (e.g., tracing a running process that loaded
libfoo.soearlier), globals work without extra steps. - Shared-library targets (new processes): For processes that start after GhostScope, enable
--enable-sysmon-shared-lib(or the matching config option) so globals can be resolved. This incurs extra system-wide work, so expect higher overhead on hosts with frequent process churn.
Note: The current sysmon pipeline still assumes the library is mapped when the exec event is handled; if a loader pulls it in much later, offsets are not retried yet.
- See Container Environments for the full explanation of container / WSL scenarios, PID namespace terminology, the scenario matrix, and current implementation limits.
- See PID namespaces manual, WSL issue #12408, and WSL issue #12115 for background.