|
3 | 3 |
|
4 | 4 | from llvmlite import ir |
5 | 5 | from pythonbpf.expr import ( |
6 | | - eval_expr, |
7 | | - get_base_type_and_depth, |
8 | | - deref_to_depth, |
9 | 6 | get_operand_value, |
10 | 7 | ) |
11 | 8 |
|
@@ -47,6 +44,11 @@ def reset_scratch_pool(): |
47 | 44 | _temp_pool_manager.reset() |
48 | 45 |
|
49 | 46 |
|
| 47 | +# ============================================================================ |
| 48 | +# Argument Preparation |
| 49 | +# ============================================================================ |
| 50 | + |
| 51 | + |
50 | 52 | def get_var_ptr_from_name(var_name, local_sym_tab): |
51 | 53 | """Get a pointer to a variable from the symbol table.""" |
52 | 54 | if local_sym_tab and var_name in local_sym_tab: |
@@ -111,234 +113,6 @@ def get_flags_val(arg, builder, local_sym_tab): |
111 | 113 | ) |
112 | 114 |
|
113 | 115 |
|
114 | | -def simple_string_print(string_value, module, builder, func): |
115 | | - """Prepare arguments for bpf_printk from a simple string value""" |
116 | | - fmt_str = string_value + "\n\0" |
117 | | - fmt_ptr = _create_format_string_global(fmt_str, func, module, builder) |
118 | | - |
119 | | - args = [fmt_ptr, ir.Constant(ir.IntType(32), len(fmt_str))] |
120 | | - return args |
121 | | - |
122 | | - |
123 | | -def handle_fstring_print( |
124 | | - joined_str, |
125 | | - module, |
126 | | - builder, |
127 | | - func, |
128 | | - local_sym_tab=None, |
129 | | - struct_sym_tab=None, |
130 | | -): |
131 | | - """Handle f-string formatting for bpf_printk emitter.""" |
132 | | - fmt_parts = [] |
133 | | - exprs = [] |
134 | | - |
135 | | - for value in joined_str.values: |
136 | | - logger.debug(f"Processing f-string value: {ast.dump(value)}") |
137 | | - |
138 | | - if isinstance(value, ast.Constant): |
139 | | - _process_constant_in_fstring(value, fmt_parts, exprs) |
140 | | - elif isinstance(value, ast.FormattedValue): |
141 | | - _process_fval( |
142 | | - value, |
143 | | - fmt_parts, |
144 | | - exprs, |
145 | | - local_sym_tab, |
146 | | - struct_sym_tab, |
147 | | - ) |
148 | | - else: |
149 | | - raise NotImplementedError(f"Unsupported f-string value type: {type(value)}") |
150 | | - |
151 | | - fmt_str = "".join(fmt_parts) |
152 | | - args = simple_string_print(fmt_str, module, builder, func) |
153 | | - |
154 | | - # NOTE: Process expressions (limited to 3 due to BPF constraints) |
155 | | - if len(exprs) > 3: |
156 | | - logger.warning("bpf_printk supports up to 3 args, extra args will be ignored.") |
157 | | - |
158 | | - for expr in exprs[:3]: |
159 | | - arg_value = _prepare_expr_args( |
160 | | - expr, |
161 | | - func, |
162 | | - module, |
163 | | - builder, |
164 | | - local_sym_tab, |
165 | | - struct_sym_tab, |
166 | | - ) |
167 | | - args.append(arg_value) |
168 | | - |
169 | | - return args |
170 | | - |
171 | | - |
172 | | -def _process_constant_in_fstring(cst, fmt_parts, exprs): |
173 | | - """Process constant values in f-string.""" |
174 | | - if isinstance(cst.value, str): |
175 | | - fmt_parts.append(cst.value) |
176 | | - elif isinstance(cst.value, int): |
177 | | - fmt_parts.append("%lld") |
178 | | - exprs.append(ir.Constant(ir.IntType(64), cst.value)) |
179 | | - else: |
180 | | - raise NotImplementedError( |
181 | | - f"Unsupported constant type in f-string: {type(cst.value)}" |
182 | | - ) |
183 | | - |
184 | | - |
185 | | -def _process_fval(fval, fmt_parts, exprs, local_sym_tab, struct_sym_tab): |
186 | | - """Process formatted values in f-string.""" |
187 | | - logger.debug(f"Processing formatted value: {ast.dump(fval)}") |
188 | | - |
189 | | - if isinstance(fval.value, ast.Name): |
190 | | - _process_name_in_fval(fval.value, fmt_parts, exprs, local_sym_tab) |
191 | | - elif isinstance(fval.value, ast.Attribute): |
192 | | - _process_attr_in_fval( |
193 | | - fval.value, |
194 | | - fmt_parts, |
195 | | - exprs, |
196 | | - local_sym_tab, |
197 | | - struct_sym_tab, |
198 | | - ) |
199 | | - else: |
200 | | - raise NotImplementedError( |
201 | | - f"Unsupported formatted value in f-string: {type(fval.value)}" |
202 | | - ) |
203 | | - |
204 | | - |
205 | | -def _process_name_in_fval(name_node, fmt_parts, exprs, local_sym_tab): |
206 | | - """Process name nodes in formatted values.""" |
207 | | - if local_sym_tab and name_node.id in local_sym_tab: |
208 | | - _, var_type, tmp = local_sym_tab[name_node.id] |
209 | | - _populate_fval(var_type, name_node, fmt_parts, exprs) |
210 | | - |
211 | | - |
212 | | -def _process_attr_in_fval(attr_node, fmt_parts, exprs, local_sym_tab, struct_sym_tab): |
213 | | - """Process attribute nodes in formatted values.""" |
214 | | - if ( |
215 | | - isinstance(attr_node.value, ast.Name) |
216 | | - and local_sym_tab |
217 | | - and attr_node.value.id in local_sym_tab |
218 | | - ): |
219 | | - var_name = attr_node.value.id |
220 | | - field_name = attr_node.attr |
221 | | - |
222 | | - var_type = local_sym_tab[var_name].metadata |
223 | | - if var_type not in struct_sym_tab: |
224 | | - raise ValueError( |
225 | | - f"Struct '{var_type}' for '{var_name}' not in symbol table" |
226 | | - ) |
227 | | - |
228 | | - struct_info = struct_sym_tab[var_type] |
229 | | - if field_name not in struct_info.fields: |
230 | | - raise ValueError(f"Field '{field_name}' not found in struct '{var_type}'") |
231 | | - |
232 | | - field_type = struct_info.field_type(field_name) |
233 | | - _populate_fval(field_type, attr_node, fmt_parts, exprs) |
234 | | - else: |
235 | | - raise NotImplementedError( |
236 | | - "Only simple attribute on local vars is supported in f-strings." |
237 | | - ) |
238 | | - |
239 | | - |
240 | | -def _populate_fval(ftype, node, fmt_parts, exprs): |
241 | | - """Populate format parts and expressions based on field type.""" |
242 | | - if isinstance(ftype, ir.IntType): |
243 | | - # TODO: We print as signed integers only for now |
244 | | - if ftype.width == 64: |
245 | | - fmt_parts.append("%lld") |
246 | | - exprs.append(node) |
247 | | - elif ftype.width == 32: |
248 | | - fmt_parts.append("%d") |
249 | | - exprs.append(node) |
250 | | - else: |
251 | | - raise NotImplementedError( |
252 | | - f"Unsupported integer width in f-string: {ftype.width}" |
253 | | - ) |
254 | | - elif isinstance(ftype, ir.PointerType): |
255 | | - target, depth = get_base_type_and_depth(ftype) |
256 | | - if isinstance(target, ir.IntType): |
257 | | - if target.width == 64: |
258 | | - fmt_parts.append("%lld") |
259 | | - exprs.append(node) |
260 | | - elif target.width == 32: |
261 | | - fmt_parts.append("%d") |
262 | | - exprs.append(node) |
263 | | - elif target.width == 8 and depth == 1: |
264 | | - # NOTE: Assume i8* is a string |
265 | | - fmt_parts.append("%s") |
266 | | - exprs.append(node) |
267 | | - else: |
268 | | - raise NotImplementedError( |
269 | | - f"Unsupported pointer target type in f-string: {target}" |
270 | | - ) |
271 | | - else: |
272 | | - raise NotImplementedError( |
273 | | - f"Unsupported pointer target type in f-string: {target}" |
274 | | - ) |
275 | | - else: |
276 | | - raise NotImplementedError(f"Unsupported field type in f-string: {ftype}") |
277 | | - |
278 | | - |
279 | | -def _create_format_string_global(fmt_str, func, module, builder): |
280 | | - """Create a global variable for the format string.""" |
281 | | - fmt_name = f"{func.name}____fmt{func._fmt_counter}" |
282 | | - func._fmt_counter += 1 |
283 | | - |
284 | | - fmt_gvar = ir.GlobalVariable( |
285 | | - module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=fmt_name |
286 | | - ) |
287 | | - fmt_gvar.global_constant = True |
288 | | - fmt_gvar.initializer = ir.Constant( |
289 | | - ir.ArrayType(ir.IntType(8), len(fmt_str)), bytearray(fmt_str.encode("utf8")) |
290 | | - ) |
291 | | - fmt_gvar.linkage = "internal" |
292 | | - fmt_gvar.align = 1 |
293 | | - |
294 | | - return builder.bitcast(fmt_gvar, ir.PointerType()) |
295 | | - |
296 | | - |
297 | | -def _prepare_expr_args(expr, func, module, builder, local_sym_tab, struct_sym_tab): |
298 | | - """Evaluate and prepare an expression to use as an arg for bpf_printk.""" |
299 | | - val, _ = eval_expr( |
300 | | - func, |
301 | | - module, |
302 | | - builder, |
303 | | - expr, |
304 | | - local_sym_tab, |
305 | | - None, |
306 | | - struct_sym_tab, |
307 | | - ) |
308 | | - |
309 | | - if val: |
310 | | - if isinstance(val.type, ir.PointerType): |
311 | | - target, depth = get_base_type_and_depth(val.type) |
312 | | - if isinstance(target, ir.IntType): |
313 | | - if target.width >= 32: |
314 | | - val = deref_to_depth(func, builder, val, depth) |
315 | | - val = builder.sext(val, ir.IntType(64)) |
316 | | - elif target.width == 8 and depth == 1: |
317 | | - # NOTE: i8* is string, no need to deref |
318 | | - pass |
319 | | - |
320 | | - else: |
321 | | - logger.warning( |
322 | | - "Only int and ptr supported in bpf_printk args. Others default to 0." |
323 | | - ) |
324 | | - val = ir.Constant(ir.IntType(64), 0) |
325 | | - elif isinstance(val.type, ir.IntType): |
326 | | - if val.type.width < 64: |
327 | | - val = builder.sext(val, ir.IntType(64)) |
328 | | - else: |
329 | | - logger.warning( |
330 | | - "Only int and ptr supported in bpf_printk args. Others default to 0." |
331 | | - ) |
332 | | - val = ir.Constant(ir.IntType(64), 0) |
333 | | - return val |
334 | | - else: |
335 | | - logger.warning( |
336 | | - "Failed to evaluate expression for bpf_printk argument. " |
337 | | - "It will be converted to 0." |
338 | | - ) |
339 | | - return ir.Constant(ir.IntType(64), 0) |
340 | | - |
341 | | - |
342 | 116 | def get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab): |
343 | 117 | """Extract data pointer and size information for perf event output.""" |
344 | 118 | if isinstance(data_arg, ast.Name): |
|
0 commit comments