Skip to content

Commit 048e182

Browse files
committed
refactor: share DWARF analyzer queries
Move compiler and query entry points to shared DwarfAnalyzer borrows. Guard lazy block-index population with an RwLock so read-only query paths can build and reuse cached function ranges without mutable access.
1 parent 40655dc commit 048e182

17 files changed

Lines changed: 163 additions & 105 deletions

bins/dwarf-tool/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ async fn run_source_line_benchmark(
10611061
let (file_path, line_number) = parse_source_line(source)?;
10621062

10631063
let load_start = Instant::now();
1064-
let (mut analyzer, load_breakdown) = load_analyzer_with_breakdown(pid, target_path).await?;
1064+
let (analyzer, load_breakdown) = load_analyzer_with_breakdown(pid, target_path).await?;
10651065
let loading_time = load_start.elapsed();
10661066

10671067
let mut query_times = Vec::with_capacity(runs);

e2e-tests/tests/cpp_script_execution.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ async fn compile_cpp_complex_script(
1010
script: &str,
1111
) -> anyhow::Result<ghostscope_compiler::CompilationResult> {
1212
let binary_path = FIXTURES.get_test_binary("cpp_complex_program")?;
13-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
13+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
1414
.await
1515
.map_err(|e| anyhow::anyhow!("failed to load DWARF for cpp_complex_program: {e}"))?;
1616
let compile_options = ghostscope_compiler::CompileOptions {
1717
binary_path_hint: Some(binary_path.to_string_lossy().into_owned()),
1818
..Default::default()
1919
};
2020

21-
ghostscope_compiler::compile_script(script, &mut analyzer, None, Some(1), &compile_options)
21+
ghostscope_compiler::compile_script(script, &analyzer, None, Some(1), &compile_options)
2222
.map_err(|e| anyhow::anyhow!("compile_script failed: {e}"))
2323
}
2424

e2e-tests/tests/dwarf_index_regressions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ async fn assert_partitioned_ranges_source_line_query_recovers_function_scope(
276276
binary_path: PathBuf,
277277
scenario: &str,
278278
) -> anyhow::Result<()> {
279-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
279+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
280280
let query_results = analyzer
281281
.query_source_line_best_effort("partitioned_ranges_program.c", 18)
282282
.map_err(|e| anyhow::anyhow!("Failed source-line query for {scenario}: {e}"))?;
@@ -614,7 +614,7 @@ async fn test_inline_callsite_clang_dwarf5_resolves_debug_addr_entry_pc() -> any
614614
);
615615
let target = spawn_inline_callsite_program(binary_path).await?;
616616
let query_result: anyhow::Result<()> = async {
617-
let mut pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
617+
let pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
618618
let query_results =
619619
pid_analyzer.query_source_line_best_effort("inline_callsite_program.c", INLINE_TRACE_LINE)?;
620620
anyhow::ensure!(

e2e-tests/tests/member_pointer_compilation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ async fn compile_member_pointer_script(
99
opt_level: OptimizationLevel,
1010
) -> anyhow::Result<ghostscope_compiler::CompilationResult> {
1111
let binary_path = FIXTURES.get_test_binary_with_opt("member_pointer_program", opt_level)?;
12-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
12+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
1313
.await
1414
.map_err(|e| anyhow::anyhow!("failed to load DWARF for member_pointer_program: {e}"))?;
1515
let compile_options = ghostscope_compiler::CompileOptions {
1616
binary_path_hint: Some(binary_path.to_string_lossy().into_owned()),
1717
..Default::default()
1818
};
1919

20-
ghostscope_compiler::compile_script(script, &mut analyzer, None, Some(1), &compile_options)
20+
ghostscope_compiler::compile_script(script, &analyzer, None, Some(1), &compile_options)
2121
.map_err(|e| anyhow::anyhow!("compile_script failed: {e}"))
2222
}
2323

@@ -27,7 +27,7 @@ async fn test_member_pointer_planner_resolves_o2_chain_accesses() -> anyhow::Res
2727

2828
let binary_path =
2929
FIXTURES.get_test_binary_with_opt("member_pointer_program", OptimizationLevel::O2)?;
30-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
30+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
3131
.await
3232
.map_err(|e| anyhow::anyhow!("failed to load DWARF for member_pointer_program: {e}"))?;
3333
let addrs = analyzer.lookup_addresses_by_source_line("member_pointer_program.c", TRACE_LINE);
@@ -201,7 +201,7 @@ async fn test_complex_bitfield_chain_planner_resolves_member_offsets() -> anyhow
201201

202202
let binary_path =
203203
FIXTURES.get_test_binary_with_opt("complex_types_program", OptimizationLevel::Debug)?;
204-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
204+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
205205
.await
206206
.map_err(|e| anyhow::anyhow!("failed to load DWARF for complex_types_program: {e}"))?;
207207
let addrs = analyzer.lookup_addresses_by_source_line("complex_types_program.c", 15);

e2e-tests/tests/optimized_inline_call_value_execution.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async fn test_optimized_inline_parameters_are_live_before_internal_call() -> any
104104
init();
105105

106106
let binary_path = FIXTURES.get_test_binary("inline_call_value_program")?;
107-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
107+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
108108
let addrs = analyzer.lookup_addresses_by_source_line(
109109
"inline_call_value_program.c",
110110
INLINE_BEFORE_CALL_TRACE_LINE,
@@ -134,7 +134,7 @@ async fn test_optimized_inline_parameters_are_live_before_internal_call() -> any
134134
}
135135

136136
let target = spawn_inline_call_value_program(&binary_path).await?;
137-
let mut pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
137+
let pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
138138
let pid_results = pid_analyzer.query_source_line_best_effort(
139139
"inline_call_value_program.c",
140140
INLINE_BEFORE_CALL_TRACE_LINE,
@@ -157,7 +157,7 @@ async fn test_optimized_inline_parameters_have_exact_values_before_internal_call
157157
init();
158158

159159
let binary_path = FIXTURES.get_test_binary("inline_call_value_program")?;
160-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
160+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
161161
let addrs = analyzer.lookup_addresses_by_source_line(
162162
"inline_call_value_program.c",
163163
INLINE_BEFORE_CALL_TRACE_LINE,
@@ -221,7 +221,7 @@ async fn test_optimized_inline_parameters_survive_internal_call_sites() -> anyho
221221
init();
222222

223223
let binary_path = FIXTURES.get_test_binary("inline_call_value_program")?;
224-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
224+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
225225
let addrs = analyzer.lookup_addresses_by_source_line(
226226
"inline_call_value_program.c",
227227
INLINE_AFTER_CALL_TRACE_LINE,
@@ -250,7 +250,7 @@ async fn test_optimized_inline_parameters_survive_internal_call_sites() -> anyho
250250
}
251251

252252
let target = spawn_inline_call_value_program(&binary_path).await?;
253-
let mut pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
253+
let pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
254254
let pid_results = pid_analyzer.query_source_line_best_effort(
255255
"inline_call_value_program.c",
256256
INLINE_AFTER_CALL_TRACE_LINE,
@@ -274,7 +274,7 @@ async fn test_entry_value_recovers_outer_parameter_inside_optimized_inline_after
274274
init();
275275

276276
let binary_path = FIXTURES.get_test_binary("inline_call_value_program")?;
277-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
277+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path).await?;
278278
let addrs = analyzer.lookup_addresses_by_source_line(
279279
"inline_call_value_program.c",
280280
INLINE_AFTER_CALL_TRACE_LINE,

e2e-tests/tests/optimized_inline_execution.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ async fn test_optimized_inline_struct_member_access_resolves_inline_parameter_na
160160
init();
161161

162162
let binary_path = FIXTURES.get_test_binary("inline_callsite_program")?;
163-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
163+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
164164
.await
165165
.map_err(|e| anyhow::anyhow!("Failed to load DWARF for inline_callsite_program: {}", e))?;
166166
let addrs = analyzer
@@ -190,7 +190,7 @@ async fn test_optimized_inline_struct_member_access_resolves_inline_parameter_na
190190
// The analyzer runs in the host test process, so it must inspect the host PID.
191191
// `visible_pid_from(observer)` is only correct for processes that actually run
192192
// inside the observer sandbox, such as GhostScope itself.
193-
let mut pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
193+
let pid_analyzer = ghostscope_dwarf::DwarfAnalyzer::from_pid(target.host_pid()).await?;
194194
let pid_addrs = pid_analyzer
195195
.lookup_addresses_by_source_line("inline_callsite_program.c", INLINE_STATE_TRACE_LINE);
196196
anyhow::ensure!(

e2e-tests/tests/script_execution.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ async fn test_capture_len_uses_scalar_script_var_from_dwarf_expr() -> anyhow::Re
420420
init();
421421

422422
let binary_path = FIXTURES.get_test_binary("sample_program")?;
423-
let mut analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
423+
let analyzer = ghostscope_dwarf::DwarfAnalyzer::from_exec_path(&binary_path)
424424
.await
425425
.map_err(|e| anyhow::anyhow!("failed to load DWARF for sample_program: {e}"))?;
426426
let script_content = r#"
@@ -436,7 +436,7 @@ trace sample_lib.c:45 {
436436
};
437437
let result = ghostscope_compiler::compile_script(
438438
script_content,
439-
&mut analyzer,
439+
&analyzer,
440440
None,
441441
Some(1),
442442
&compile_options,

ghostscope-compiler/src/ebpf/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub struct EbpfContext<'ctx, 'dw> {
8080
pub optimized_out_vars: HashMap<String, bool>, // Optimized out variables
8181
pub var_pc_addresses: HashMap<String, u64>, // Variable -> PC address
8282
pub variable_context: Option<VariableContext>, // Scope validation context
83-
pub process_analyzer: Option<&'dw mut DwarfAnalyzer>, // Multi-module DWARF analyzer
83+
pub(super) process_analyzer: Option<&'dw DwarfAnalyzer>, // Multi-module DWARF analyzer
8484
pub current_trace_id: Option<u32>, // Current trace_id being compiled
8585
pub current_compile_time_context: Option<CompileTimeContext>, // PC address and module for DWARF queries
8686

@@ -287,7 +287,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
287287
pub fn new_with_process_analyzer(
288288
context: &'ctx Context,
289289
module_name: &str,
290-
process_analyzer: Option<&'dw mut DwarfAnalyzer>,
290+
process_analyzer: Option<&'dw DwarfAnalyzer>,
291291
trace_id: Option<u32>,
292292
compile_options: &crate::CompileOptions,
293293
) -> Result<Self> {

ghostscope-compiler/src/ebpf/dwarf_bridge.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
2020

2121
/// Compute section code for an address within a module (text=0, rodata=1, data=2, bss=3).
2222
fn section_code_for_address(&mut self, module_path: &str, link_addr: u64) -> u8 {
23-
if let Some(analyzer) = self.process_analyzer.as_deref_mut() {
23+
if let Some(analyzer) = self.process_analyzer {
2424
if let Some(st) = analyzer.classify_section_for_address(module_path, link_addr) {
2525
return match st {
2626
ghostscope_dwarf::core::SectionType::Text => 0,
@@ -1320,7 +1320,6 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
13201320

13211321
let analyzer = self
13221322
.process_analyzer
1323-
.as_deref_mut()
13241323
.ok_or_else(|| CodeGenError::DwarfError("No DWARF analyzer available".to_string()))?;
13251324

13261325
let module_address = ghostscope_dwarf::ModuleAddress::new(
@@ -1329,7 +1328,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
13291328
);
13301329

13311330
let module_path_owned = module_path;
1332-
let lookup_globals = |analyzer: &mut ghostscope_dwarf::DwarfAnalyzer| -> Result<
1331+
let lookup_globals = |analyzer: &ghostscope_dwarf::DwarfAnalyzer| -> Result<
13331332
Option<(std::path::PathBuf, VariableWithEvaluation)>,
13341333
> {
13351334
debug!(
@@ -1647,7 +1646,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
16471646
let ctx = self.get_compile_time_context()?;
16481647
let module_path = ctx.module_path.clone();
16491648
let pc_address = ctx.pc_address;
1650-
let analyzer = self.process_analyzer.as_deref_mut().ok_or_else(|| {
1649+
let analyzer = self.process_analyzer.ok_or_else(|| {
16511650
CodeGenError::DwarfError("No DWARF analyzer available".to_string())
16521651
})?;
16531652
let module_address = ghostscope_dwarf::ModuleAddress::new(
@@ -1801,7 +1800,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
18011800
let ctx = self.get_compile_time_context()?;
18021801
let module_path = ctx.module_path.clone();
18031802
let pc_address = ctx.pc_address;
1804-
let analyzer = self.process_analyzer.as_deref_mut().ok_or_else(|| {
1803+
let analyzer = self.process_analyzer.ok_or_else(|| {
18051804
CodeGenError::DwarfError("No DWARF analyzer available".to_string())
18061805
})?;
18071806
let module_address = ghostscope_dwarf::ModuleAddress::new(
@@ -1927,7 +1926,6 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
19271926
let pc_address = ctx.pc_address;
19281927
let analyzer = self
19291928
.process_analyzer
1930-
.as_deref_mut()
19311929
.ok_or_else(|| CodeGenError::DwarfError("No DWARF analyzer available".to_string()))?;
19321930
// First attempt: current module at current PC (locals/params)
19331931
let module_address = ghostscope_dwarf::ModuleAddress::new(
@@ -2095,7 +2093,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
20952093
}
20962094
let ctx = self.get_compile_time_context()?;
20972095
let module_path = ctx.module_path.clone();
2098-
if let Some(analyzer) = self.process_analyzer.as_deref_mut() {
2096+
if let Some(analyzer) = self.process_analyzer {
20992097
let mut alias_used: Option<String> = None;
21002098
for n in candidate_names {
21012099
// Prefer cross-module definitions first to avoid forward decls with size=0 in current CU

ghostscope-compiler/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ impl Default for CompileOptions {
123123
/// to perform compilation across main executable and dynamic libraries
124124
pub fn compile_script(
125125
script_source: &str,
126-
process_analyzer: &mut ghostscope_dwarf::DwarfAnalyzer,
126+
process_analyzer: &ghostscope_dwarf::DwarfAnalyzer,
127127
pid: Option<u32>,
128128
trace_id: Option<u32>,
129129
compile_options: &CompileOptions,

0 commit comments

Comments
 (0)