@@ -115,11 +115,11 @@ def handle_vmlinux_struct_field(
115115 struct_name = python_type .__name__
116116 globvar_ir , field_data = self .get_field_type (struct_name , field_name )
117117
118- # Handle cast struct field access (use standard GEP )
118+ # Handle cast struct field access (use bpf_probe_read_kernel )
119119 # Load the struct pointer from the local variable
120120 struct_ptr = builder .load (var_info .var )
121121
122- # Use standard GEP for non-context struct field access
122+ # Use bpf_probe_read_kernel for non-context struct field access
123123 field_value = self .load_struct_field (
124124 builder , struct_ptr , globvar_ir , field_data , struct_name
125125 )
@@ -133,7 +133,7 @@ def load_struct_field(
133133 builder , struct_ptr_int , offset_global , field_data , struct_name = None
134134 ):
135135 """
136- Generate LLVM IR to load a field from a regular (non-context) struct using standard GEP .
136+ Generate LLVM IR to load a field from a regular (non-context) struct using bpf_probe_read_kernel .
137137
138138 Args:
139139 builder: llvmlite IRBuilder instance
@@ -159,7 +159,8 @@ def load_struct_field(
159159 inbounds = False ,
160160 )
161161
162- # Determine the appropriate IR type based on field information
162+ # Determine the appropriate field size based on field information
163+ field_size_bytes = 8 # Default to 8 bytes (64-bit)
163164 int_width = 64 # Default to 64-bit
164165 needs_zext = False
165166
@@ -172,7 +173,7 @@ def load_struct_field(
172173
173174 if field_size_bits in [8 , 16 , 32 , 64 ]:
174175 int_width = field_size_bits
175- logger .info (f"Determined field size: { int_width } bits" )
176+ logger .info (f"Determined field size: { int_width } bits ( { field_size_bytes } bytes) " )
176177
177178 # Special handling for struct_xdp_md i32 fields
178179 if struct_name == "struct_xdp_md" and int_width == 32 :
@@ -195,16 +196,31 @@ def load_struct_field(
195196 field_data .ctype_complex_type , ctypes ._Pointer
196197 ):
197198 int_width = 64 # Pointers are always 64-bit
199+ field_size_bytes = 8
198200 logger .info ("Field is a pointer type, using 64 bits" )
199201 else :
200202 logger .warning ("Complex vmlinux field type, using default 64 bits" )
201203
202- # Bitcast to appropriate pointer type based on determined width
203- ptr_type = ir .PointerType (ir .IntType (int_width ))
204- typed_ptr = builder .bitcast (field_ptr , ptr_type )
204+ # Allocate local storage for the field value
205+ local_storage = builder .alloca (ir .IntType (int_width ))
206+ local_storage_i8_ptr = builder .bitcast (local_storage , i8_ptr_type )
207+
208+ # Use bpf_probe_read_kernel to safely read the field
209+ # This generates:
210+ # %gep = getelementptr i8, ptr %struct_ptr, i64 %offset (already done above as field_ptr)
211+ # %passed = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %gep)
212+ # %result = call i64 inttoptr (i64 113 to ptr)(ptr %local_storage, i32 %size, ptr %passed)
213+ from pythonbpf .helper import emit_probe_read_kernel_call
214+
215+ result = emit_probe_read_kernel_call (
216+ builder ,
217+ local_storage_i8_ptr ,
218+ field_size_bytes ,
219+ field_ptr
220+ )
205221
206- # Load the value
207- value = builder .load (typed_ptr )
222+ # Load the value from local storage
223+ value = builder .load (local_storage )
208224
209225 # Zero-extend i32 to i64 if needed
210226 if needs_zext :
0 commit comments