1212 get_int_value_from_arg ,
1313)
1414from .printk_formatter import simple_string_print , handle_fstring_print
15-
16- from logging import Logger
15+ from pythonbpf .maps import BPFMapType
1716import logging
1817
19- logger : Logger = logging .getLogger (__name__ )
18+ logger = logging .getLogger (__name__ )
2019
2120
2221class BPFHelperID (Enum ):
@@ -33,7 +32,12 @@ class BPFHelperID(Enum):
3332 BPF_GET_CURRENT_UID_GID = 15
3433 BPF_GET_CURRENT_COMM = 16
3534 BPF_PERF_EVENT_OUTPUT = 25
35+ BPF_GET_STACK = 67
3636 BPF_PROBE_READ_KERNEL_STR = 115
37+ BPF_RINGBUF_OUTPUT = 130
38+ BPF_RINGBUF_RESERVE = 131
39+ BPF_RINGBUF_SUBMIT = 132
40+ BPF_RINGBUF_DISCARD = 133
3741
3842
3943@HelperHandlerRegistry .register (
@@ -358,11 +362,6 @@ def bpf_get_current_pid_tgid_emitter(
358362 return pid , ir .IntType (64 )
359363
360364
361- @HelperHandlerRegistry .register (
362- "output" ,
363- param_types = [ir .PointerType (ir .IntType (8 ))],
364- return_type = ir .IntType (64 ),
365- )
366365def bpf_perf_event_output_handler (
367366 call ,
368367 map_ptr ,
@@ -373,6 +372,10 @@ def bpf_perf_event_output_handler(
373372 struct_sym_tab = None ,
374373 map_sym_tab = None ,
375374):
375+ """
376+ Emit LLVM IR for bpf_perf_event_output helper function call.
377+ """
378+
376379 if len (call .args ) != 1 :
377380 raise ValueError (
378381 f"Perf event output expects exactly one argument, got { len (call .args )} "
@@ -410,6 +413,98 @@ def bpf_perf_event_output_handler(
410413 return result , None
411414
412415
416+ def bpf_ringbuf_output_emitter (
417+ call ,
418+ map_ptr ,
419+ module ,
420+ builder ,
421+ func ,
422+ local_sym_tab = None ,
423+ struct_sym_tab = None ,
424+ map_sym_tab = None ,
425+ ):
426+ """
427+ Emit LLVM IR for bpf_ringbuf_output helper function call.
428+ """
429+
430+ if len (call .args ) != 1 :
431+ raise ValueError (
432+ f"Ringbuf output expects exactly one argument, got { len (call .args )} "
433+ )
434+ data_arg = call .args [0 ]
435+ data_ptr , size_val = get_data_ptr_and_size (data_arg , local_sym_tab , struct_sym_tab )
436+ flags_val = ir .Constant (ir .IntType (64 ), 0 )
437+
438+ map_void_ptr = builder .bitcast (map_ptr , ir .PointerType ())
439+ data_void_ptr = builder .bitcast (data_ptr , ir .PointerType ())
440+ fn_type = ir .FunctionType (
441+ ir .IntType (64 ),
442+ [
443+ ir .PointerType (),
444+ ir .PointerType (),
445+ ir .IntType (64 ),
446+ ir .IntType (64 ),
447+ ],
448+ var_arg = False ,
449+ )
450+ fn_ptr_type = ir .PointerType (fn_type )
451+
452+ # helper id
453+ fn_addr = ir .Constant (ir .IntType (64 ), BPFHelperID .BPF_RINGBUF_OUTPUT .value )
454+ fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
455+
456+ result = builder .call (
457+ fn_ptr , [map_void_ptr , data_void_ptr , size_val , flags_val ], tail = False
458+ )
459+ return result , None
460+
461+
462+ @HelperHandlerRegistry .register (
463+ "output" ,
464+ param_types = [ir .PointerType (ir .IntType (8 ))],
465+ return_type = ir .IntType (64 ),
466+ )
467+ def handle_output_helper (
468+ call ,
469+ map_ptr ,
470+ module ,
471+ builder ,
472+ func ,
473+ local_sym_tab = None ,
474+ struct_sym_tab = None ,
475+ map_sym_tab = None ,
476+ ):
477+ """
478+ Route output helper to the appropriate emitter based on map type.
479+ """
480+ match map_sym_tab [map_ptr .name ].type :
481+ case BPFMapType .PERF_EVENT_ARRAY :
482+ return bpf_perf_event_output_handler (
483+ call ,
484+ map_ptr ,
485+ module ,
486+ builder ,
487+ func ,
488+ local_sym_tab ,
489+ struct_sym_tab ,
490+ map_sym_tab ,
491+ )
492+ case BPFMapType .RINGBUF :
493+ return bpf_ringbuf_output_emitter (
494+ call ,
495+ map_ptr ,
496+ module ,
497+ builder ,
498+ func ,
499+ local_sym_tab ,
500+ struct_sym_tab ,
501+ map_sym_tab ,
502+ )
503+ case _:
504+ logger .error ("Unsupported map type for output helper." )
505+ raise NotImplementedError ("Output helper for this map type is not implemented." )
506+
507+
413508def emit_probe_read_kernel_str_call (builder , dst_ptr , dst_size , src_ptr ):
414509 """Emit LLVM IR call to bpf_probe_read_kernel_str"""
415510
@@ -711,7 +806,10 @@ def bpf_skb_store_bytes_emitter(
711806 flags_val = get_flags_val (call .args [3 ], builder , local_sym_tab )
712807 else :
713808 flags_val = 0
714- flags = ir .Constant (ir .IntType (64 ), flags_val )
809+ if isinstance (flags_val , int ):
810+ flags = ir .Constant (ir .IntType (64 ), flags_val )
811+ else :
812+ flags = flags_val
715813 fn_type = ir .FunctionType (
716814 ir .IntType (64 ),
717815 args_signature ,
@@ -736,6 +834,170 @@ def bpf_skb_store_bytes_emitter(
736834 return result , ir .IntType (64 )
737835
738836
837+ @HelperHandlerRegistry .register (
838+ "reserve" ,
839+ param_types = [ir .IntType (64 )],
840+ return_type = ir .PointerType (ir .IntType (8 )),
841+ )
842+ def bpf_ringbuf_reserve_emitter (
843+ call ,
844+ map_ptr ,
845+ module ,
846+ builder ,
847+ func ,
848+ local_sym_tab = None ,
849+ struct_sym_tab = None ,
850+ map_sym_tab = None ,
851+ ):
852+ """
853+ Emit LLVM IR for bpf_ringbuf_reserve helper function call.
854+ Expected call signature: ringbuf.reserve(size)
855+ """
856+
857+ if len (call .args ) != 1 :
858+ raise ValueError (
859+ f"ringbuf.reserve expects exactly one argument (size), got { len (call .args )} "
860+ )
861+
862+ size_val = get_int_value_from_arg (
863+ call .args [0 ],
864+ func ,
865+ module ,
866+ builder ,
867+ local_sym_tab ,
868+ map_sym_tab ,
869+ struct_sym_tab ,
870+ )
871+
872+ map_void_ptr = builder .bitcast (map_ptr , ir .PointerType ())
873+ fn_type = ir .FunctionType (
874+ ir .PointerType (ir .IntType (8 )),
875+ [ir .PointerType (), ir .IntType (64 )],
876+ var_arg = False ,
877+ )
878+ fn_ptr_type = ir .PointerType (fn_type )
879+
880+ fn_addr = ir .Constant (ir .IntType (64 ), BPFHelperID .BPF_RINGBUF_RESERVE .value )
881+ fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
882+
883+ result = builder .call (fn_ptr , [map_void_ptr , size_val ], tail = False )
884+
885+ return result , ir .PointerType (ir .IntType (8 ))
886+
887+
888+ @HelperHandlerRegistry .register (
889+ "submit" ,
890+ param_types = [ir .PointerType (ir .IntType (8 )), ir .IntType (64 )],
891+ return_type = ir .VoidType (),
892+ )
893+ def bpf_ringbuf_submit_emitter (
894+ call ,
895+ map_ptr ,
896+ module ,
897+ builder ,
898+ func ,
899+ local_sym_tab = None ,
900+ struct_sym_tab = None ,
901+ map_sym_tab = None ,
902+ ):
903+ """
904+ Emit LLVM IR for bpf_ringbuf_submit helper function call.
905+ Expected call signature: ringbuf.submit(data, flags=0)
906+ """
907+
908+ if len (call .args ) not in (1 , 2 ):
909+ raise ValueError (
910+ f"ringbuf.submit expects 1 or 2 args (data, flags), got { len (call .args )} "
911+ )
912+
913+ data_arg = call .args [0 ]
914+ flags_arg = call .args [1 ] if len (call .args ) == 2 else None
915+
916+ data_ptr = get_or_create_ptr_from_arg (
917+ func ,
918+ module ,
919+ data_arg ,
920+ builder ,
921+ local_sym_tab ,
922+ map_sym_tab ,
923+ struct_sym_tab ,
924+ ir .PointerType (ir .IntType (8 )),
925+ )
926+
927+ flags_const = get_flags_val (flags_arg , builder , local_sym_tab )
928+ if isinstance (flags_const , int ):
929+ flags_const = ir .Constant (ir .IntType (64 ), flags_const )
930+
931+ map_void_ptr = builder .bitcast (map_ptr , ir .PointerType ())
932+ fn_type = ir .FunctionType (
933+ ir .VoidType (),
934+ [ir .PointerType (), ir .PointerType (), ir .IntType (64 )],
935+ var_arg = False ,
936+ )
937+ fn_ptr_type = ir .PointerType (fn_type )
938+
939+ fn_addr = ir .Constant (ir .IntType (64 ), BPFHelperID .BPF_RINGBUF_SUBMIT .value )
940+ fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
941+
942+ result = builder .call (fn_ptr , [map_void_ptr , data_ptr , flags_const ], tail = False )
943+
944+ return result , None
945+
946+
947+ @HelperHandlerRegistry .register (
948+ "get_stack" ,
949+ param_types = [ir .PointerType (ir .IntType (8 )), ir .IntType (64 )],
950+ return_type = ir .IntType (64 ),
951+ )
952+ def bpf_get_stack_emitter (
953+ call ,
954+ map_ptr ,
955+ module ,
956+ builder ,
957+ func ,
958+ local_sym_tab = None ,
959+ struct_sym_tab = None ,
960+ map_sym_tab = None ,
961+ ):
962+ """
963+ Emit LLVM IR for bpf_get_stack helper function call.
964+ """
965+ if len (call .args ) not in (1 , 2 ):
966+ raise ValueError (
967+ f"get_stack expects atmost two arguments (buf, flags), got { len (call .args )} "
968+ )
969+ ctx_ptr = func .args [0 ] # First argument to the function is ctx
970+ buf_arg = call .args [0 ]
971+ flags_arg = call .args [1 ] if len (call .args ) == 2 else None
972+ buf_ptr , buf_size = get_buffer_ptr_and_size (
973+ buf_arg , builder , local_sym_tab , struct_sym_tab
974+ )
975+ flags_val = get_flags_val (flags_arg , builder , local_sym_tab )
976+ if isinstance (flags_val , int ):
977+ flags_val = ir .Constant (ir .IntType (64 ), flags_val )
978+
979+ buf_void_ptr = builder .bitcast (buf_ptr , ir .PointerType ())
980+ fn_type = ir .FunctionType (
981+ ir .IntType (64 ),
982+ [
983+ ir .PointerType (ir .IntType (8 )),
984+ ir .PointerType (),
985+ ir .IntType (64 ),
986+ ir .IntType (64 ),
987+ ],
988+ var_arg = False ,
989+ )
990+ fn_ptr_type = ir .PointerType (fn_type )
991+ fn_addr = ir .Constant (ir .IntType (64 ), BPFHelperID .BPF_GET_STACK .value )
992+ fn_ptr = builder .inttoptr (fn_addr , fn_ptr_type )
993+ result = builder .call (
994+ fn_ptr ,
995+ [ctx_ptr , buf_void_ptr , ir .Constant (ir .IntType (64 ), buf_size ), flags_val ],
996+ tail = False ,
997+ )
998+ return result , ir .IntType (64 )
999+
1000+
7391001def handle_helper_call (
7401002 call ,
7411003 module ,
@@ -790,6 +1052,6 @@ def invoke_helper(method_name, map_ptr=None):
7901052 if not map_sym_tab or map_name not in map_sym_tab :
7911053 raise ValueError (f"Map '{ map_name } ' not found in symbol table" )
7921054
793- return invoke_helper (method_name , map_sym_tab [map_name ])
1055+ return invoke_helper (method_name , map_sym_tab [map_name ]. sym )
7941056
7951057 return None
0 commit comments