Skip to content

Commit 13a804f

Browse files
committed
Implement bpf_get_current_comm_emitter
1 parent a0d954b commit 13a804f

File tree

4 files changed

+100
-4
lines changed

4 files changed

+100
-4
lines changed

BCC-Examples/hello_perf_output.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pythonbpf import bpf, map, struct, section, bpfglobal, compile
2-
from pythonbpf.helper import ktime, pid
2+
from pythonbpf.helper import ktime, pid, comm
33
from pythonbpf.maps import PerfEventArray
44

55
from ctypes import c_void_p, c_int64, c_uint64
@@ -25,7 +25,7 @@ def hello(ctx: c_void_p) -> c_int64:
2525
dataobj = data_t()
2626
strobj = "hellohellohello"
2727
dataobj.pid, dataobj.ts = pid(), ktime()
28-
# get_curr_comm(dataobj.comm)
28+
comm(dataobj.comm)
2929
print(f"clone called at {dataobj.ts} by pid {dataobj.pid}, comm {strobj}")
3030
events.output(dataobj)
3131
return 0 # type: ignore [return-value]

pythonbpf/helper/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .helper_registry import HelperHandlerRegistry
22
from .helper_utils import reset_scratch_pool
33
from .bpf_helper_handler import handle_helper_call
4-
from .helpers import ktime, pid, deref, XDP_DROP, XDP_PASS
4+
from .helpers import ktime, pid, deref, comm, XDP_DROP, XDP_PASS
55

66

77
# Register the helper handler with expr module
@@ -62,6 +62,7 @@ def helper_call_handler(
6262
"ktime",
6363
"pid",
6464
"deref",
65+
"comm",
6566
"XDP_DROP",
6667
"XDP_PASS",
6768
]

pythonbpf/helper/bpf_helper_handler.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
get_or_create_ptr_from_arg,
88
get_flags_val,
99
get_data_ptr_and_size,
10+
get_buffer_ptr_and_size,
1011
)
1112
from .printk_formatter import simple_string_print, handle_fstring_print
1213

@@ -248,8 +249,48 @@ def bpf_get_current_comm_emitter(
248249
):
249250
"""
250251
Emit LLVM IR for bpf_get_current_comm helper function call.
252+
253+
Accepts: comm(dataobj.field) or comm(my_buffer)
251254
"""
252-
pass # Not implemented yet
255+
if not call.args or len(call.args) != 1:
256+
raise ValueError(
257+
f"comm expects exactly one argument (buffer), got {len(call.args)}"
258+
)
259+
260+
buf_arg = call.args[0]
261+
262+
# Extract buffer pointer and size
263+
buf_ptr, buf_size = get_buffer_ptr_and_size(
264+
buf_arg, builder, local_sym_tab, struct_sym_tab
265+
)
266+
267+
# Validate it's a char array
268+
if not isinstance(
269+
buf_ptr.type.pointee, ir.ArrayType
270+
) or buf_ptr.type.pointee.element != ir.IntType(8):
271+
raise ValueError(
272+
f"comm expects a char array buffer, got {buf_ptr.type.pointee}"
273+
)
274+
275+
# Cast to void* and call helper
276+
buf_void_ptr = builder.bitcast(buf_ptr, ir.PointerType())
277+
278+
fn_type = ir.FunctionType(
279+
ir.IntType(64),
280+
[ir.PointerType(), ir.IntType(32)],
281+
var_arg=False,
282+
)
283+
fn_ptr = builder.inttoptr(
284+
ir.Constant(ir.IntType(64), BPFHelperID.BPF_GET_CURRENT_COMM.value),
285+
ir.PointerType(fn_type),
286+
)
287+
288+
result = builder.call(
289+
fn_ptr, [buf_void_ptr, ir.Constant(ir.IntType(32), buf_size)], tail=False
290+
)
291+
292+
logger.info(f"Emitted bpf_get_current_comm with {buf_size} byte buffer")
293+
return result, None
253294

254295

255296
@HelperHandlerRegistry.register("pid")

pythonbpf/helper/helper_utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,57 @@ def get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab):
136136
raise NotImplementedError(
137137
"Only simple object names are supported as data in perf event output."
138138
)
139+
140+
141+
def get_buffer_ptr_and_size(buf_arg, builder, local_sym_tab, struct_sym_tab):
142+
"""Extract buffer pointer and size from either a struct field or variable."""
143+
144+
# Case 1: Struct field (obj.field)
145+
if isinstance(buf_arg, ast.Attribute):
146+
if not isinstance(buf_arg.value, ast.Name):
147+
raise ValueError(
148+
"Only simple struct field access supported (e.g., obj.field)"
149+
)
150+
151+
struct_name = buf_arg.value.id
152+
field_name = buf_arg.attr
153+
154+
# Lookup struct
155+
if not local_sym_tab or struct_name not in local_sym_tab:
156+
raise ValueError(f"Struct '{struct_name}' not found")
157+
158+
struct_type = local_sym_tab[struct_name].metadata
159+
if not struct_sym_tab or struct_type not in struct_sym_tab:
160+
raise ValueError(f"Struct type '{struct_type}' not found")
161+
162+
struct_info = struct_sym_tab[struct_type]
163+
164+
# Get field pointer and type
165+
struct_ptr = local_sym_tab[struct_name].var
166+
field_ptr = struct_info.gep(builder, struct_ptr, field_name)
167+
field_type = struct_info.field_type(field_name)
168+
169+
if not isinstance(field_type, ir.ArrayType):
170+
raise ValueError(f"Field '{field_name}' must be an array type")
171+
172+
return field_ptr, field_type.count
173+
174+
# Case 2: Variable name
175+
elif isinstance(buf_arg, ast.Name):
176+
var_name = buf_arg.id
177+
178+
if not local_sym_tab or var_name not in local_sym_tab:
179+
raise ValueError(f"Variable '{var_name}' not found")
180+
181+
var_ptr = local_sym_tab[var_name].var
182+
var_type = local_sym_tab[var_name].ir_type
183+
184+
if not isinstance(var_type, ir.ArrayType):
185+
raise ValueError(f"Variable '{var_name}' must be an array type")
186+
187+
return var_ptr, var_type.count
188+
189+
else:
190+
raise ValueError(
191+
"comm expects either a struct field (obj.field) or variable name"
192+
)

0 commit comments

Comments
 (0)