@@ -61,6 +61,7 @@ def _handle_constant_expr(module, builder, expr: ast.Constant):
6161
6262
6363def _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 ,
0 commit comments