1
1
import ast
2
2
from llvmlite import ir
3
+ from .expr_pass import eval_expr
3
4
4
5
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 ):
6
7
"""
7
8
Emit LLVM IR for bpf_ktime_get_ns helper function call.
8
9
"""
@@ -62,10 +63,87 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
62
63
return result
63
64
64
65
65
- def bpf_printk_emitter (call , module , builder , func ):
66
+ def bpf_printk_emitter (call , map_ptr , module , builder , func , local_sym_tab = None ):
66
67
if not hasattr (func , "_fmt_counter" ):
67
68
func ._fmt_counter = 0
68
69
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
+
69
147
for arg in call .args :
70
148
if isinstance (arg , ast .Constant ) and isinstance (arg .value , str ):
71
149
fmt_str = arg .value + "\n " + "\0 "
@@ -93,6 +171,7 @@ def bpf_printk_emitter(call, module, builder, func):
93
171
builder .call (fn_ptr , [fmt_ptr , ir .Constant (
94
172
ir .IntType (32 ), len (fmt_str ))], tail = True )
95
173
174
+
96
175
def bpf_map_update_elem_emitter (call , map_ptr , module , builder , local_sym_tab = None ):
97
176
"""
98
177
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
101
180
if not call .args or len (call .args ) < 2 or len (call .args ) > 3 :
102
181
raise ValueError ("Map update expects 2 or 3 arguments (key, value, flags), got "
103
182
f"{ len (call .args )} " )
104
-
183
+
105
184
key_arg = call .args [0 ]
106
185
value_arg = call .args [1 ]
107
186
flags_arg = call .args [2 ] if len (call .args ) > 2 else None
108
-
187
+
109
188
# Handle key
110
189
if isinstance (key_arg , ast .Name ):
111
190
key_name = key_arg .id
@@ -124,7 +203,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
124
203
else :
125
204
raise NotImplementedError (
126
205
"Only simple variable names and integer constants are supported as keys in map update." )
127
-
206
+
128
207
# Handle value
129
208
if isinstance (value_arg , ast .Name ):
130
209
value_name = value_arg .id
@@ -143,7 +222,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
143
222
else :
144
223
raise NotImplementedError (
145
224
"Only simple variable names and integer constants are supported as values in map update." )
146
-
225
+
147
226
# Handle flags argument (defaults to 0)
148
227
if flags_arg is not None :
149
228
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
162
241
"Only integer constants and simple variable names are supported as flags in map update." )
163
242
else :
164
243
flags_val = 0
165
-
244
+
166
245
if key_ptr is None or value_ptr is None :
167
246
raise ValueError ("Key pointer or value pointer is None." )
168
247
@@ -173,20 +252,22 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, local_sym_tab=No
173
252
var_arg = False
174
253
)
175
254
fn_ptr_type = ir .PointerType (fn_type )
176
-
255
+
177
256
# helper id
178
257
fn_addr = ir .Constant (ir .IntType (64 ), 2 )
179
258
fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
180
-
259
+
181
260
if isinstance (flags_val , int ):
182
261
flags_const = ir .Constant (ir .IntType (64 ), flags_val )
183
262
else :
184
263
flags_const = flags_val
185
264
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
+
188
268
return result
189
269
270
+
190
271
helper_func_list = {
191
272
"lookup" : bpf_map_lookup_elem_emitter ,
192
273
"print" : bpf_printk_emitter ,
@@ -200,7 +281,7 @@ def handle_helper_call(call, module, builder, func, local_sym_tab=None, map_sym_
200
281
func_name = call .func .id
201
282
if func_name in helper_func_list :
202
283
# 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 )
204
285
else :
205
286
raise NotImplementedError (
206
287
f"Function { func_name } is not implemented as a helper function." )
0 commit comments