@@ -77,7 +77,7 @@ def handle_vmlinux_enum(self, name):
7777 return None
7878
7979 def get_vmlinux_enum_value (self , name ):
80- """Handle vmlinux enum constants by returning LLVM IR constants"""
80+ """Handle vmlinux. enum constants by returning LLVM IR constants"""
8181 if self .is_vmlinux_enum (name ):
8282 value = self .vmlinux_symtab [name ].value
8383 logger .info (f"The value of vmlinux enum { name } = { value } " )
@@ -119,6 +119,9 @@ def handle_vmlinux_struct_field(
119119 # Load the struct pointer from the local variable
120120 struct_ptr = builder .load (var_info .var )
121121
122+ # Determine the preallocated tmp name that assignment pass should have created
123+ tmp_name = f"{ struct_var_name } _{ field_name } _tmp"
124+
122125 # Use bpf_probe_read_kernel for non-context struct field access
123126 field_value = self .load_struct_field (
124127 builder ,
@@ -127,6 +130,7 @@ def handle_vmlinux_struct_field(
127130 field_data ,
128131 struct_name ,
129132 local_sym_tab ,
133+ tmp_name ,
130134 )
131135 # Return field value and field type
132136 return field_value , field_data
@@ -141,6 +145,7 @@ def load_struct_field(
141145 field_data ,
142146 struct_name = None ,
143147 local_sym_tab = None ,
148+ tmp_name : str = None ,
144149 ):
145150 """
146151 Generate LLVM IR to load a field from a regular (non-context) struct using bpf_probe_read_kernel.
@@ -151,6 +156,8 @@ def load_struct_field(
151156 offset_global: Global variable containing the field offset (i64)
152157 field_data: contains data about the field
153158 struct_name: Name of the struct being accessed (optional)
159+ local_sym_tab: symbol table (optional) - used to locate preallocated tmp storage
160+ tmp_name: name of the preallocated temporary storage to use (preferred)
154161 Returns:
155162 The loaded value
156163 """
@@ -213,10 +220,20 @@ def load_struct_field(
213220 else :
214221 logger .warning ("Complex vmlinux field type, using default 64 bits" )
215222
216- # Allocate local storage for the field value
217- # TODO: CRITICAL BUG. alloca cannot be used anywhere other than the basic block
218- local_storage = builder .alloca (ir .IntType (int_width ))
219- local_storage_i8_ptr = builder .bitcast (local_storage , i8_ptr_type )
223+ # Use preallocated temporary storage if provided by allocation pass
224+
225+ local_storage_i8_ptr = None
226+ if tmp_name and local_sym_tab and tmp_name in local_sym_tab :
227+ # Expect the tmp to be an alloca created during allocation pass
228+ tmp_alloca = local_sym_tab [tmp_name ].var
229+ local_storage_i8_ptr = builder .bitcast (tmp_alloca , i8_ptr_type )
230+ else :
231+ # Fallback: allocate inline (not ideal, but preserves behavior)
232+ local_storage = builder .alloca (ir .IntType (int_width ))
233+ local_storage_i8_ptr = builder .bitcast (local_storage , i8_ptr_type )
234+ logger .warning (
235+ f"Temp storage '{ tmp_name } ' not found. Allocating inline"
236+ )
220237
221238 # Use bpf_probe_read_kernel to safely read the field
222239 # This generates:
@@ -230,7 +247,7 @@ def load_struct_field(
230247 )
231248
232249 # Load the value from local storage
233- value = builder .load (local_storage )
250+ value = builder .load (builder . bitcast ( local_storage_i8_ptr , ir . PointerType ( ir . IntType ( int_width ))) )
234251
235252 # Zero-extend i32 to i64 if needed
236253 if needs_zext :
0 commit comments