Skip to content

Commit 9def969

Browse files
committed
Make map val struct type allocation work by fixing pointer deref and debuginfogen: WIP
1 parent e5b3b00 commit 9def969

File tree

4 files changed

+97
-3
lines changed

4 files changed

+97
-3
lines changed

pythonbpf/allocation_pass.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def _allocate_for_map_method(
178178
# Main variable (pointer to pointer)
179179
ir_type = ir.PointerType(ir.IntType(64))
180180
var = builder.alloca(ir_type, name=var_name)
181-
local_sym_tab[var_name] = LocalSymbol(var, ir_type)
181+
local_sym_tab[var_name] = LocalSymbol(var, ir_type, value_type)
182182
# Temporary variable for computed values
183183
tmp_ir_type = value_ir_type
184184
var_tmp = builder.alloca(tmp_ir_type, name=f"{var_name}_tmp")

pythonbpf/expr/expr_pass.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def _handle_constant_expr(module, builder, expr: ast.Constant):
6161

6262

6363
def _handle_attribute_expr(
64+
func,
6465
expr: ast.Attribute,
6566
local_sym_tab: Dict,
6667
structs_sym_tab: Dict,
@@ -76,6 +77,89 @@ def _handle_attribute_expr(
7677
logger.info(
7778
f"Variable type: {var_type}, Variable ptr: {var_ptr}, Variable Metadata: {var_metadata}"
7879
)
80+
# Check if this is a pointer to a struct (from map lookup)
81+
if (
82+
isinstance(var_type, ir.PointerType)
83+
and var_metadata
84+
and isinstance(var_metadata, str)
85+
):
86+
if var_metadata in structs_sym_tab:
87+
logger.info(
88+
f"Handling pointer to struct {var_metadata} from map lookup"
89+
)
90+
91+
if func is None:
92+
raise ValueError(
93+
f"func parameter required for null-safe pointer access to {var_name}.{attr_name}"
94+
)
95+
96+
# Load the pointer value (ptr<struct>)
97+
struct_ptr = builder.load(var_ptr)
98+
99+
# Create blocks for null check
100+
null_check_block = builder.block
101+
not_null_block = func.append_basic_block(
102+
name=f"{var_name}_not_null"
103+
)
104+
merge_block = func.append_basic_block(name=f"{var_name}_merge")
105+
106+
# Check if pointer is null
107+
null_ptr = ir.Constant(struct_ptr.type, None)
108+
is_not_null = builder.icmp_signed("!=", struct_ptr, null_ptr)
109+
logger.info(f"Inserted null check for pointer {var_name}")
110+
111+
builder.cbranch(is_not_null, not_null_block, merge_block)
112+
113+
# Not-null block: Access the field
114+
builder.position_at_end(not_null_block)
115+
116+
# Get struct metadata
117+
metadata = structs_sym_tab[var_metadata]
118+
struct_ptr = builder.bitcast(
119+
struct_ptr, metadata.ir_type.as_pointer()
120+
)
121+
122+
if attr_name not in metadata.fields:
123+
raise ValueError(
124+
f"Field '{attr_name}' not found in struct '{var_metadata}'"
125+
)
126+
127+
# GEP to field
128+
field_gep = metadata.gep(builder, struct_ptr, attr_name)
129+
130+
# Load field value
131+
field_val = builder.load(field_gep)
132+
field_type = metadata.field_type(attr_name)
133+
134+
logger.info(
135+
f"Loaded field {attr_name} from struct pointer, type: {field_type}"
136+
)
137+
138+
# Branch to merge
139+
not_null_after_load = builder.block
140+
builder.branch(merge_block)
141+
142+
# Merge block: PHI node for the result
143+
builder.position_at_end(merge_block)
144+
phi = builder.phi(field_type, name=f"{var_name}_{attr_name}")
145+
146+
# If null, return zero/default value
147+
if isinstance(field_type, ir.IntType):
148+
zero_value = ir.Constant(field_type, 0)
149+
elif isinstance(field_type, ir.PointerType):
150+
zero_value = ir.Constant(field_type, None)
151+
elif isinstance(field_type, ir.ArrayType):
152+
# For arrays, we can't easily create a zero constant
153+
# This case is tricky - for now, just use undef
154+
zero_value = ir.Constant(field_type, ir.Undefined)
155+
else:
156+
zero_value = ir.Constant(field_type, ir.Undefined)
157+
158+
phi.add_incoming(zero_value, null_check_block)
159+
phi.add_incoming(field_val, not_null_after_load)
160+
161+
logger.info(f"Created PHI node for {var_name}.{attr_name}")
162+
return phi, field_type
79163
if (
80164
hasattr(var_metadata, "__module__")
81165
and var_metadata.__module__ == "vmlinux"
@@ -568,7 +652,9 @@ def eval_expr(
568652
logger.warning(f"Unknown call: {ast.dump(expr)}")
569653
return None
570654
elif isinstance(expr, ast.Attribute):
571-
return _handle_attribute_expr(expr, local_sym_tab, structs_sym_tab, builder)
655+
return _handle_attribute_expr(
656+
func, expr, local_sym_tab, structs_sym_tab, builder
657+
)
572658
elif isinstance(expr, ast.BinOp):
573659
return _handle_binary_op(
574660
func,

pythonbpf/expr/ir_ops.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ def deref_to_depth(func, builder, val, target_depth):
4848
cur_val = phi
4949
cur_type = pointee_type
5050
return cur_val
51+
52+
53+
def deref_struct_ptr(
54+
func, builder, struct_ptr, struct_metadata, field_name, structs_sym_tab
55+
):
56+
"""Dereference a pointer to a struct type."""
57+
return deref_to_depth(func, builder, struct_ptr, 1)

pythonbpf/maps/map_debug_info.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def _get_key_val_dbg_type(name, generator, structs_sym_tab):
117117

118118
type_obj = structs_sym_tab.get(name)
119119
if type_obj:
120+
logger.info(f"Found struct named {name}, generating debug type")
120121
return _get_struct_debug_type(type_obj, generator, structs_sym_tab)
121122

122123
# Fallback to basic types
@@ -165,6 +166,6 @@ def _get_struct_debug_type(struct_obj, generator, structs_sym_tab):
165166
)
166167
elements_arr.append(member)
167168
struct_type = generator.create_struct_type(
168-
elements_arr, struct_obj.size, is_distinct=True
169+
elements_arr, struct_obj.size * 8, is_distinct=True
169170
)
170171
return struct_type

0 commit comments

Comments
 (0)