Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions e2e-tests/tests/rust_script_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,54 @@ async fn test_rust_tuple_projection_plan_preserves_semantic_identity() -> anyhow
assert_eq!(layout.offset, 4);
assert_eq!(layout.member_type.type_name(), "i32");

let cast_type = analyzer
.try_resolve_c_style_semantic_type_spec_in_module(&binary_path, "Pair *")?
.ok_or_else(|| anyhow::anyhow!("expected semantic Pair pointer type"))?;
assert_eq!(
cast_type.origin.as_ref().map(|origin| origin.language),
Some(ghostscope_dwarf::SourceLanguage::Rust)
);
let pointee = analyzer.project_resolved_type(
&cast_type,
&ghostscope_dwarf::VariableAccessSegment::Dereference,
Some(&binary_path),
)?;
assert_eq!(
pointee.layout,
ghostscope_dwarf::TypeProjectionLayout::Dereference
);
assert_eq!(
pointee.resolved_type.identity.layout_dwarf_id(),
pair_plan.type_id
);
assert!(matches!(
ghostscope_dwarf::strip_type_aliases(&pointee.resolved_type.summary),
ghostscope_dwarf::TypeInfo::StructType { name, .. } if name == "Pair"
));

let pair_member = analyzer.project_resolved_type(
&pointee.resolved_type,
&ghostscope_dwarf::VariableAccessSegment::TupleIndex(0),
Some(&binary_path),
)?;
assert_eq!(
pair_member.layout,
ghostscope_dwarf::TypeProjectionLayout::Member { offset: 0 }
);
assert_eq!(pair_member.resolved_type.summary.type_name(), "i32");
assert!(pair_member
.resolved_type
.identity
.layout_dwarf_id()
.is_some());
assert_eq!(
pair_member
.resolved_type
.origin
.map(|origin| origin.language),
Some(ghostscope_dwarf::SourceLanguage::Rust)
);

Ok(())
}

