diff --git a/ghostscope-compiler/src/ebpf/dwarf_bridge.rs b/ghostscope-compiler/src/ebpf/dwarf_bridge.rs index 8869cd7..6991bdc 100644 --- a/ghostscope-compiler/src/ebpf/dwarf_bridge.rs +++ b/ghostscope-compiler/src/ebpf/dwarf_bridge.rs @@ -66,24 +66,21 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { fn planned_value_to_llvm_value( &mut self, value: &ghostscope_dwarf::PlannedValue, - dwarf_type: &TypeInfo, var_name: &str, - _pc_address: u64, status_ptr: Option>, ) -> Result> { let pt_regs_ptr = self.get_pt_regs_parameter()?; - let result_size = MemoryAccessSize::from_size(Self::get_dwarf_type_size(dwarf_type)); match value { - ghostscope_dwarf::PlannedValue::Constant(value) => Ok(self + ghostscope_dwarf::PlannedValue::Constant { value, .. } => Ok(self .context .i64_type() .const_int(*value as u64, true) .into()), - ghostscope_dwarf::PlannedValue::RegisterValue { dwarf_reg } => { + ghostscope_dwarf::PlannedValue::RegisterValue { dwarf_reg, .. } => { debug!("Generating register value: {dwarf_reg}"); self.load_register_value(*dwarf_reg, pt_regs_ptr) } - ghostscope_dwarf::PlannedValue::ComputedValue { steps } => { + ghostscope_dwarf::PlannedValue::ComputedValue { steps, result_size } => { debug!("Generating computed value: {} steps", steps.len()); let runtime_status_ptr = if self.condition_context_active { Some(self.get_or_create_cond_error_global()) @@ -93,7 +90,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { self.generate_compute_steps( steps, pt_regs_ptr, - Some(result_size), + Some(*result_size), runtime_status_ptr, None, ) @@ -106,7 +103,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { } Ok(self.context.i64_type().const_int(value, false).into()) } - ghostscope_dwarf::PlannedValue::AddressValue { address } => { + ghostscope_dwarf::PlannedValue::AddressValue { address, .. } => { debug!("Generating address direct value for variable: {var_name}"); let runtime_status_ptr = if self.condition_context_active { Some(self.get_or_create_cond_error_global()) @@ -302,14 +299,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { /// Convert DWARF type size to MemoryAccessSize fn dwarf_type_to_memory_access_size(&self, dwarf_type: &TypeInfo) -> MemoryAccessSize { - let size = Self::get_dwarf_type_size(dwarf_type); - match size { - 1 => MemoryAccessSize::U8, - 2 => MemoryAccessSize::U16, - 4 => MemoryAccessSize::U32, - 8 => MemoryAccessSize::U64, - _ => MemoryAccessSize::U64, // Default to U64 for unknown sizes - } + MemoryAccessSize::from_size(dwarf_type.size()) } fn is_signed_integer_type(dwarf_type: &TypeInfo) -> bool { @@ -377,7 +367,12 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { )); } - if materialization.availability != Availability::OptimizedOut { + if materialization.availability != Availability::OptimizedOut + && matches!( + materialization.materialization, + ghostscope_dwarf::VariableMaterialization::UserMemoryRead { .. } + ) + { materialization.dwarf_type.as_ref().ok_or_else(|| { CodeGenError::DwarfError("Expression has no DWARF type information".to_string()) })?; @@ -394,18 +389,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { ) -> Result> { match &materialization.materialization { ghostscope_dwarf::VariableMaterialization::DirectValue { value } => { - let dwarf_type = materialization.dwarf_type.as_ref().ok_or_else(|| { - CodeGenError::DwarfError( - "Expression has no DWARF type information".to_string(), - ) - })?; - self.planned_value_to_llvm_value( - value, - dwarf_type, - &materialization.name, - pc_address, - status_ptr, - ) + self.planned_value_to_llvm_value(value, &materialization.name, status_ptr) } ghostscope_dwarf::VariableMaterialization::UserMemoryRead { address } => { let dwarf_type = materialization.dwarf_type.as_ref().ok_or_else(|| { @@ -1399,33 +1383,6 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> { Ok(Some((base, VariableAccessPath::new(segments)))) } - /// Get DWARF type size in bytes - pub fn get_dwarf_type_size(dwarf_type: &TypeInfo) -> u64 { - match dwarf_type { - TypeInfo::BaseType { size, .. } => *size, - TypeInfo::PointerType { size, .. } => *size, - TypeInfo::ArrayType { total_size, .. } => total_size.unwrap_or(0), - TypeInfo::StructType { size, .. } => *size, - TypeInfo::UnionType { size, .. } => *size, - TypeInfo::EnumType { size, .. } => *size, - TypeInfo::BitfieldType { - underlying_type, .. - } => { - // Read size equals the storage type size - Self::get_dwarf_type_size(underlying_type) - } - TypeInfo::TypedefType { - underlying_type, .. - } => Self::get_dwarf_type_size(underlying_type), - TypeInfo::QualifiedType { - underlying_type, .. - } => Self::get_dwarf_type_size(underlying_type), - TypeInfo::FunctionType { .. } => 8, // Function pointer size - TypeInfo::UnknownType { .. } => 0, - TypeInfo::OptimizedOut { .. } => 0, // Optimized out has no size - } - } - /// Compute a typed pointed-to location for expressions like `ptr +/- K` where K is an element index. /// Returns a computed location along with the pointed-to DWARF type. /// The offset is scaled by the element size of the pointer/array target type. diff --git a/ghostscope-dwarf/src/semantics/variable_plan.rs b/ghostscope-dwarf/src/semantics/variable_plan.rs index e72a7d3..806a66f 100644 --- a/ghostscope-dwarf/src/semantics/variable_plan.rs +++ b/ghostscope-dwarf/src/semantics/variable_plan.rs @@ -83,11 +83,23 @@ pub enum PlannedAddressKind { #[derive(Debug, Clone, PartialEq)] pub enum PlannedValue { - Constant(i64), - RegisterValue { dwarf_reg: u16 }, - ComputedValue { steps: Vec }, + Constant { + value: i64, + size: MemoryAccessSize, + }, + RegisterValue { + dwarf_reg: u16, + size: MemoryAccessSize, + }, + ComputedValue { + steps: Vec, + result_size: MemoryAccessSize, + }, ImplicitBytes(Vec), - AddressValue { address: PlannedAddress }, + AddressValue { + address: PlannedAddress, + size: MemoryAccessSize, + }, } #[derive(Debug, Clone, PartialEq)] @@ -297,7 +309,8 @@ impl VariableReadPlan { } else { match lowering.kind { VariableLoweringKind::DirectValue => { - match PlannedValue::from_location(self.location.clone()) { + let size = planned_value_size(self.dwarf_type.as_ref()); + match PlannedValue::from_location(self.location.clone(), size) { Some(value) => VariableMaterialization::DirectValue { value }, None => VariableMaterialization::Unavailable { availability: Availability::Unsupported( @@ -470,22 +483,28 @@ impl VariableReadPlan { } impl PlannedValue { - pub fn from_location(location: VariableLocation) -> Option { + pub fn from_location(location: VariableLocation, size: MemoryAccessSize) -> Option { match location { VariableLocation::RegisterValue { dwarf_reg } => { - Some(Self::RegisterValue { dwarf_reg }) + Some(Self::RegisterValue { dwarf_reg, size }) } VariableLocation::ComputedValue(steps) => { if let [ComputeStep::PushConstant(value)] = steps.as_slice() { - Some(Self::Constant(*value)) + Some(Self::Constant { + value: *value, + size, + }) } else { - Some(Self::ComputedValue { steps }) + Some(Self::ComputedValue { + steps, + result_size: size, + }) } } VariableLocation::ImplicitValue(bytes) => Some(Self::ImplicitBytes(bytes)), VariableLocation::AbsoluteAddressValue(expr) => { PlannedAddress::from_location(VariableLocation::AbsoluteAddressValue(expr)) - .map(|address| Self::AddressValue { address }) + .map(|address| Self::AddressValue { address, size }) } VariableLocation::Address(_) | VariableLocation::RegisterAddress { .. } @@ -573,6 +592,12 @@ impl RuntimeCapabilities { } } +fn planned_value_size(dwarf_type: Option<&TypeInfo>) -> MemoryAccessSize { + dwarf_type + .map(|ty| MemoryAccessSize::from_size(ty.size())) + .unwrap_or(MemoryAccessSize::U64) +} + fn address_origin_for_steps(steps: &[ComputeStep]) -> AddressOrigin { if fold_constant_steps(steps).is_some() { return AddressOrigin::LinkTime; @@ -1231,6 +1256,7 @@ mod tests { kind: PlannedAddressKind::Constant { address: 0x2000 }, .. }, + size: MemoryAccessSize::U64, }, } => {} VariableMaterialization::DirectValue { value } => { @@ -1249,7 +1275,40 @@ mod tests { match materialized.materialization { VariableMaterialization::DirectValue { - value: PlannedValue::Constant(42), + value: + PlannedValue::Constant { + value: 42, + size: MemoryAccessSize::U64, + }, + } => {} + other => panic!("unexpected materialization: {other:?}"), + } + } + + #[test] + fn materialization_plan_records_direct_value_size_from_type() { + let byte_type = TypeInfo::BaseType { + name: "uint8_t".to_string(), + size: 1, + encoding: gimli::constants::DW_ATE_unsigned.0 as u16, + }; + let plan = typed_read_plan( + VariableLocation::ComputedValue(vec![ + ComputeStep::LoadRegister(0), + ComputeStep::PushConstant(1), + ComputeStep::Add, + ]), + byte_type, + ); + let materialized = plan.materialization_plan(&capabilities(false)); + + match materialized.materialization { + VariableMaterialization::DirectValue { + value: + PlannedValue::ComputedValue { + result_size: MemoryAccessSize::U8, + .. + }, } => {} other => panic!("unexpected materialization: {other:?}"), } @@ -1262,7 +1321,11 @@ mod tests { match materialized.materialization { VariableMaterialization::DirectValue { - value: PlannedValue::RegisterValue { dwarf_reg: 6 }, + value: + PlannedValue::RegisterValue { + dwarf_reg: 6, + size: MemoryAccessSize::U64, + }, } => {} other => panic!("unexpected materialization: {other:?}"), }