Skip to content

Commit f9ec0b1

Browse files
committed
feat: add configurable search paths for .gnu_debuglink files
1 parent 1256238 commit f9ec0b1

15 files changed

Lines changed: 526 additions & 111 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config-zh.toml

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,35 @@ enable_logging = true
3333
log_level = "trace"
3434

3535
[dwarf]
36-
# DWARF 调试信息搜索路径(用于未来的 --debug-file 自动发现功能)
37-
# 目前未实现,为未来使用保留
36+
# DWARF 调试信息搜索路径(用于 .gnu_debuglink 文件)
37+
#
38+
# 当二进制文件使用 .gnu_debuglink 引用独立的调试文件时,
39+
# GhostScope 会在这些路径中搜索调试文件。
40+
#
41+
# 搜索顺序(优先级从高到低):
42+
# 1. 绝对路径(如果 .gnu_debuglink 包含绝对路径 - 罕见)
43+
# 2. 用户配置的 search_paths + basename(此处配置)
44+
# 3. 二进制文件所在目录 + basename
45+
# 4. 二进制文件所在目录的 .debug 子目录 + basename
46+
#
47+
# 对于每个用户配置的路径,会检查两种位置:
48+
# - <路径>/debug_文件名
49+
# - <路径>/.debug/debug_文件名
50+
#
51+
# 特性:
52+
# - 主目录展开:"~/" 会被替换为你的主目录
53+
# - 自动去除重复路径以避免冗余检查
54+
# - 按顺序尝试路径,直到找到匹配的调试文件
55+
#
56+
# 常用搜索路径:
57+
# - 系统调试符号:"/usr/lib/debug"(用于已安装的调试包)
58+
# - 本地调试符号:"/usr/local/lib/debug"
59+
# - 用户特定: "~/.local/lib/debug"
60+
# - 自定义构建输出:"/path/to/build/debug"
61+
#
62+
# 注意:.gnu_debuglink 通常使用 basename(相对路径),但也支持绝对路径。
63+
# 如需使用系统范围的调试目录(如 /usr/lib/debug),请添加到 search_paths。
64+
#
3865
# 默认值:["/usr/lib/debug", "/usr/local/lib/debug"]
3966
search_paths = [
4067
"/usr/lib/debug",
@@ -96,3 +123,86 @@ output_dir = "."
96123
# 自动生成的实时日志文件的默认文件名前缀
97124
# 默认值:"ghostscope_session"
98125
filename_prefix = "ghostscope_session"
126+
127+
[ebpf]
128+
# RingBuf 映射大小(字节,必须是 2 的幂)
129+
# 控制用于从内核向用户空间传输跟踪事件的环形缓冲区大小。
130+
# 较大的尺寸允许缓冲更多事件,但会消耗更多内核内存。
131+
# 有效范围:4096 (4KB) 到 16777216 (16MB)
132+
# 推荐值:
133+
# - 低频追踪:131072 (128KB)
134+
# - 中频追踪:262144 (256KB)
135+
# - 高频追踪:524288 (512KB) 或 1048576 (1MB)
136+
# 默认值:262144 (256KB)
137+
ringbuf_size = 262144
138+
139+
# ASLR 地址转换的最大 (pid, module) 偏移条目数
140+
# 此映射存储每个进程中每个已加载模块的运行时地址偏移。
141+
# 每个条目存储 text/rodata/data/bss 段的偏移量。
142+
# 有效范围:64 到 65536
143+
# 推荐值:
144+
# - 单进程:1024
145+
# - 多进程:4096
146+
# - 系统范围追踪:8192 或 16384
147+
# 默认值:4096
148+
proc_module_offsets_max_entries = 4096
149+
150+
# PerfEventArray 页数(每个 CPU 的 perf 缓冲区页数)
151+
# 仅在选择 PerfEventArray 时使用(内核 < 5.8 或 force_perf_event_array=true 时)
152+
# 必须是 2 的幂。大多数系统上每页为 4KB。
153+
# 有效范围:1 到 512 页
154+
# 推荐值:
155+
# - 低频追踪:8 页 (每 CPU 32KB)
156+
# - 中频追踪:32 页 (每 CPU 128KB)
157+
# - 高频追踪:64 页 (每 CPU 256KB)
158+
# 默认值:32 (每 CPU 128KB)
159+
perf_page_count = 32
160+
161+
# 强制使用 PerfEventArray 而不是 RingBuf(仅用于测试)
162+
# 警告:仅用于测试目的。正常情况下系统会自动检测内核能力,
163+
# 并使用 RingBuf(内核 >= 5.8)或回退到 PerfEventArray。
164+
# 设置为 true 可在支持 RingBuf 的内核上强制使用 PerfEventArray。
165+
# 默认值:false
166+
force_perf_event_array = false
167+
168+
# 源代码路径配置
169+
# 当 DWARF 调试信息中包含的编译时路径与运行时路径不同时,
170+
# 使用这些设置帮助 ghostscope 定位实际的源文件。
171+
172+
[source]
173+
# 路径替换规则(首先应用,优先级最高)
174+
# 将编译时路径前缀替换为运行时路径前缀。
175+
# 适用于源代码在不同机器上编译或移动到新位置的情况。
176+
#
177+
# 使用场景示例:
178+
# - 在 CI 服务器上编译:/home/build/project -> /home/user/work/project
179+
# - 内核源码移动:/usr/src/linux-5.15 -> /home/user/kernel/linux-5.15
180+
# - 交叉编译:/buildroot/arm/src -> /local/embedded/src
181+
#
182+
# 格式:数组,包含 { from = "编译路径前缀", to = "运行时路径前缀" }
183+
substitutions = [
184+
# { from = "/home/build/myproject", to = "/home/user/work/myproject" },
185+
# { from = "/usr/src/linux", to = "/home/user/kernel/linux" },
186+
]
187+
188+
# 附加搜索目录(替换失败时的回退方案)
189+
# 当通过替换无法找到源文件时,ghostscope 将在这些目录中
190+
# 按文件名(basename 匹配)进行搜索。
191+
# 类似于 GDB 的 "directory" 命令。
192+
#
193+
# 格式:目录路径数组
194+
search_dirs = [
195+
# "/home/user/sources",
196+
# "/opt/local/src",
197+
]
198+
199+
# 运行时配置:
200+
# 你也可以使用 'srcpath' 命令交互式配置源路径:
201+
# srcpath - 显示当前配置
202+
# srcpath map <from> <to> - 添加路径替换规则
203+
# srcpath add <directory> - 添加搜索目录
204+
# srcpath remove <path> - 移除规则
205+
# srcpath clear - 清除所有运行时规则
206+
# srcpath reset - 重置为配置文件规则
207+
#
208+
# 运行时规则优先于配置文件规则,且不会持久化保存。

config.toml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,36 @@ enable_logging = true
3333
log_level = "trace"
3434

3535
[dwarf]
36-
# DWARF debug information search paths (for future --debug-file auto-discovery)
37-
# Currently not implemented, reserved for future use
36+
# DWARF debug information search paths for .gnu_debuglink files
37+
#
38+
# When a binary uses .gnu_debuglink to reference separate debug files,
39+
# GhostScope searches these paths to locate the debug file.
40+
#
41+
# Search order (highest priority first):
42+
# 1. Absolute path (if .gnu_debuglink contains an absolute path - rare)
43+
# 2. User-configured search_paths + basename (configured here)
44+
# 3. Same directory as the binary + basename
45+
# 4. .debug subdirectory next to the binary + basename
46+
#
47+
# For each user-configured path, both direct and .debug subdirectory are checked:
48+
# - <path>/debug_filename
49+
# - <path>/.debug/debug_filename
50+
#
51+
# Features:
52+
# - Home directory expansion: "~/" is replaced with your home directory
53+
# - Duplicate paths are automatically removed to avoid redundant checks
54+
# - Paths are tried in order until a matching debug file is found
55+
#
56+
# Common search paths:
57+
# - System debug symbols: "/usr/lib/debug" (for installed debug packages)
58+
# - Local debug symbols: "/usr/local/lib/debug"
59+
# - User-specific: "~/.local/lib/debug"
60+
# - Custom build output: "/path/to/build/debug"
61+
#
62+
# Note: .gnu_debuglink typically uses basename (relative path), but absolute paths
63+
# are also supported. If you need system-wide debug directories like /usr/lib/debug,
64+
# add them to search_paths.
65+
#
3866
# Default: ["/usr/lib/debug", "/usr/local/lib/debug"]
3967
search_paths = [
4068
"/usr/lib/debug",

docs/configuration.md

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,18 @@ ghostscope --debug-file /path/to/binary.debug
5959

6060
# Auto-detection searches in order:
6161
# 1. Binary itself (.debug_info sections)
62-
# 2. .gnu_debuglink section
62+
# 2. .gnu_debuglink section (see search paths below)
6363
# 3. .gnu_debugdata section (Android/compressed)
64-
# 4. /usr/lib/debug, /usr/local/lib/debug
65-
# 5. Build-ID based paths
66-
# 6. binary.debug, binary.dbg
64+
# 4. Build-ID based paths
65+
66+
# .gnu_debuglink search paths (configurable in config.toml):
67+
# 1. Absolute path (if .gnu_debuglink contains absolute path - rare)
68+
# 2. User-configured search_paths + basename (highest priority)
69+
# 3. Same directory as the binary + basename
70+
# 4. .debug subdirectory next to the binary + basename
71+
#
72+
# Note: To use system-wide debug directories like /usr/lib/debug,
73+
# add them to search_paths in config.toml
6774
```
6875

6976
### Logging Configuration
@@ -176,10 +183,35 @@ enable_console_logging = false
176183
log_level = "warn"
177184

178185
[dwarf]
179-
# Debug information search paths
186+
# Debug information search paths for .gnu_debuglink files
187+
# When a binary uses .gnu_debuglink to reference separate debug files,
188+
# GhostScope searches these paths to locate the debug file.
189+
#
190+
# Search order (highest priority first):
191+
# 1. Absolute path (if .gnu_debuglink contains an absolute path - rare)
192+
# 2. User-configured search_paths + basename (configured here)
193+
# 3. Same directory as the binary + basename
194+
# 4. .debug subdirectory next to the binary + basename
195+
#
196+
# For each user-configured path, both direct and .debug subdirectory are checked:
197+
# - <path>/debug_filename
198+
# - <path>/.debug/debug_filename
199+
#
200+
# Features:
201+
# - Home directory expansion: "~/" is replaced with your home directory
202+
# - Duplicate paths are automatically removed to avoid redundant checks
203+
# - Paths are tried in order until a matching debug file is found
204+
#
205+
# Note: .gnu_debuglink typically uses basename (relative path), but absolute paths
206+
# are also supported. If you need system-wide debug directories like /usr/lib/debug,
207+
# add them to search_paths.
208+
#
209+
# Examples:
180210
search_paths = [
181-
"/usr/lib/debug",
182-
"/usr/local/lib/debug"
211+
"/usr/lib/debug", # System debug symbols (for installed packages)
212+
"/usr/local/lib/debug", # Local debug symbols
213+
"~/.local/lib/debug", # User debug symbols (~ expands to home)
214+
"/opt/debug-symbols" # Custom debug symbol server
183215
]
184216

185217
[files]

docs/install.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ GhostScope automatically searches for debug files in the following locations:
134134
2. `.debug` subdirectory: `/path/to/.debug/your_program.debug`
135135
3. Global debug directory: `/usr/lib/debug/path/to/your_program.debug`
136136

137+
> **📝 Custom Search Paths**: You can configure additional search paths (including user-specific directories like `~/.local/lib/debug`) in the configuration file. See the [Configuration Reference - DWARF Debug Search Paths](configuration.md#dwarf) for detailed information.
138+
137139
**Installing system debug packages:**
138140
```bash
139141
# Ubuntu/Debian - install debug symbols for libc

docs/zh/configuration.md

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,18 @@ ghostscope --debug-file /path/to/binary.debug
5959

6060
# 自动检测按以下顺序搜索:
6161
# 1. 二进制文件本身(.debug_info 节)
62-
# 2. .gnu_debuglink 节
62+
# 2. .gnu_debuglink 节(参见下方搜索路径)
6363
# 3. .gnu_debugdata 节(Android/压缩格式)
64-
# 4. /usr/lib/debug, /usr/local/lib/debug
65-
# 5. 基于 Build-ID 的路径
66-
# 6. binary.debug, binary.dbg
64+
# 4. 基于 Build-ID 的路径
65+
66+
# .gnu_debuglink 搜索路径(可在 config.toml 中配置):
67+
# 1. 绝对路径(如果 .gnu_debuglink 包含绝对路径 - 罕见)
68+
# 2. 用户配置的 search_paths + basename(最高优先级)
69+
# 3. 二进制文件同目录 + basename
70+
# 4. 二进制文件同目录的 .debug 子目录 + basename
71+
#
72+
# 注意:如需使用系统范围的调试目录(如 /usr/lib/debug),
73+
# 请在 config.toml 的 search_paths 中添加
6774
```
6875

6976
### 日志配置
@@ -176,10 +183,34 @@ enable_console_logging = false
176183
log_level = "warn"
177184

178185
[dwarf]
179-
# 调试信息搜索路径
186+
# DWARF 调试信息搜索路径(用于 .gnu_debuglink 文件)
187+
# 当二进制文件使用 .gnu_debuglink 引用独立的调试文件时,
188+
# GhostScope 会在这些路径中搜索调试文件。
189+
#
190+
# 搜索顺序(优先级从高到低):
191+
# 1. 绝对路径(如果 .gnu_debuglink 包含绝对路径 - 罕见)
192+
# 2. 用户配置的 search_paths + basename(此处配置)
193+
# 3. 二进制文件所在目录 + basename
194+
# 4. 二进制文件所在目录的 .debug 子目录 + basename
195+
#
196+
# 对于每个用户配置的路径,会检查两种位置:
197+
# - <路径>/debug_文件名
198+
# - <路径>/.debug/debug_文件名
199+
#
200+
# 特性:
201+
# - 主目录展开:"~/" 会被替换为你的主目录
202+
# - 自动去除重复路径以避免冗余检查
203+
# - 按顺序尝试路径,直到找到匹配的调试文件
204+
#
205+
# 注意:.gnu_debuglink 通常使用 basename(相对路径),但也支持绝对路径。
206+
# 如需使用系统范围的调试目录(如 /usr/lib/debug),请添加到 search_paths。
207+
#
208+
# 示例:
180209
search_paths = [
181-
"/usr/lib/debug",
182-
"/usr/local/lib/debug"
210+
"/usr/lib/debug", # 系统调试符号(用于已安装的软件包)
211+
"/usr/local/lib/debug", # 本地调试符号
212+
"~/.local/lib/debug", # 用户调试符号(~ 会展开为主目录)
213+
"/opt/debug-symbols" # 自定义调试符号服务器
183214
]
184215

185216
[files]

docs/zh/install.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ GhostScope 会自动在以下位置搜索调试文件:
134134
2. `.debug` 子目录:`/path/to/.debug/your_program.debug`
135135
3. 全局调试目录:`/usr/lib/debug/path/to/your_program.debug`
136136

137+
> **📝 自定义搜索路径**:你可以在配置文件中配置额外的搜索路径(包括用户特定目录如 `~/.local/lib/debug`)。详细信息请参阅 [配置参考 - DWARF 调试搜索路径](configuration.md#dwarf)
138+
137139
**安装系统调试包:**
138140
```bash
139141
# Ubuntu/Debian - 安装 libc 的调试符号

ghostscope-dwarf/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ libc = "0.2"
2727
# For .gnu_debuglink CRC validation
2828
crc32fast = "1.4"
2929

30+
# For home directory expansion in debug search paths
31+
dirs = "5.0"
32+

ghostscope-dwarf/src/analyzer.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,23 @@ impl DwarfAnalyzer {
135135

136136
/// Create DWARF analyzer from PID using parallel loading
137137
pub async fn from_pid_parallel(pid: u32) -> Result<Self> {
138-
Self::from_pid_parallel_with_progress(pid, |_event| {}).await
138+
Self::from_pid_parallel_with_config(pid, &[], |_event| {}).await
139139
}
140140

141141
/// Create DWARF analyzer from PID using parallel loading with progress callback
142142
pub async fn from_pid_parallel_with_progress<F>(pid: u32, progress_callback: F) -> Result<Self>
143+
where
144+
F: Fn(ModuleLoadingEvent) + Send + Sync + 'static,
145+
{
146+
Self::from_pid_parallel_with_config(pid, &[], progress_callback).await
147+
}
148+
149+
/// Create DWARF analyzer from PID using parallel loading with debug search paths and progress callback
150+
pub async fn from_pid_parallel_with_config<F>(
151+
pid: u32,
152+
debug_search_paths: &[String],
153+
progress_callback: F,
154+
) -> Result<Self>
143155
where
144156
F: Fn(ModuleLoadingEvent) + Send + Sync + 'static,
145157
{
@@ -164,8 +176,14 @@ impl DwarfAnalyzer {
164176
}
165177

166178
// Load all modules in parallel with progress tracking
167-
let modules = crate::loader::ModuleLoader::new(module_mappings)
168-
.parallel()
179+
let mut loader = crate::loader::ModuleLoader::new(module_mappings).parallel();
180+
181+
// Configure debug search paths if provided
182+
if !debug_search_paths.is_empty() {
183+
loader = loader.with_debug_search_paths(debug_search_paths.to_vec());
184+
}
185+
186+
let modules = loader
169187
.with_progress_callback(progress_callback)
170188
.load()
171189
.await?;
@@ -181,6 +199,14 @@ impl DwarfAnalyzer {
181199

182200
/// Create DWARF analyzer from executable path (single module mode, now async parallel)
183201
pub async fn from_exec_path<P: AsRef<std::path::Path>>(exec_path: P) -> Result<Self> {
202+
Self::from_exec_path_with_config(exec_path, &[]).await
203+
}
204+
205+
/// Create DWARF analyzer from executable path with debug search paths
206+
pub async fn from_exec_path_with_config<P: AsRef<std::path::Path>>(
207+
exec_path: P,
208+
debug_search_paths: &[String],
209+
) -> Result<Self> {
184210
let exec_path = exec_path.as_ref().to_path_buf();
185211
tracing::info!(
186212
"Creating DWARF analyzer for executable: {}",
@@ -201,7 +227,7 @@ impl DwarfAnalyzer {
201227
};
202228

203229
// Load the single module using parallel loading
204-
match ModuleData::load_parallel(module_mapping).await {
230+
match ModuleData::load_parallel(module_mapping, debug_search_paths).await {
205231
Ok(module_data) => {
206232
analyzer.modules.insert(exec_path.clone(), module_data);
207233
tracing::info!(

0 commit comments

Comments
 (0)