Skip to content

Commit cc35896

Browse files
committed
refactor: remove DWARF analyzer raw pointer
Store the analyzer as a scoped mutable reference instead of a raw pointer. Move bytecode emission out of the active analyzer borrow so compiler DWARF queries stay borrow-checked.
1 parent ae30603 commit cc35896

8 files changed

Lines changed: 115 additions & 93 deletions

File tree

ghostscope-compiler/src/ebpf/codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ fn allocate_dynamic_payload_reservations(max_lens: &[usize], available: usize) -
154154
reservations
155155
}
156156

157-
impl<'ctx> EbpfContext<'ctx> {
157+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
158158
const UNKNOWN_CHAR_ARRAY_READ_FALLBACK: usize = 256;
159159

160160
fn build_errno_i32(&self, ret: IntValue<'ctx>, name: &str) -> Result<IntValue<'ctx>> {

ghostscope-compiler/src/ebpf/context.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub enum CodeGenError {
5656
pub type Result<T> = std::result::Result<T, CodeGenError>;
5757

5858
/// eBPF LLVM code generation context
59-
pub struct EbpfContext<'ctx> {
59+
pub struct EbpfContext<'ctx, 'dw> {
6060
pub context: &'ctx Context,
6161
pub module: Module<'ctx>,
6262
pub builder: Builder<'ctx>,
@@ -80,7 +80,7 @@ pub struct EbpfContext<'ctx> {
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<*mut DwarfAnalyzer>, // Multi-module DWARF analyzer
83+
pub process_analyzer: Option<&'dw mut 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

@@ -122,9 +122,9 @@ pub struct EbpfContext<'ctx> {
122122
}
123123

124124
// Temporary alias for backward compatibility during refactoring
125-
pub type NewCodeGen<'ctx> = EbpfContext<'ctx>;
125+
pub type NewCodeGen<'ctx, 'dw> = EbpfContext<'ctx, 'dw>;
126126

127-
impl<'ctx> EbpfContext<'ctx> {
127+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
128128
/// Create a new eBPF code generation context
129129
pub fn new(
130130
context: &'ctx Context,
@@ -287,12 +287,12 @@ impl<'ctx> EbpfContext<'ctx> {
287287
pub fn new_with_process_analyzer(
288288
context: &'ctx Context,
289289
module_name: &str,
290-
process_analyzer: Option<&mut DwarfAnalyzer>,
290+
process_analyzer: Option<&'dw mut DwarfAnalyzer>,
291291
trace_id: Option<u32>,
292292
compile_options: &crate::CompileOptions,
293293
) -> Result<Self> {
294294
let mut codegen = Self::new(context, module_name, trace_id, compile_options)?;
295-
codegen.process_analyzer = process_analyzer.map(|pa| pa as *const _ as *mut _);
295+
codegen.process_analyzer = process_analyzer;
296296
Ok(codegen)
297297
}
298298

ghostscope-compiler/src/ebpf/dwarf_bridge.rs

Lines changed: 44 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ use ghostscope_process::module_probe;
1212
use inkwell::values::{BasicValueEnum, IntValue, PointerValue};
1313
use tracing::{debug, warn};
1414

15-
impl<'ctx> EbpfContext<'ctx> {
15+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
1616
/// Compute a stable cookie for a module when per-PID offsets are unavailable (via coordinator).
1717
fn fallback_cookie_from_module_path(&self, module_path: &str) -> u64 {
1818
module_probe::cookie_for_path(module_path)
1919
}
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_ptr) = self.process_analyzer {
24-
let analyzer = unsafe { &mut *analyzer_ptr };
23+
if let Some(analyzer) = self.process_analyzer.as_deref_mut() {
2524
if let Some(st) = analyzer.classify_section_for_address(module_path, link_addr) {
2625
return match st {
2726
ghostscope_dwarf::core::SectionType::Text => 0,
@@ -1187,7 +1186,7 @@ impl<'ctx> EbpfContext<'ctx> {
11871186
// DWARF resolvers see the actual DWARF-based expression tree.
11881187
// Guard against self-referential or cyclic aliases.
11891188
fn expand_aliases(
1190-
ctx: &crate::ebpf::context::EbpfContext<'_>,
1189+
ctx: &crate::ebpf::context::EbpfContext<'_, '_>,
11911190
e: &crate::script::Expr,
11921191
visited: &mut std::collections::HashSet<String>,
11931192
depth: usize,
@@ -1310,30 +1309,26 @@ impl<'ctx> EbpfContext<'ctx> {
13101309
&mut self,
13111310
var_name: &str,
13121311
) -> Result<Option<VariableWithEvaluation>> {
1313-
if self.process_analyzer.is_none() {
1314-
return Err(CodeGenError::DwarfError(
1315-
"No DWARF analyzer available".to_string(),
1316-
));
1317-
}
1318-
13191312
let context = self.get_compile_time_context()?;
13201313
let pc_address = context.pc_address;
1321-
let module_path = &context.module_path;
1314+
let module_path = context.module_path.clone();
13221315

13231316
debug!(
13241317
"Querying DWARF for variable '{}' at PC 0x{:x} in module '{}'",
13251318
var_name, pc_address, module_path
13261319
);
13271320

1328-
// Query DWARF analyzer for variable
1329-
let analyzer = unsafe { &mut *(self.process_analyzer.unwrap()) };
1321+
let analyzer = self
1322+
.process_analyzer
1323+
.as_deref_mut()
1324+
.ok_or_else(|| CodeGenError::DwarfError("No DWARF analyzer available".to_string()))?;
13301325

13311326
let module_address = ghostscope_dwarf::ModuleAddress::new(
13321327
std::path::PathBuf::from(module_path.clone()),
13331328
pc_address,
13341329
);
13351330

1336-
let module_path_owned = module_path.clone();
1331+
let module_path_owned = module_path;
13371332
let lookup_globals = |analyzer: &mut ghostscope_dwarf::DwarfAnalyzer| -> Result<
13381333
Option<(std::path::PathBuf, VariableWithEvaluation)>,
13391334
> {
@@ -1649,16 +1644,15 @@ impl<'ctx> EbpfContext<'ctx> {
16491644
}
16501645
// Support simple variable base and fall back to global/static lowering
16511646
if let crate::script::Expr::Variable(base_name) = obj_expr {
1652-
let Some(analyzer_ptr) = self.process_analyzer else {
1653-
return Err(CodeGenError::DwarfError(
1654-
"No DWARF analyzer available".to_string(),
1655-
));
1656-
};
1657-
let analyzer = unsafe { &mut *analyzer_ptr };
16581647
let ctx = self.get_compile_time_context()?;
1648+
let module_path = ctx.module_path.clone();
1649+
let pc_address = ctx.pc_address;
1650+
let analyzer = self.process_analyzer.as_deref_mut().ok_or_else(|| {
1651+
CodeGenError::DwarfError("No DWARF analyzer available".to_string())
1652+
})?;
16591653
let module_address = ghostscope_dwarf::ModuleAddress::new(
1660-
std::path::PathBuf::from(ctx.module_path.clone()),
1661-
ctx.pc_address,
1654+
std::path::PathBuf::from(module_path.clone()),
1655+
pc_address,
16621656
);
16631657
// Try current module at PC first
16641658
match analyzer.plan_chain_access(&module_address, base_name, &[field_name.to_string()])
@@ -1673,7 +1667,7 @@ impl<'ctx> EbpfContext<'ctx> {
16731667
// Strict cross-module chain planning via analyzer API
16741668
match analyzer
16751669
.plan_global_chain_access(
1676-
&std::path::PathBuf::from(ctx.module_path.clone()),
1670+
&std::path::PathBuf::from(module_path.clone()),
16771671
base_name,
16781672
&[field_name.to_string()],
16791673
)
@@ -1696,7 +1690,7 @@ impl<'ctx> EbpfContext<'ctx> {
16961690
ghostscope_dwarf::core::GlobalVariableInfo,
16971691
)> = matches
16981692
.iter()
1699-
.filter(|(p, _)| p.to_string_lossy() == ctx.module_path.as_str())
1693+
.filter(|(p, _)| p.to_string_lossy() == module_path.as_str())
17001694
.cloned()
17011695
.collect();
17021696
let chosen = if preferred.len() == 1 {
@@ -1804,16 +1798,15 @@ impl<'ctx> EbpfContext<'ctx> {
18041798
}
18051799
let mut segs: Vec<&str> = Vec::new();
18061800
if flatten_chain(array_expr, &mut segs) && !segs.is_empty() {
1807-
let Some(analyzer_ptr) = self.process_analyzer else {
1808-
return Err(CodeGenError::DwarfError(
1809-
"No DWARF analyzer available".to_string(),
1810-
));
1811-
};
1812-
let analyzer = unsafe { &mut *analyzer_ptr };
18131801
let ctx = self.get_compile_time_context()?;
1802+
let module_path = ctx.module_path.clone();
1803+
let pc_address = ctx.pc_address;
1804+
let analyzer = self.process_analyzer.as_deref_mut().ok_or_else(|| {
1805+
CodeGenError::DwarfError("No DWARF analyzer available".to_string())
1806+
})?;
18141807
let module_address = ghostscope_dwarf::ModuleAddress::new(
1815-
std::path::PathBuf::from(ctx.module_path.clone()),
1816-
ctx.pc_address,
1808+
std::path::PathBuf::from(module_path),
1809+
pc_address,
18171810
);
18181811
let base = segs[0].to_string();
18191812
let rest: Vec<String> = segs[1..].iter().map(|s| s.to_string()).collect();
@@ -1929,17 +1922,17 @@ impl<'ctx> EbpfContext<'ctx> {
19291922
return self.query_dwarf_for_variable(&chain[0]);
19301923
}
19311924
// Planner path only; do not fallback. If planning fails, surface an error.
1932-
let Some(analyzer_ptr) = self.process_analyzer else {
1933-
return Err(CodeGenError::DwarfError(
1934-
"No DWARF analyzer available".to_string(),
1935-
));
1936-
};
1937-
let analyzer = unsafe { &mut *analyzer_ptr };
19381925
let ctx = self.get_compile_time_context()?;
1926+
let module_path = ctx.module_path.clone();
1927+
let pc_address = ctx.pc_address;
1928+
let analyzer = self
1929+
.process_analyzer
1930+
.as_deref_mut()
1931+
.ok_or_else(|| CodeGenError::DwarfError("No DWARF analyzer available".to_string()))?;
19391932
// First attempt: current module at current PC (locals/params)
19401933
let module_address = ghostscope_dwarf::ModuleAddress::new(
1941-
std::path::PathBuf::from(ctx.module_path.clone()),
1942-
ctx.pc_address,
1934+
std::path::PathBuf::from(module_path.clone()),
1935+
pc_address,
19431936
);
19441937
match analyzer.plan_chain_access(&module_address, &chain[0], &chain[1..]) {
19451938
Ok(Some(var)) => return Ok(Some(var)),
@@ -1953,11 +1946,7 @@ impl<'ctx> EbpfContext<'ctx> {
19531946
let base = &chain[0];
19541947
let rest = &chain[1..];
19551948
match analyzer
1956-
.plan_global_chain_access(
1957-
&std::path::PathBuf::from(ctx.module_path.clone()),
1958-
base,
1959-
rest,
1960-
)
1949+
.plan_global_chain_access(&std::path::PathBuf::from(module_path.clone()), base, rest)
19611950
.map_err(|e| CodeGenError::DwarfError(e.to_string()))?
19621951
{
19631952
Some((mpath, v)) => {
@@ -1975,7 +1964,7 @@ impl<'ctx> EbpfContext<'ctx> {
19751964
ghostscope_dwarf::core::GlobalVariableInfo,
19761965
)> = matches
19771966
.iter()
1978-
.filter(|(p, _)| p.to_string_lossy() == ctx.module_path.as_str())
1967+
.filter(|(p, _)| p.to_string_lossy() == module_path.as_str())
19791968
.cloned()
19801969
.collect();
19811970
let chosen = if preferred.len() == 1 {
@@ -2104,9 +2093,9 @@ impl<'ctx> EbpfContext<'ctx> {
21042093
}
21052094
}
21062095
}
2107-
if let Some(analyzer_ptr) = self.process_analyzer {
2108-
let analyzer = unsafe { &mut *analyzer_ptr };
2109-
let ctx = self.get_compile_time_context()?;
2096+
let ctx = self.get_compile_time_context()?;
2097+
let module_path = ctx.module_path.clone();
2098+
if let Some(analyzer) = self.process_analyzer.as_deref_mut() {
21102099
let mut alias_used: Option<String> = None;
21112100
for n in candidate_names {
21122101
// Prefer cross-module definitions first to avoid forward decls with size=0 in current CU
@@ -2118,8 +2107,8 @@ impl<'ctx> EbpfContext<'ctx> {
21182107
}
21192108
}
21202109
if upgraded.is_none() {
2121-
if let Some(ti) = analyzer
2122-
.resolve_struct_type_shallow_by_name_in_module(&ctx.module_path, &n)
2110+
if let Some(ti) =
2111+
analyzer.resolve_struct_type_shallow_by_name_in_module(&module_path, &n)
21232112
{
21242113
if ti.size() > 0 {
21252114
upgraded = Some(ti);
@@ -2135,8 +2124,8 @@ impl<'ctx> EbpfContext<'ctx> {
21352124
}
21362125
}
21372126
if upgraded.is_none() {
2138-
if let Some(ti) = analyzer
2139-
.resolve_union_type_shallow_by_name_in_module(&ctx.module_path, &n)
2127+
if let Some(ti) =
2128+
analyzer.resolve_union_type_shallow_by_name_in_module(&module_path, &n)
21402129
{
21412130
if ti.size() > 0 {
21422131
upgraded = Some(ti);
@@ -2152,8 +2141,8 @@ impl<'ctx> EbpfContext<'ctx> {
21522141
}
21532142
}
21542143
if upgraded.is_none() {
2155-
if let Some(ti) = analyzer
2156-
.resolve_enum_type_shallow_by_name_in_module(&ctx.module_path, &n)
2144+
if let Some(ti) =
2145+
analyzer.resolve_enum_type_shallow_by_name_in_module(&module_path, &n)
21572146
{
21582147
if ti.size() > 0 {
21592148
upgraded = Some(ti);

ghostscope-compiler/src/ebpf/expression.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tracing::debug;
1212

1313
// compare cap is provided via compile_options.compare_cap (config: ebpf.compare_cap)
1414

15-
impl<'ctx> EbpfContext<'ctx> {
15+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
1616
pub(crate) fn get_host_pid_tid_values(&mut self) -> Result<(IntValue<'ctx>, IntValue<'ctx>)> {
1717
let i32_type = self.context.i32_type();
1818
let i64_type = self.context.i64_type();
@@ -1361,8 +1361,8 @@ impl<'ctx> EbpfContext<'ctx> {
13611361
}
13621362
};
13631363
// Accept string on either side: string literal or script string variable
1364-
fn extract_script_string<'a>(
1365-
this: &mut EbpfContext<'a>,
1364+
fn extract_script_string(
1365+
this: &mut EbpfContext<'_, '_>,
13661366
e: &Expr,
13671367
) -> Option<String> {
13681368
match e {
@@ -1404,8 +1404,8 @@ impl<'ctx> EbpfContext<'ctx> {
14041404
));
14051405
}
14061406
// Accept string on either side (literal or script string var)
1407-
fn extract_script_string<'a>(
1408-
this: &mut EbpfContext<'a>,
1407+
fn extract_script_string(
1408+
this: &mut EbpfContext<'_, '_>,
14091409
e: &Expr,
14101410
) -> Option<String> {
14111411
match e {
@@ -2222,7 +2222,7 @@ impl<'ctx> EbpfContext<'ctx> {
22222222
}
22232223
}
22242224

2225-
impl<'ctx> EbpfContext<'ctx> {
2225+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
22262226
/// Compile comparison between a DWARF-side expression and a script string literal.
22272227
/// Supports char* and char[N] according to design in string_comparison.md.
22282228
fn compile_string_comparison(

ghostscope-compiler/src/ebpf/helper_functions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct ProbeReadResult<'ctx> {
2222
not_found: IntValue<'ctx>,
2323
}
2424

25-
impl<'ctx> EbpfContext<'ctx> {
25+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
2626
fn get_probe_read_scratch_buffer(
2727
&mut self,
2828
result_size: usize,
@@ -603,7 +603,7 @@ impl<'ctx> EbpfContext<'ctx> {
603603
.build_pointer_cast(val_ptr, i64_ptr_ty, "val_u64_ptr")
604604
.map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
605605
let load_field = |idx: u64,
606-
ctx: &mut EbpfContext<'ctx>,
606+
ctx: &mut EbpfContext<'ctx, 'dw>,
607607
base: PointerValue<'ctx>|
608608
-> Result<IntValue<'ctx>> {
609609
// GEP in i64 element space

ghostscope-compiler/src/ebpf/instruction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const fn split_pid_tgid(pid_tgid: u64) -> (u32, u32) {
1515
((pid_tgid >> 32) as u32, pid_tgid as u32)
1616
}
1717

18-
impl<'ctx> EbpfContext<'ctx> {
18+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
1919
/// Reserve `size` bytes in the per-CPU accumulation buffer and return a pointer to the
2020
/// beginning of the reserved region. On overflow, resets the event offset and returns
2121
/// from the eBPF program early (mirrors existing control-flow style used elsewhere).

ghostscope-compiler/src/ebpf/variables.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use inkwell::values::BasicValueEnum;
99
use inkwell::AddressSpace;
1010
use tracing::{debug, info};
1111

12-
impl<'ctx> EbpfContext<'ctx> {
12+
impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
1313
/// Register a DWARF alias variable. The value expression is stored and resolved at use time.
1414
pub fn set_alias_variable(&mut self, name: &str, expr: crate::script::Expr) {
1515
self.alias_vars.insert(name.to_string(), expr);

0 commit comments

Comments
 (0)