diff --git a/docs/configuration.md b/docs/configuration.md index 3bc0022..e7935f5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -173,11 +173,12 @@ ghostscope --source-panel # Show source panel # WARNING: Testing purposes only. Forces PerfEventArray even on kernels >= 5.8 ghostscope --force-perf-event-array -# Start sysmon for standalone -t when target is a shared library (.so). -# Not needed when -t is combined with -p. +# Standalone -t starts sysmon by default. It is not used when -t is +# combined with -p because the PID already provides concrete process mappings. # WARNING: Attaches system-wide sched tracepoints (exec/fork/exit) and may add -# overhead on hosts with high process churn. Default is OFF. -ghostscope --enable-sysmon-shared-lib +# overhead on hosts with high process churn. 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 ``` ### BPFFS Maintenance @@ -252,7 +253,7 @@ Behavior: | `--source-panel` | | Show source panel | On | | `--config ` | | Custom config file | Auto-detect | | `--force-perf-event-array` | | Force PerfEventArray (testing) | Off | -| `--enable-sysmon-shared-lib` | | Start sysmon for standalone `-t` shared library, so globals can be traced in future processes. Not needed with `-t -p`. | Off | +| `--enable-sysmon-for-target` | | Re-enable sysmon for standalone `-t` when config disables it. Standalone `-t` enables sysmon by default; `-t -p` does not use it. | Off | | `[BINARY] [ARGS...]` | | Launch target program with positional arguments | None | | `--args [ARGS...]` | | Separate GhostScope options from target program arguments | None | @@ -485,13 +486,13 @@ max_trace_event_size = 32768 # overhead compared to RingBuf and should only be used for compatibility testing. force_perf_event_array = false # Default (auto-detect based on kernel version) -# Start sysmon eBPF for standalone -t when the target is a shared library (.so). -# Maintains ASLR offsets for late-start processes loading the library. +# Start sysmon eBPF for standalone -t targets. +# Maintains ASLR offsets for late-start processes loading the target. # Not used when -t is combined with -p, because the PID already provides the # concrete process mappings. # This enables system-wide sched tracepoints and may impact performance # when process churn is high. -enable_sysmon_for_shared_lib = false # Default +enable_sysmon_for_target = true # Default ``` ### Configuration Examples @@ -573,6 +574,7 @@ mem_dump_cap = 512 compare_cap = 32 # Smaller compare cap for minimal overhead max_trace_event_size = 16384 proc_module_offsets_max_entries = 1024 # Single process only +enable_sysmon_for_target = false # Disable standalone -t lifecycle tracking [general] log_level = "error" diff --git a/docs/container.md b/docs/container.md index 562ce71..342b155 100644 --- a/docs/container.md +++ b/docs/container.md @@ -425,7 +425,7 @@ It mainly listens for: - `fork` - `exit` -In the current implementation, `-p` mode does not start this pipeline. A combined `-t -p ` run also does not start `sysmon`: `-t` scopes function/source/address target resolution to one module, while `-p` supplies the concrete process mappings and PID filter. `sysmon` mainly serves standalone `-t` mode, especially when GhostScope needs to keep module offsets, allowlists, and exit cleanup up to date after the target starts. +In the current implementation, standalone `-t` starts this pipeline by default unless `enable_sysmon_for_target = false` is set in config. `-p` mode does not start it. A combined `-t -p ` run also does not start `sysmon`: `-t` scopes function/source/address target resolution to one module, while `-p` supplies the concrete process mappings and PID filter. `sysmon` mainly serves standalone `-t` mode, especially when GhostScope needs to keep module offsets, allowlists, and exit cleanup up to date after the target starts. #### Which PID View sysmon Depends On diff --git a/docs/limitations.md b/docs/limitations.md index 2652bb2..1c4c4cc 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -55,7 +55,7 @@ GhostScope scans `/proc/PID/maps` at startup to obtain loaded dynamic library in - **Executable targets**: When `-t` points 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.so` earlier), 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. +- **Shared-library targets (new processes)**: Standalone `-t` starts sysmon by default so globals can be resolved for later-started processes. This incurs extra system-wide work, so expect higher overhead on hosts with frequent process churn; set `enable_sysmon_for_target = false` in config to disable it. - **Target-scoped PID runs (`-t ... -p ...`)**: sysmon is not needed or started. `-t` chooses the module used for function/source/address target resolution, while `-p` supplies the concrete process mappings and PID filter. > **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. diff --git a/docs/tutorial.md b/docs/tutorial.md index 87f5569..b871825 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -47,7 +47,7 @@ sudo ghostscope -t /usr/lib/libexample.so ``` - **When to use**: You want to catch process startup events or trace multiple instances - **Advantage**: Can capture events from process initialization, perfect for debugging startup issues -- **Note**: Will trace ALL processes using this binary/library, which may generate more events +- **Note**: Standalone `-t` starts sysmon by default and will trace ALL processes using this binary/library, which may generate more events. Set `enable_sysmon_for_target = false` in config to disable sysmon for standalone `-t`. - **Target-scoped PID variant**: Use `-t /path/to/module -p ` when you want `-t` target resolution for one module but only one running process's events. In this variant, `-t` takes precedence and `sysmon` is not started. #### Important Notes diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md index 90e421c..35f8740 100644 --- a/docs/zh/configuration.md +++ b/docs/zh/configuration.md @@ -174,11 +174,12 @@ ghostscope --source-panel # 显示源码面板 # 警告:仅用于测试目的。即使在内核 >= 5.8 上也强制使用 PerfEventArray ghostscope --force-perf-event-array -# 当独立 -t 目标是共享库(.so)时启动 sysmon。 -# -t 与 -p 同时使用时不需要。 +# 独立 -t 默认启动 sysmon。-t 与 -p 同时使用时不会使用 sysmon, +# 因为 PID 已经提供了具体进程映射。 # 警告:该选项会全局附加 sched 的 exec/fork/exit tracepoint,在进程频繁 -# 启动/退出的主机上可能带来一定性能开销。默认关闭。 -ghostscope --enable-sysmon-shared-lib +# 启动/退出的主机上可能带来一定性能开销。可在配置中设置 +# enable_sysmon_for_target=false 关闭;该选项可为单次运行重新开启。 +ghostscope --enable-sysmon-for-target ``` ### BPFFS 维护 @@ -253,7 +254,7 @@ ghostscope bpffs prune --dry-run --json | `--source-panel` | | 显示源码面板 | 开 | | `--config ` | | 自定义配置文件 | 自动检测 | | `--force-perf-event-array` | | 强制 PerfEventArray(测试) | 关 | -| `--enable-sysmon-shared-lib` | | 独立 `-t` 目标为共享库时启动 sysmon,以支持未来进程中的全局变量探测。`-t -p` 不需要。 | 关 | +| `--enable-sysmon-for-target` | | 当配置关闭 sysmon 时,重新为独立 `-t` 开启 sysmon。独立 `-t` 默认开启;`-t -p` 不使用 sysmon。 | 关 | | `[BINARY] [ARGS...]` | | 启动目标程序并传递位置参数 | 无 | | `--args [ARGS...]` | | 分隔 GhostScope 选项和目标程序参数 | 无 | @@ -480,11 +481,11 @@ max_trace_event_size = 32768 # 有性能开销,仅应用于兼容性测试。 force_perf_event_array = false # 默认(根据内核版本自动检测) -# 当独立 -t 目标为共享库(.so)时启动 sysmon eBPF, -# 用于维护后续启动进程里动态库的 ASLR 偏移。 +# 为独立 -t 目标启动 sysmon eBPF, +# 用于维护后续启动进程里目标模块的 ASLR 偏移。 # -t 与 -p 同时使用时不会使用 sysmon,因为 PID 已经提供具体进程映射。 # 启用后会注册系统范围的 sched tracepoint,进程频繁创建/退出的环境下可能带来性能开销。 -enable_sysmon_for_shared_lib = false # 默认关闭 +enable_sysmon_for_target = true # 默认开启 ``` ### 配置示例 @@ -566,6 +567,7 @@ mem_dump_cap = 512 compare_cap = 32 # 降低内置比较上限以减小开销 max_trace_event_size = 16384 proc_module_offsets_max_entries = 1024 # 仅单进程 +enable_sysmon_for_target = false # 关闭独立 -t 生命周期跟踪 [general] log_level = "error" diff --git a/docs/zh/container.md b/docs/zh/container.md index 46773c7..51b1a8c 100644 --- a/docs/zh/container.md +++ b/docs/zh/container.md @@ -424,7 +424,7 @@ proc_offsets_runtime_pid -> pid_aliases -> proc_offsets_lookup_pid (= 通常就 - `fork` - `exit` -当前实现里,`-p` 模式不启动这条链路。组合使用 `-t -p ` 时也不会启动 `sysmon`:`-t` 只负责把函数/源码行/地址目标解析限定到一个模块,`-p` 提供具体进程映射和 PID 过滤。`sysmon` 主要服务于独立 `-t` 模式,尤其是需要在目标进程启动后持续维护模块 offsets、allowlist 和退出清理的时候。 +当前实现里,独立 `-t` 默认启动这条链路,除非配置中设置了 `enable_sysmon_for_target = false`。`-p` 模式不启动这条链路。组合使用 `-t -p ` 时也不会启动 `sysmon`:`-t` 只负责把函数/源码行/地址目标解析限定到一个模块,`-p` 提供具体进程映射和 PID 过滤。`sysmon` 主要服务于独立 `-t` 模式,尤其是需要在目标进程启动后持续维护模块 offsets、allowlist 和退出清理的时候。 #### `sysmon` 依赖什么 PID 视角 diff --git a/docs/zh/limitations.md b/docs/zh/limitations.md index e648868..74347f8 100644 --- a/docs/zh/limitations.md +++ b/docs/zh/limitations.md @@ -55,7 +55,7 @@ GhostScope 启动时会扫描进程的 `/proc/PID/maps` 获取已加载的动态 - **可执行目标**:当 `-t` 指向可执行文件(`-t /path/to/app`)时,会以该二进制作为主模块,默认支持全局变量。 - **共享库目标(已有进程)**:若 GhostScope 启动时,目标库已经被现有进程加载,例如追踪一个已运行但早先加载好 `libfoo.so` 的进程,能够直接解析全局变量。 -- **共享库目标(新启动进程)**:如果目标进程在 GhostScope 启动之后才运行,为确保全局变量可用,需要开启 `--enable-sysmon-shared-lib`(或在配置文件中启用)。该功能会带来额外的系统负载,进程频繁启动/退出的环境下开销会更明显。 +- **共享库目标(新启动进程)**:独立 `-t` 默认启动 sysmon,因此能为后续启动的进程解析全局变量。该功能会带来额外的系统负载,进程频繁启动/退出的环境下开销会更明显;可在配置文件中设置 `enable_sysmon_for_target = false` 关闭。 - **限定 PID 的目标模式(`-t ... -p ...`)**:不需要也不会启动 sysmon。`-t` 决定函数/源码行/地址目标解析使用哪个模块,`-p` 提供具体进程映射和 PID 过滤。 提示:`-p ` 模式下仍会自动计算并下发模块偏移,全局变量始终可用。 diff --git a/docs/zh/tutorial.md b/docs/zh/tutorial.md index 0b4fc75..bc03da0 100644 --- a/docs/zh/tutorial.md +++ b/docs/zh/tutorial.md @@ -47,7 +47,7 @@ sudo ghostscope -t /usr/lib/libexample.so ``` - **使用场景**:您想捕获进程启动事件或追踪多个实例 - **优势**:可以捕获进程初始化的事件,非常适合调试启动问题 -- **注意**:将追踪所有使用此二进制文件/库的进程,可能会产生更多事件 +- **注意**:独立 `-t` 默认启动 sysmon,并会追踪所有使用此二进制文件/库的进程,可能会产生更多事件。可在配置中设置 `enable_sysmon_for_target = false` 关闭独立 `-t` 的 sysmon。 - **限定 PID 的目标模式**:如果想使用 `-t /path/to/module` 的模块目标解析,但只观察一个运行中进程的事件,可以使用 `-t /path/to/module -p `。这种形式下以 `-t` 为准,且不会启动 sysmon。 #### 重要说明 diff --git a/e2e-tests/tests/c_multithread_execution.rs b/e2e-tests/tests/c_multithread_execution.rs index 73f263e..a1bd2b7 100644 --- a/e2e-tests/tests/c_multithread_execution.rs +++ b/e2e-tests/tests/c_multithread_execution.rs @@ -18,7 +18,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/common/mod.rs b/e2e-tests/tests/common/mod.rs index 61fb9b7..1051af0 100644 --- a/e2e-tests/tests/common/mod.rs +++ b/e2e-tests/tests/common/mod.rs @@ -257,7 +257,7 @@ pub fn init() { .with_target("/") .with_cli_args([std::ffi::OsString::from("--help")]) .force_perf_event_array(false) - .enable_sysmon_shared_lib(false); + .enable_sysmon_for_target(false); let _use_pid_check: fn(u32) -> bool = host_pid_is_running; let _use_compiler_check: fn(FixtureCompiler) -> bool = fixture_compiler_available; diff --git a/e2e-tests/tests/common/runner.rs b/e2e-tests/tests/common/runner.rs index 363f26b..33c76ae 100644 --- a/e2e-tests/tests/common/runner.rs +++ b/e2e-tests/tests/common/runner.rs @@ -49,7 +49,8 @@ pub struct GhostscopeRunner { timeout_secs: u64, force_perf_event_array: bool, log_level: Option, - enable_sysmon_shared_lib: bool, + enable_sysmon_for_target: bool, + disable_sysmon_for_target: bool, enable_file_logging: bool, enable_console_logging: bool, sandbox: Option, @@ -66,7 +67,8 @@ impl Default for GhostscopeRunner { timeout_secs: 3, force_perf_event_array: false, log_level: None, - enable_sysmon_shared_lib: false, + enable_sysmon_for_target: false, + disable_sysmon_for_target: false, enable_file_logging: false, enable_console_logging: false, sandbox: None, @@ -118,8 +120,13 @@ impl GhostscopeRunner { self } - pub fn enable_sysmon_shared_lib(mut self, yes: bool) -> Self { - self.enable_sysmon_shared_lib = yes; + pub fn enable_sysmon_for_target(mut self, yes: bool) -> Self { + self.enable_sysmon_for_target = yes; + self + } + + pub fn disable_sysmon_for_target(mut self, yes: bool) -> Self { + self.disable_sysmon_for_target = yes; self } @@ -227,6 +234,13 @@ impl GhostscopeRunner { use std::io::Write as _; script_file.write_all(self.script_content.as_bytes())?; let script_path = sandbox.path_in_sandbox(script_file.path())?; + let sysmon_config_file = if self.disable_sysmon_for_target { + let mut file = create_config_file()?; + file.write_all(b"[ebpf]\nenable_sysmon_for_target = false\n")?; + Some(file) + } else { + None + }; let mut args: Vec = Vec::new(); if let Some(ref target) = self.target { @@ -244,6 +258,14 @@ impl GhostscopeRunner { args.push(OsString::from("--script-file")); args.push(script_path.into_os_string()); + if let Some(config_file) = sysmon_config_file.as_ref() { + args.push(OsString::from("--config")); + args.push( + sandbox + .path_in_sandbox(config_file.path())? + .into_os_string(), + ); + } if let Some(level) = &logging.level { args.push(OsString::from("--log-level")); @@ -256,8 +278,8 @@ impl GhostscopeRunner { args.push(OsString::from("--emit-ready-marker")); args.push(OsString::from(marker)); } - if self.enable_sysmon_shared_lib { - args.push(OsString::from("--enable-sysmon-shared-lib")); + if self.enable_sysmon_for_target { + args.push(OsString::from("--enable-sysmon-for-target")); } if logging.enable_logging { args.push(OsString::from("--log")); @@ -721,6 +743,18 @@ fn create_script_file() -> Result { .map_err(Into::into) } +fn create_config_file() -> Result { + let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent() + .ok_or_else(|| anyhow::anyhow!("failed to resolve repo root for temp config file"))? + .to_path_buf(); + Builder::new() + .prefix(".ghostscope-test-config-") + .suffix(".toml") + .tempfile_in(repo_root) + .map_err(Into::into) +} + fn env_bool(name: &str) -> Option { let raw = env::var(name).ok()?; let value = raw.trim(); diff --git a/e2e-tests/tests/complex_types_execution.rs b/e2e-tests/tests/complex_types_execution.rs index 11f41bc..aaa48c6 100644 --- a/e2e-tests/tests/complex_types_execution.rs +++ b/e2e-tests/tests/complex_types_execution.rs @@ -17,7 +17,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } @@ -32,7 +32,7 @@ async fn run_ghostscope_with_script_for_target_perf( .attach_to(target) .timeout_secs(timeout_secs) .force_perf_event_array(true) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/cpp_script_execution.rs b/e2e-tests/tests/cpp_script_execution.rs index 4e12440..3a2d87d 100644 --- a/e2e-tests/tests/cpp_script_execution.rs +++ b/e2e-tests/tests/cpp_script_execution.rs @@ -31,7 +31,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/debuginfod_execution.rs b/e2e-tests/tests/debuginfod_execution.rs index 059d201..19b0ddb 100644 --- a/e2e-tests/tests/debuginfod_execution.rs +++ b/e2e-tests/tests/debuginfod_execution.rs @@ -86,7 +86,7 @@ trace add_numbers { .with_script(script_content) .attach_to(&target) .timeout_secs(4) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .with_cli_args(cli_args) .run() .await?; diff --git a/e2e-tests/tests/entry_value_recovery_execution.rs b/e2e-tests/tests/entry_value_recovery_execution.rs index 45484b6..d57d622 100644 --- a/e2e-tests/tests/entry_value_recovery_execution.rs +++ b/e2e-tests/tests/entry_value_recovery_execution.rs @@ -488,7 +488,7 @@ async fn test_non_inline_entry_value_recovers_touch_parameters_at_runtime() -> a .with_script(&script) .attach_to(&target.target) .timeout_secs(4) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; let (target_stdout, target_stderr) = target.terminate_and_collect().await?; @@ -647,7 +647,7 @@ async fn test_post_call_entry_value_recovers_state_members_at_runtime() -> anyho .with_script(&script) .attach_to(&target.target) .timeout_secs(4) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; let (target_stdout, target_stderr) = target.terminate_and_collect().await?; @@ -778,7 +778,7 @@ async fn test_post_call_entry_value_state_pointer_memory_formats() -> anyhow::Re .with_script(&script) .attach_to(&target.target) .timeout_secs(4) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; let (_target_stdout, target_stderr) = target.terminate_and_collect().await?; @@ -837,7 +837,7 @@ async fn test_entry_value_breg_stack_parameter_recovers_at_runtime() -> anyhow:: .with_script(&script) .attach_to(&target.target) .timeout_secs(4) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; let (target_stdout, target_stderr) = target.terminate_and_collect().await?; diff --git a/e2e-tests/tests/globals_execution.rs b/e2e-tests/tests/globals_execution.rs index ad9f447..3ba22c9 100644 --- a/e2e-tests/tests/globals_execution.rs +++ b/e2e-tests/tests/globals_execution.rs @@ -18,7 +18,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } @@ -33,7 +33,7 @@ async fn run_ghostscope_with_script_for_target_perf( .attach_to(target) .timeout_secs(timeout_secs) .force_perf_event_array(true) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } @@ -48,7 +48,7 @@ async fn run_ghostscope_with_script_for_target_with_log( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/globals_target_execution.rs b/e2e-tests/tests/globals_target_execution.rs index 236c786..1173b04 100644 --- a/e2e-tests/tests/globals_target_execution.rs +++ b/e2e-tests/tests/globals_target_execution.rs @@ -4,7 +4,6 @@ mod common; use common::{init, FIXTURES}; -use ghostscope_process::is_shared_object; use regex::Regex; use serial_test::serial; use std::env; @@ -22,12 +21,10 @@ async fn run_ghostscope_with_script_for_target( timeout_secs: u64, target_path: &std::path::Path, ) -> anyhow::Result<(i32, String, String)> { - let enable_sysmon = is_shared_object(target_path); common::runner::GhostscopeRunner::new() .with_script(script_content) .with_target(target_path) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(enable_sysmon) .run() .await } @@ -302,7 +299,7 @@ trace 0x{lib_tick_addr:x} {{ .with_target(&lib_path) .attach_to(&target) .timeout_secs(2) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; target.terminate().await?; @@ -354,7 +351,7 @@ trace libgvars_alias.so:0x{lib_tick_addr:x} {{ .with_target(&target_symlink) .attach_to(&target) .timeout_secs(2) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await?; target.terminate().await?; @@ -575,7 +572,7 @@ trace lib_tick { .with_script(script) .with_target(&lib_path) .timeout_secs(12) - .enable_sysmon_shared_lib(true), + .enable_sysmon_for_target(true), &binary_path, ) .await?; @@ -698,7 +695,7 @@ trace lib_tick { .with_script(script) .with_target(&lib_path) .timeout_secs(8) - .enable_sysmon_shared_lib(false), + .disable_sysmon_for_target(true), &binary_path, ) .await?; diff --git a/e2e-tests/tests/member_pointer_execution.rs b/e2e-tests/tests/member_pointer_execution.rs index 40a2ce0..9af8914 100644 --- a/e2e-tests/tests/member_pointer_execution.rs +++ b/e2e-tests/tests/member_pointer_execution.rs @@ -19,7 +19,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/optimized_inline_call_value_execution.rs b/e2e-tests/tests/optimized_inline_call_value_execution.rs index 95bbe7b..488b8be 100644 --- a/e2e-tests/tests/optimized_inline_call_value_execution.rs +++ b/e2e-tests/tests/optimized_inline_call_value_execution.rs @@ -41,7 +41,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/optimized_inline_execution.rs b/e2e-tests/tests/optimized_inline_execution.rs index cd9a3eb..12f8895 100644 --- a/e2e-tests/tests/optimized_inline_execution.rs +++ b/e2e-tests/tests/optimized_inline_execution.rs @@ -26,7 +26,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/partitioned_ranges_execution.rs b/e2e-tests/tests/partitioned_ranges_execution.rs index b6d40c1..8cef703 100644 --- a/e2e-tests/tests/partitioned_ranges_execution.rs +++ b/e2e-tests/tests/partitioned_ranges_execution.rs @@ -14,7 +14,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/rust_script_execution.rs b/e2e-tests/tests/rust_script_execution.rs index 8e40c1d..58e4351 100644 --- a/e2e-tests/tests/rust_script_execution.rs +++ b/e2e-tests/tests/rust_script_execution.rs @@ -13,7 +13,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/scalar_types_execution.rs b/e2e-tests/tests/scalar_types_execution.rs index 1bd41f1..f52c5d2 100644 --- a/e2e-tests/tests/scalar_types_execution.rs +++ b/e2e-tests/tests/scalar_types_execution.rs @@ -16,7 +16,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/script_execution.rs b/e2e-tests/tests/script_execution.rs index 6c00435..a118b45 100644 --- a/e2e-tests/tests/script_execution.rs +++ b/e2e-tests/tests/script_execution.rs @@ -427,7 +427,7 @@ async fn run_ghostscope_with_script_opt( .with_script(script_content) .attach_to(&target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } @@ -2089,7 +2089,7 @@ async fn run_ghostscope_with_specific_pid( .with_script(script_content) .with_pid(target_pid) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } @@ -2103,7 +2103,7 @@ async fn run_ghostscope_attached_to_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/e2e-tests/tests/static_scope_execution.rs b/e2e-tests/tests/static_scope_execution.rs index 4b67ffa..2232e1d 100644 --- a/e2e-tests/tests/static_scope_execution.rs +++ b/e2e-tests/tests/static_scope_execution.rs @@ -13,7 +13,7 @@ async fn run_ghostscope_with_script_for_target( .with_script(script_content) .attach_to(target) .timeout_secs(timeout_secs) - .enable_sysmon_shared_lib(false) + .enable_sysmon_for_target(false) .run() .await } diff --git a/ghostscope/src/config/args.rs b/ghostscope/src/config/args.rs index 619a8b1..ec81cdb 100644 --- a/ghostscope/src/config/args.rs +++ b/ghostscope/src/config/args.rs @@ -286,12 +286,14 @@ pub struct Args { #[arg(long, action = clap::ArgAction::SetTrue)] pub force_perf_event_array: bool, - /// Enable sysmon eBPF for -t when the target is a shared library (.so). - /// This starts system-wide sched exec/fork/exit tracepoints to maintain - /// ASLR offsets for late-start processes loading the library. Disabled by - /// default due to possible overhead on systems with high process churn. - #[arg(long = "enable-sysmon-shared-lib", action = clap::ArgAction::SetTrue)] - pub enable_sysmon_shared_lib: bool, + /// Re-enable sysmon eBPF for standalone -t if config disabled it. + /// Standalone -t starts sysmon by default; -t with -p does not use sysmon. + #[arg( + long = "enable-sysmon-for-target", + alias = "enable-sysmon-shared-lib", + action = clap::ArgAction::SetTrue + )] + pub enable_sysmon_for_target: bool, /// Show the source panel explicitly (overrides config) #[arg(long, action = clap::ArgAction::SetTrue)] @@ -333,7 +335,7 @@ pub struct ParsedArgs { pub should_save_ast: bool, pub layout_mode: LayoutMode, pub force_perf_event_array: bool, - pub enable_sysmon_for_shared_lib: bool, + pub enable_sysmon_for_target: bool, pub allow_loose_debug_match: bool, pub debuginfod: Option, pub debuginfod_urls: Vec, @@ -510,7 +512,7 @@ impl Args { should_save_ast, layout_mode: parsed.layout, force_perf_event_array: parsed.force_perf_event_array, - enable_sysmon_for_shared_lib: parsed.enable_sysmon_shared_lib, + enable_sysmon_for_target: parsed.enable_sysmon_for_target, allow_loose_debug_match: parsed.allow_loose_debug_match, debuginfod: parsed.debuginfod, debuginfod_urls: parsed.debuginfod_urls, diff --git a/ghostscope/src/config/settings.rs b/ghostscope/src/config/settings.rs index 1894982..a20c73b 100644 --- a/ghostscope/src/config/settings.rs +++ b/ghostscope/src/config/settings.rs @@ -210,6 +210,7 @@ pub struct PathSubstitution { } #[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] pub struct EbpfConfig { /// RingBuf map size in bytes (must be power of 2) /// Recommended values: @@ -249,12 +250,12 @@ pub struct EbpfConfig { /// Default: 32768 bytes (32KB). Increase for larger formatted prints. #[serde(default = "default_max_trace_event_size")] pub max_trace_event_size: u32, - /// Start sysmon eBPF for -t when the target is a shared library (.so). - /// Maintains ASLR offsets for late-start processes loading the library. + /// Start sysmon eBPF for standalone -t targets. + /// Maintains ASLR offsets for late-start processes loading the target. /// WARNING: This enables system-wide sched tracepoints and may impact - /// performance on hosts with high process churn. Default: false. - #[serde(default = "default_enable_sysmon_for_shared_lib")] - pub enable_sysmon_for_shared_lib: bool, + /// performance on hosts with high process churn. Default: true. + #[serde(default = "default_enable_sysmon_for_target")] + pub enable_sysmon_for_target: bool, } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -376,8 +377,8 @@ fn default_compare_cap() -> u32 { 64 } -fn default_enable_sysmon_for_shared_lib() -> bool { - false +fn default_enable_sysmon_for_target() -> bool { + true } fn default_save_option() -> SaveOption { @@ -464,7 +465,7 @@ impl Default for EbpfConfig { mem_dump_cap: default_mem_dump_cap(), compare_cap: default_compare_cap(), max_trace_event_size: default_max_trace_event_size(), - enable_sysmon_for_shared_lib: default_enable_sysmon_for_shared_lib(), + enable_sysmon_for_target: default_enable_sysmon_for_target(), } } } @@ -840,3 +841,26 @@ impl Config { Ok(config) } } + +#[cfg(test)] +mod tests { + use super::Config; + + #[test] + fn ebpf_defaults_enable_sysmon_for_target() { + assert!(Config::default().ebpf.enable_sysmon_for_target); + } + + #[test] + fn ebpf_rejects_legacy_shared_lib_sysmon_key() { + let error = toml::from_str::( + r#" + [ebpf] + enable_sysmon_for_shared_lib = false + "#, + ) + .expect_err("legacy sysmon config key should be retired"); + + assert!(error.to_string().contains("enable_sysmon_for_shared_lib")); + } +} diff --git a/ghostscope/src/config/user.rs b/ghostscope/src/config/user.rs index 21f157a..2d64044 100644 --- a/ghostscope/src/config/user.rs +++ b/ghostscope/src/config/user.rs @@ -193,8 +193,8 @@ impl UserConfig { if args.force_perf_event_array { ebpf_config.force_perf_event_array = true; } - if args.enable_sysmon_for_shared_lib { - ebpf_config.enable_sysmon_for_shared_lib = true; + if args.enable_sysmon_for_target { + ebpf_config.enable_sysmon_for_target = true; } ebpf_config }, diff --git a/ghostscope/src/core/session.rs b/ghostscope/src/core/session.rs index 49120b0..ddcc23f 100644 --- a/ghostscope/src/core/session.rs +++ b/ghostscope/src/core/session.rs @@ -112,18 +112,11 @@ impl GhostSession { } } - // Start sysmon: - // -t executable: always start (PID collection is constrained in eBPF) - // -t shared library: start only if enabled in config + // Start sysmon for standalone -t only. Combined -t -p uses the PID for + // concrete process mappings and does not need system-wide lifecycle tracking. if s.proc_pid().is_none() && s.target_binary.is_some() { let tpath = PathBuf::from(s.target_binary.as_ref().unwrap()); - let is_shared = ghostscope_process::is_shared_object(&tpath); - let should_start = if is_shared { - config.ebpf_config.enable_sysmon_for_shared_lib - } else { - true - }; - if should_start { + if config.ebpf_config.enable_sysmon_for_target { let cfg = SysmonConfig { target_module: Some(tpath.clone()), proc_offsets_max_entries: config.ebpf_config.proc_module_offsets_max_entries @@ -134,13 +127,14 @@ impl GhostSession { let mut sysmon = ProcessSysmon::new(mgr, cfg); sysmon.start(); s.sysmon = Some(Arc::new(Mutex::new(sysmon))); + let is_shared = ghostscope_process::is_shared_object(&tpath); if is_shared { info!("Sysmon started (-t shared library)"); } else { info!("Sysmon started (-t executable)"); } } else { - info!("Sysmon not started (-t shared library disabled by config)"); + info!("Sysmon not started (-t disabled by config)"); } } else if s.proc_pid().is_some() && s.target_binary.is_some() { info!("Sysmon not started (-t target scoped by -p)"); @@ -465,7 +459,7 @@ mod tests { should_save_ast: false, layout_mode: crate::config::LayoutMode::Horizontal, force_perf_event_array: false, - enable_sysmon_for_shared_lib: false, + enable_sysmon_for_target: false, allow_loose_debug_match: false, debuginfod: None, debuginfod_urls: Vec::new(),