Expand Down
6 changes: 3 additions & 3 deletions ghostscope-compiler/src/ebpf/codegen/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
expr: &crate::script::ast::Expr,
lvalue: crate::ebpf::expression::DynamicLvalue<'ctx>,
) -> Result<ComplexArg<'ctx>> {
let dwarf_type = lvalue.type_info.dwarf_type;
let dwarf_type = lvalue.type_info.resolved_type.summary;
let data_len = Self::compute_read_size_for_type(&dwarf_type);
if data_len == 0 {
return Err(CodeGenError::TypeSizeNotAvailable(self.expr_to_name(expr)));
Expand Down Expand Up @@ -351,7 +351,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
E::AddressOf(inner) => {
if let Some(lvalue) = self.dynamic_lvalue_address_and_type(inner)? {
let ptr_ty = ghostscope_dwarf::TypeInfo::PointerType {
target_type: Box::new(lvalue.type_info.dwarf_type),
target_type: Box::new(lvalue.type_info.resolved_type.summary),
size: 8,
};
return Ok(ComplexArg {
Expand Down Expand Up @@ -515,7 +515,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
if var
.dwarf_type
.as_ref()
.is_some_and(ghostscope_dwarf::is_c_pointer_or_array_type)
.is_some_and(ghostscope_dwarf::is_pointer_or_array_type)
{
let pointed_plan =
self.plan_dwarf_pointer_element_index(&var, index)?;
Expand Down
2 changes: 1 addition & 1 deletion ghostscope-compiler/src/ebpf/dwarf_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
};
let addr = self.resolve_planned_address(address, runtime_status_ptr, module_hint)?;

if ghostscope_dwarf::is_c_aggregate_type(dwarf_type) {
if ghostscope_dwarf::is_aggregate_type(dwarf_type) {
let ptr_ty = self.context.ptr_type(inkwell::AddressSpace::default());
let as_ptr = self
.builder
Expand Down
130 changes: 85 additions & 45 deletions ghostscope-compiler/src/ebpf/expression/casts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{DynamicLvalue, DynamicTypeInfo, IndexableElementInfo};
use crate::ebpf::context::{CodeGenError, EbpfContext, Result, RuntimeAddress};
use crate::script::Expr;
use ghostscope_dwarf::TypeInfo as DwarfType;
use ghostscope_dwarf::{TypeInfo as DwarfType, TypeProjectionLayout, VariableAccessSegment};
use inkwell::values::{BasicValueEnum, IntValue};
use inkwell::AddressSpace;
use std::path::{Path, PathBuf};
Expand All @@ -12,12 +12,12 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
return self
.resolve_cast_target_type(target_type)
.ok()
.is_some_and(|ty| ghostscope_dwarf::is_c_aggregate_type(&ty));
.is_some_and(|ty| ghostscope_dwarf::is_aggregate_type(&ty));
}

if let Ok(Some(var)) = self.query_dwarf_for_complex_expr(expr) {
if let Some(ref ty) = var.dwarf_type {
return ghostscope_dwarf::is_c_aggregate_type(ty);
return ghostscope_dwarf::is_aggregate_type(ty);
}
}
false
Expand Down Expand Up @@ -58,7 +58,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {

if let Ok(Some(var)) = self.query_dwarf_for_complex_expr(expr) {
if let Some(ref ty) = var.dwarf_type {
if ghostscope_dwarf::is_c_pointer_or_array_type(ty) {
if ghostscope_dwarf::is_pointer_or_array_type(ty) {
return true;
}
}
Expand All @@ -67,29 +67,68 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
}

pub(in crate::ebpf) fn resolve_cast_target_type(&self, target_type: &str) -> Result<DwarfType> {
self.resolve_cast_target(target_type)
.map(|resolved| resolved.summary)
}

pub(in crate::ebpf) fn resolve_cast_target(
&self,
target_type: &str,
) -> Result<ghostscope_dwarf::ResolvedType> {
let analyzer = self.process_analyzer;
let resolved = if let Some(context) = self.current_compile_time_context.as_ref() {
let module_path = Path::new(&context.module_path);
analyzer
.map(|analyzer| analyzer.try_resolve_type_spec_in_module(module_path, target_type))
.map(|analyzer| {
analyzer
.try_resolve_c_style_semantic_type_spec_in_module(module_path, target_type)
})
.transpose()
.map_err(|err| CodeGenError::DwarfError(err.to_string()))?
.flatten()
.or_else(|| ghostscope_dwarf::DwarfAnalyzer::resolve_builtin_type_spec(target_type))
.or_else(|| {
ghostscope_dwarf::DwarfAnalyzer::resolve_builtin_c_style_semantic_type_spec(
target_type,
)
})
} else {
analyzer
.map(|analyzer| analyzer.try_resolve_type_spec(target_type))
.map(|analyzer| analyzer.try_resolve_c_style_semantic_type_spec(target_type))
.transpose()
.map_err(|err| CodeGenError::DwarfError(err.to_string()))?
.flatten()
.or_else(|| ghostscope_dwarf::DwarfAnalyzer::resolve_builtin_type_spec(target_type))
.or_else(|| {
ghostscope_dwarf::DwarfAnalyzer::resolve_builtin_c_style_semantic_type_spec(
target_type,
)
})
};

resolved.ok_or_else(|| {
CodeGenError::DwarfError(format!("cast target type '{target_type}' was not found"))
})
}

pub(super) fn dynamic_type_info(
&self,
resolved_type: ghostscope_dwarf::ResolvedType,
fallback_module_path: Option<PathBuf>,
) -> DynamicTypeInfo {
let type_module_path = resolved_type
.origin
.as_ref()
.and_then(|origin| {
self.process_analyzer
.and_then(|analyzer| analyzer.module_path_for_id(origin.module))
})
.map(Path::to_path_buf)
.or(fallback_module_path);
DynamicTypeInfo {
resolved_type,
type_module_path,
}
}

pub(super) fn cast_pointer_target_type(target_type: &DwarfType) -> Option<DwarfType> {
match ghostscope_dwarf::strip_type_aliases(target_type) {
DwarfType::PointerType { target_type, .. } => Some(target_type.as_ref().clone()),
Expand Down Expand Up @@ -197,32 +236,32 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
expr: &Expr,
target_type: &str,
) -> Result<DynamicLvalue<'ctx>> {
let target_type = self.resolve_cast_target_type(target_type)?;
let target = self.resolve_cast_target(target_type)?;
let module_path = self
.current_compile_time_context
.as_ref()
.map(|context| PathBuf::from(&context.module_path));

if let Some(pointee_type) = Self::cast_pointer_target_type(&target_type) {
let target_type_info = self.dynamic_type_info(target, module_path);

if matches!(
ghostscope_dwarf::strip_type_aliases(&target_type_info.resolved_type.summary),
DwarfType::PointerType { .. }
) {
let projection =
self.project_dynamic_type(&target_type_info, &VariableAccessSegment::Dereference)?;
let address = self.cast_source_pointer_value(expr)?;
return Ok(DynamicLvalue {
address,
type_info: DynamicTypeInfo {
dwarf_type: pointee_type,
module_path,
type_id: None,
},
type_info: self
.dynamic_type_info(projection.resolved_type, target_type_info.type_module_path),
});
}

let address = self.cast_source_memory_address(expr)?;
Ok(DynamicLvalue {
address,
type_info: DynamicTypeInfo {
dwarf_type: target_type,
module_path,
type_id: None,
},
type_info: target_type_info,
})
}

Expand All @@ -238,26 +277,23 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
return Ok(None);
};

let target_type = self.resolve_cast_target_type(target_type)?;
let target = self.resolve_cast_target(target_type)?;
let module_path = self
.current_compile_time_context
.as_ref()
.map(|context| PathBuf::from(&context.module_path));

match ghostscope_dwarf::strip_type_aliases(&target_type) {
let target_type_info = self.dynamic_type_info(target, module_path);
match ghostscope_dwarf::strip_type_aliases(&target_type_info.resolved_type.summary) {
DwarfType::PointerType { .. } => {
let Some(element_info) =
Self::indexable_info_from_type(&target_type, module_path, None)
else {
let Some(element_info) = self.project_indexable_type(&target_type_info)? else {
return Ok(None);
};
let base_address = self.cast_source_pointer_value(source_expr)?;
Ok(Some((element_info, base_address)))
}
DwarfType::ArrayType { .. } => {
let Some(element_info) =
Self::indexable_info_from_type(&target_type, module_path, None)
else {
let Some(element_info) = self.project_indexable_type(&target_type_info)? else {
return Ok(None);
};
let base_address = self.cast_source_memory_address(source_expr)?;
Expand All @@ -267,17 +303,25 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
}
}

pub(super) fn indexable_info_from_type(
dwarf_type: &DwarfType,
module_path: Option<PathBuf>,
type_id: Option<ghostscope_dwarf::TypeId>,
) -> Option<IndexableElementInfo> {
ghostscope_dwarf::indexable_element_layout(dwarf_type).map(|layout| IndexableElementInfo {
element_type: layout.element_type,
stride: layout.stride,
module_path,
type_id,
})
pub(super) fn project_indexable_type(
&self,
type_info: &DynamicTypeInfo,
) -> Result<Option<IndexableElementInfo>> {
if !ghostscope_dwarf::is_pointer_or_array_type(&type_info.resolved_type.summary) {
return Ok(None);
}
let projection =
self.project_dynamic_type(type_info, &VariableAccessSegment::ArrayIndex(0))?;
let TypeProjectionLayout::Element { stride } = projection.layout else {
return Err(CodeGenError::DwarfError(
"index projection did not produce an element layout".to_string(),
));
};
Ok(Some(IndexableElementInfo {
type_info: self
.dynamic_type_info(projection.resolved_type, type_info.type_module_path.clone()),
stride,
}))
}

pub(super) fn compiled_pointer_value_to_runtime_address(
Expand Down Expand Up @@ -327,11 +371,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {

Ok(DynamicLvalue {
address: base_address.with_value(element_address),
type_info: DynamicTypeInfo {
dwarf_type: element_info.element_type,
module_path: element_info.module_path,
type_id: element_info.type_id,
},
type_info: element_info.type_info,
})
}

Expand Down Expand Up @@ -447,7 +487,7 @@ impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
.map_err(|err| CodeGenError::Builder(err.to_string()));
}

if ghostscope_dwarf::is_c_aggregate_type(&target_type) {
if ghostscope_dwarf::is_aggregate_type(&target_type) {
let address = self.cast_source_memory_address(expr)?;
let ptr_ty = self.context.ptr_type(AddressSpace::default());
return self
Expand Down
Loading
Loading