11import ast
22from llvmlite import ir
3+ from .expr_pass import eval_expr
34
45
5- def bpf_ktime_get_ns_emitter (call , module , builder , func ):
6+ def bpf_ktime_get_ns_emitter (call , map_ptr , module , builder , func , local_sym_tab = None ):
67 """
78 Emit LLVM IR for bpf_ktime_get_ns helper function call.
89 """
@@ -62,10 +63,87 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
6263 return result
6364
6465
65- def bpf_printk_emitter (call , module , builder , func ):
66+ def bpf_printk_emitter (call , map_ptr , module , builder , func , local_sym_tab = None ):
6667 if not hasattr (func , "_fmt_counter" ):
6768 func ._fmt_counter = 0
6869
70+ if not call .args :
71+ raise ValueError ("print expects at least one argument" )
72+
73+ if isinstance (call .args [0 ], ast .JoinedStr ):
74+ fmt_parts = []
75+ exprs = []
76+
77+ for value in call .args [0 ].values :
78+ if isinstance (value , ast .Constant ):
79+ if isinstance (value .value , str ):
80+ fmt_parts .append (value .value )
81+ elif isinstance (value .value , int ):
82+ fmt_parts .append ("%lld" )
83+ exprs .append (ir .Constant (ir .IntType (64 ), value .value ))
84+ else :
85+ raise NotImplementedError (
86+ "Only string and integer constants are supported in f-string." )
87+ elif isinstance (value , ast .FormattedValue ):
88+ # Assume int for now
89+ fmt_parts .append ("%d" )
90+ if isinstance (value .value , ast .Name ):
91+ exprs .append (value .value )
92+ else :
93+ raise NotImplementedError (
94+ "Only simple variable names are supported in formatted values." )
95+ else :
96+ raise NotImplementedError (
97+ "Unsupported value type in f-string." )
98+
99+ fmt_str = "" .join (fmt_parts ) + "\n " + "\0 "
100+ fmt_name = f"{ func .name } ____fmt{ func ._fmt_counter } "
101+ func ._fmt_counter += 1
102+
103+ fmt_gvar = ir .GlobalVariable (
104+ module , ir .ArrayType (ir .IntType (8 ), len (fmt_str )), name = fmt_name )
105+ fmt_gvar .global_constant = True
106+ fmt_gvar .initializer = ir .Constant (
107+ ir .ArrayType (ir .IntType (8 ), len (fmt_str )),
108+ bytearray (fmt_str .encode ("utf8" ))
109+ )
110+ fmt_gvar .linkage = "internal"
111+ fmt_gvar .align = 1
112+
113+ fmt_ptr = builder .bitcast (fmt_gvar , ir .PointerType ())
114+
115+ args = [fmt_ptr , ir .Constant (ir .IntType (32 ), len (fmt_str ))]
116+
117+ # Only 3 args supported in bpf_printk
118+ if len (exprs ) > 3 :
119+ print (
120+ "Warning: bpf_printk supports up to 3 arguments, extra arguments will be ignored." )
121+
122+ for expr in exprs [:3 ]:
123+ val = eval_expr (func , module , builder , expr , local_sym_tab , None )
124+ if val :
125+ if isinstance (val .type , ir .PointerType ):
126+ val = builder .ptrtoint (val , ir .IntType (64 ))
127+ elif isinstance (val .type , ir .IntType ):
128+ if val .type .width < 64 :
129+ val = builder .sext (val , ir .IntType (64 ))
130+ else :
131+ print (
132+ "Warning: Only integer and pointer types are supported in bpf_printk arguments. Others will be converted to 0." )
133+ val = ir .Constant (ir .IntType (64 ), 0 )
134+ args .append (val )
135+ else :
136+ print (
137+ "Warning: Failed to evaluate expression for bpf_printk argument. It will be converted to 0." )
138+ args .append (ir .Constant (ir .IntType (64 ), 0 ))
139+
140+ fn_type = ir .FunctionType (ir .IntType (
141+ 64 ), [ir .PointerType (), ir .IntType (32 )], var_arg = True )
142+ fn_ptr_type = ir .PointerType (fn_type )
143+ fn_addr = ir .Constant (ir .IntType (64 ), 6 )
144+ fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
145+ return builder .call (fn_ptr , args , tail = True )
146+
69147 for arg in call .args :
70148 if isinstance (arg , ast .Constant ) and isinstance (arg .value , str ):
71149 fmt_str = arg .value + "\n " + "\0 "
@@ -93,6 +171,7 @@ def bpf_printk_emitter(call, module, builder, func):
93171 builder .call (fn_ptr , [fmt_ptr , ir .Constant (
94172 ir .IntType (32 ), len (fmt_str ))], tail = True )
95173
174+
96175def bpf_map_update_elem_emitter (call , map_ptr , module , builder , local_sym_tab = None ):
97176 """
98177 Emit LLVM IR for bpf_map_update_elem helper function call.
@@ -101,11 +180,11 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
101180 if not call .args or len (call .args ) < 2 or len (call .args ) > 3 :
102181 raise ValueError ("Map update expects 2 or 3 arguments (key, value, flags), got "
103182 f"{ len (call .args )} " )
104-
183+
105184 key_arg = call .args [0 ]
106185 value_arg = call .args [1 ]
107186 flags_arg = call .args [2 ] if len (call .args ) > 2 else None
108-
187+
109188 # Handle key
110189 if isinstance (key_arg , ast .Name ):
111190 key_name = key_arg .id
@@ -124,7 +203,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
124203 else :
125204 raise NotImplementedError (
126205 "Only simple variable names and integer constants are supported as keys in map update." )
127-
206+
128207 # Handle value
129208 if isinstance (value_arg , ast .Name ):
130209 value_name = value_arg .id
@@ -143,7 +222,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
143222 else :
144223 raise NotImplementedError (
145224 "Only simple variable names and integer constants are supported as values in map update." )
146-
225+
147226 # Handle flags argument (defaults to 0)
148227 if flags_arg is not None :
149228 if isinstance (flags_arg , ast .Constant ) and isinstance (flags_arg .value , int ):
@@ -162,7 +241,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
162241 "Only integer constants and simple variable names are supported as flags in map update." )
163242 else :
164243 flags_val = 0
165-
244+
166245 if key_ptr is None or value_ptr is None :
167246 raise ValueError ("Key pointer or value pointer is None." )
168247
@@ -173,20 +252,22 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
173252 var_arg = False
174253 )
175254 fn_ptr_type = ir .PointerType (fn_type )
176-
255+
177256 # helper id
178257 fn_addr = ir .Constant (ir .IntType (64 ), 2 )
179258 fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
180-
259+
181260 if isinstance (flags_val , int ):
182261 flags_const = ir .Constant (ir .IntType (64 ), flags_val )
183262 else :
184263 flags_const = flags_val
185264
186- result = builder .call (fn_ptr , [map_void_ptr , key_ptr , value_ptr , flags_const ], tail = False )
187-
265+ result = builder .call (
266+ fn_ptr , [map_void_ptr , key_ptr , value_ptr , flags_const ], tail = False )
267+
188268 return result
189269
270+
190271helper_func_list = {
191272 "lookup" : bpf_map_lookup_elem_emitter ,
192273 "print" : bpf_printk_emitter ,
@@ -200,7 +281,7 @@ def handle_helper_call(call, module, builder, func, local_sym_tab=None, map_sym_
200281 func_name = call .func .id
201282 if func_name in helper_func_list :
202283 # it is not a map method call
203- return helper_func_list [func_name ](call , module , builder , func )
284+ return helper_func_list [func_name ](call , None , module , builder , func , local_sym_tab )
204285 else :
205286 raise NotImplementedError (
206287 f"Function { func_name } is not implemented as a helper function." )
0 commit comments