@@ -94,17 +94,119 @@ def handle_vmlinux_struct_field(
9494 f"Attempting to access field { field_name } of possible vmlinux struct { struct_var_name } "
9595 )
9696 python_type : type = var_info .metadata
97- struct_name = python_type .__name__
98- globvar_ir , field_data = self .get_field_type (struct_name , field_name )
99- builder .function .args [0 ].type = ir .PointerType (ir .IntType (8 ))
100- field_ptr = self .load_ctx_field (
101- builder , builder .function .args [0 ], globvar_ir , field_data , struct_name
102- )
103- # Return pointer to field and field type
104- return field_ptr , field_data
97+ # Check if this is a context field (ctx) or a cast struct
98+ is_context_field = var_info .var is None
99+
100+ if is_context_field :
101+ # Handle context field access (original behavior)
102+ struct_name = python_type .__name__
103+ globvar_ir , field_data = self .get_field_type (struct_name , field_name )
104+ builder .function .args [0 ].type = ir .PointerType (ir .IntType (8 ))
105+ field_ptr = self .load_ctx_field (
106+ builder , builder .function .args [0 ], globvar_ir , field_data , struct_name
107+ )
108+ return field_ptr , field_data
109+ else :
110+ # Handle cast struct field access
111+ struct_name = python_type .__name__
112+ globvar_ir , field_data = self .get_field_type (struct_name , field_name )
113+
114+ # Handle cast struct field access (use standard GEP)
115+ # Load the struct pointer from the local variable
116+ struct_ptr = builder .load (var_info .var )
117+
118+ # Use standard GEP for non-context struct field access
119+ field_value = self .load_struct_field (
120+ builder , struct_ptr , globvar_ir , field_data , struct_name
121+ )
122+ # Return field value and field type
123+ return field_value , field_data
105124 else :
106125 raise RuntimeError ("Variable accessed not found in symbol table" )
107126
127+ @staticmethod
128+ def load_struct_field (builder , struct_ptr_int , offset_global , field_data , struct_name = None ):
129+ """
130+ Generate LLVM IR to load a field from a regular (non-context) struct using standard GEP.
131+
132+ Args:
133+ builder: llvmlite IRBuilder instance
134+ struct_ptr_int: The struct pointer as an i64 value (already loaded from alloca)
135+ offset_global: Global variable containing the field offset (i64)
136+ field_data: contains data about the field
137+ struct_name: Name of the struct being accessed (optional)
138+ Returns:
139+ The loaded value
140+ """
141+
142+ # Load the offset value
143+ offset = builder .load (offset_global )
144+
145+ # Convert i64 to pointer type (BPF stores pointers as i64)
146+ i8_ptr_type = ir .PointerType (ir .IntType (8 ))
147+ struct_ptr = builder .inttoptr (struct_ptr_int , i8_ptr_type )
148+
149+ # GEP with offset to get field pointer
150+ field_ptr = builder .gep (
151+ struct_ptr ,
152+ [offset ],
153+ inbounds = False ,
154+ )
155+
156+ # Determine the appropriate IR type based on field information
157+ int_width = 64 # Default to 64-bit
158+ needs_zext = False
159+
160+ if field_data is not None :
161+ # Try to determine the size from field metadata
162+ if field_data .type .__module__ == ctypes .__name__ :
163+ try :
164+ field_size_bytes = ctypes .sizeof (field_data .type )
165+ field_size_bits = field_size_bytes * 8
166+
167+ if field_size_bits in [8 , 16 , 32 , 64 ]:
168+ int_width = field_size_bits
169+ logger .info (f"Determined field size: { int_width } bits" )
170+
171+ # Special handling for struct_xdp_md i32 fields
172+ if struct_name == "struct_xdp_md" and int_width == 32 :
173+ needs_zext = True
174+ logger .info (
175+ "struct_xdp_md i32 field detected, will zero-extend to i64"
176+ )
177+ else :
178+ logger .warning (
179+ f"Unusual field size { field_size_bits } bits, using default 64"
180+ )
181+ except Exception as e :
182+ logger .warning (
183+ f"Could not determine field size: { e } , using default 64"
184+ )
185+
186+ elif field_data .type .__module__ == "vmlinux" :
187+ # For pointers to structs or complex vmlinux types
188+ if field_data .ctype_complex_type is not None and issubclass (
189+ field_data .ctype_complex_type , ctypes ._Pointer
190+ ):
191+ int_width = 64 # Pointers are always 64-bit
192+ logger .info ("Field is a pointer type, using 64 bits" )
193+ else :
194+ logger .warning ("Complex vmlinux field type, using default 64 bits" )
195+
196+ # Bitcast to appropriate pointer type based on determined width
197+ ptr_type = ir .PointerType (ir .IntType (int_width ))
198+ typed_ptr = builder .bitcast (field_ptr , ptr_type )
199+
200+ # Load the value
201+ value = builder .load (typed_ptr )
202+
203+ # Zero-extend i32 to i64 if needed
204+ if needs_zext :
205+ value = builder .zext (value , ir .IntType (64 ))
206+ logger .info ("Zero-extended i32 value to i64" )
207+
208+ return value
209+
108210 @staticmethod
109211 def load_ctx_field (builder , ctx_arg , offset_global , field_data , struct_name = None ):
110212 """
0 commit comments