Skip to content

Commit 5b20b08

Browse files
Add docstrings to core modules and helper functions
Co-authored-by: varun-r-mallya <100590632+varun-r-mallya@users.noreply.github.com>
1 parent 9f103c3 commit 5b20b08

File tree

14 files changed

+532
-11
lines changed

14 files changed

+532
-11
lines changed

pythonbpf/binary_ops.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ def get_operand_value(operand, builder, local_sym_tab):
3535

3636

3737
def handle_binary_op_impl(rval, builder, local_sym_tab):
38+
"""
39+
Handle binary operations and emit corresponding LLVM IR instructions.
40+
41+
Args:
42+
rval: The AST BinOp node representing the binary operation
43+
builder: LLVM IR builder for emitting instructions
44+
local_sym_tab: Symbol table mapping variable names to their IR representations
45+
46+
Returns:
47+
The LLVM IR value representing the result of the binary operation
48+
"""
3849
op = rval.op
3950
left = get_operand_value(rval.left, builder, local_sym_tab)
4051
right = get_operand_value(rval.right, builder, local_sym_tab)
@@ -63,6 +74,18 @@ def handle_binary_op_impl(rval, builder, local_sym_tab):
6374

6475

6576
def handle_binary_op(rval, builder, var_name, local_sym_tab):
77+
"""
78+
Handle binary operations and optionally store the result to a variable.
79+
80+
Args:
81+
rval: The AST BinOp node representing the binary operation
82+
builder: LLVM IR builder for emitting instructions
83+
var_name: Optional variable name to store the result
84+
local_sym_tab: Symbol table mapping variable names to their IR representations
85+
86+
Returns:
87+
A tuple of (result_value, result_type)
88+
"""
6689
result = handle_binary_op_impl(rval, builder, local_sym_tab)
6790
if var_name and var_name in local_sym_tab:
6891
logger.info(

pythonbpf/codegen.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ def find_bpf_chunks(tree):
3737

3838

3939
def processor(source_code, filename, module):
40+
"""
41+
Process Python source code and convert BPF-decorated functions to LLVM IR.
42+
43+
Args:
44+
source_code: The Python source code to process
45+
filename: The name of the source file
46+
module: The LLVM IR module to populate
47+
"""
4048
tree = ast.parse(source_code, filename)
4149
logger.debug(ast.dump(tree, indent=4))
4250

@@ -56,6 +64,17 @@ def processor(source_code, filename, module):
5664

5765

5866
def compile_to_ir(filename: str, output: str, loglevel=logging.INFO):
67+
"""
68+
Compile a Python BPF program to LLVM IR.
69+
70+
Args:
71+
filename: Path to the Python source file containing BPF programs
72+
output: Path where the LLVM IR (.ll) file will be written
73+
loglevel: Logging level for compilation messages
74+
75+
Returns:
76+
Path to the generated LLVM IR file
77+
"""
5978
logging.basicConfig(
6079
level=loglevel, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
6180
)
@@ -129,6 +148,18 @@ def compile_to_ir(filename: str, output: str, loglevel=logging.INFO):
129148

130149

131150
def compile(loglevel=logging.INFO) -> bool:
151+
"""
152+
Compile the calling Python BPF program to an object file.
153+
154+
This function should be called from a Python file containing BPF programs.
155+
It will compile the calling file to LLVM IR and then to a BPF object file.
156+
157+
Args:
158+
loglevel: Logging level for compilation messages
159+
160+
Returns:
161+
True if compilation succeeded, False otherwise
162+
"""
132163
# Look one level up the stack to the caller of this function
133164
caller_frame = inspect.stack()[1]
134165
caller_file = Path(caller_frame.filename).resolve()
@@ -162,6 +193,18 @@ def compile(loglevel=logging.INFO) -> bool:
162193

163194

164195
def BPF(loglevel=logging.INFO) -> BpfProgram:
196+
"""
197+
Compile the calling Python BPF program and return a BpfProgram object.
198+
199+
This function compiles the calling file's BPF programs to an object file
200+
and loads it into a BpfProgram object for immediate use.
201+
202+
Args:
203+
loglevel: Logging level for compilation messages
204+
205+
Returns:
206+
A BpfProgram object that can be used to load and attach BPF programs
207+
"""
165208
caller_frame = inspect.stack()[1]
166209
src = inspect.getsource(caller_frame.frame)
167210
with tempfile.NamedTemporaryFile(

pythonbpf/decorators.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ def struct(cls):
2323

2424

2525
def section(name: str):
26+
"""
27+
Decorator to specify the ELF section name for a BPF program.
28+
29+
Args:
30+
name: The section name (e.g., 'xdp', 'tracepoint/syscalls/sys_enter_execve')
31+
32+
Returns:
33+
A decorator function that marks the function with the section name
34+
"""
2635
def wrapper(fn):
2736
fn._section = name
2837
return fn

pythonbpf/expr/expr_pass.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,21 @@ def eval_expr(
332332
map_sym_tab,
333333
structs_sym_tab=None,
334334
):
335+
"""
336+
Evaluate an expression and return its LLVM IR value and type.
337+
338+
Args:
339+
func: The LLVM IR function being built
340+
module: The LLVM IR module
341+
builder: LLVM IR builder
342+
expr: The AST expression node to evaluate
343+
local_sym_tab: Local symbol table
344+
map_sym_tab: Map symbol table
345+
structs_sym_tab: Struct symbol table
346+
347+
Returns:
348+
A tuple of (value, type) or None if evaluation fails
349+
"""
335350
logger.info(f"Evaluating expression: {ast.dump(expr)}")
336351
if isinstance(expr, ast.Name):
337352
return _handle_name_expr(expr, local_sym_tab, builder)

pythonbpf/expr/type_normalization.py

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,15 @@
1717

1818

1919
def _get_base_type_and_depth(ir_type):
20-
"""Get the base type for pointer types."""
20+
"""
21+
Get the base type and pointer depth for an LLVM IR type.
22+
23+
Args:
24+
ir_type: The LLVM IR type to analyze
25+
26+
Returns:
27+
A tuple of (base_type, depth) where depth is the number of pointer levels
28+
"""
2129
cur_type = ir_type
2230
depth = 0
2331
while isinstance(cur_type, ir.PointerType):
@@ -27,7 +35,18 @@ def _get_base_type_and_depth(ir_type):
2735

2836

2937
def _deref_to_depth(func, builder, val, target_depth):
30-
"""Dereference a pointer to a certain depth."""
38+
"""
39+
Dereference a pointer to a certain depth with null checks.
40+
41+
Args:
42+
func: The LLVM IR function being built
43+
builder: LLVM IR builder
44+
val: The pointer value to dereference
45+
target_depth: Number of levels to dereference
46+
47+
Returns:
48+
The dereferenced value, or None if dereferencing fails
49+
"""
3150

3251
cur_val = val
3352
cur_type = val.type
@@ -73,7 +92,18 @@ def _deref_to_depth(func, builder, val, target_depth):
7392

7493

7594
def _normalize_types(func, builder, lhs, rhs):
76-
"""Normalize types for comparison."""
95+
"""
96+
Normalize types for comparison by casting or dereferencing as needed.
97+
98+
Args:
99+
func: The LLVM IR function being built
100+
builder: LLVM IR builder
101+
lhs: Left-hand side value
102+
rhs: Right-hand side value
103+
104+
Returns:
105+
A tuple of (normalized_lhs, normalized_rhs) or (None, None) on error
106+
"""
77107

78108
logger.info(f"Normalizing types: {lhs.type} vs {rhs.type}")
79109
if isinstance(lhs.type, ir.IntType) and isinstance(rhs.type, ir.IntType):
@@ -99,7 +129,16 @@ def _normalize_types(func, builder, lhs, rhs):
99129

100130

101131
def convert_to_bool(builder, val):
102-
"""Convert a value to boolean."""
132+
"""
133+
Convert an LLVM IR value to a boolean (i1) type.
134+
135+
Args:
136+
builder: LLVM IR builder
137+
val: The value to convert
138+
139+
Returns:
140+
An i1 boolean value
141+
"""
103142
if val.type == ir.IntType(1):
104143
return val
105144
if isinstance(val.type, ir.PointerType):
@@ -110,7 +149,19 @@ def convert_to_bool(builder, val):
110149

111150

112151
def handle_comparator(func, builder, op, lhs, rhs):
113-
"""Handle comparison operations."""
152+
"""
153+
Handle comparison operations between two values.
154+
155+
Args:
156+
func: The LLVM IR function being built
157+
builder: LLVM IR builder
158+
op: The AST comparison operator node
159+
lhs: Left-hand side value
160+
rhs: Right-hand side value
161+
162+
Returns:
163+
A tuple of (result, ir.IntType(1)) or None on error
164+
"""
114165

115166
if lhs.type != rhs.type:
116167
lhs, rhs = _normalize_types(func, builder, lhs, rhs)

pythonbpf/functions/functions_pass.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,21 @@ def handle_assign(
243243
def handle_cond(
244244
func, module, builder, cond, local_sym_tab, map_sym_tab, structs_sym_tab=None
245245
):
246+
"""
247+
Evaluate a condition expression and convert it to a boolean value.
248+
249+
Args:
250+
func: The LLVM IR function being built
251+
module: The LLVM IR module
252+
builder: LLVM IR builder
253+
cond: The AST condition node to evaluate
254+
local_sym_tab: Local symbol table
255+
map_sym_tab: Map symbol table
256+
structs_sym_tab: Struct symbol table
257+
258+
Returns:
259+
LLVM IR boolean value representing the condition result
260+
"""
246261
val = eval_expr(
247262
func, module, builder, cond, local_sym_tab, map_sym_tab, structs_sym_tab
248263
)[0]
@@ -298,6 +313,18 @@ def handle_if(
298313

299314

300315
def handle_return(builder, stmt, local_sym_tab, ret_type):
316+
"""
317+
Handle return statements in BPF functions.
318+
319+
Args:
320+
builder: LLVM IR builder
321+
stmt: The AST Return node
322+
local_sym_tab: Local symbol table
323+
ret_type: Expected return type
324+
325+
Returns:
326+
True if a return was emitted, False otherwise
327+
"""
301328
logger.info(f"Handling return statement: {ast.dump(stmt)}")
302329
if stmt.value is None:
303330
return _handle_none_return(builder)
@@ -329,6 +356,23 @@ def process_stmt(
329356
did_return,
330357
ret_type=ir.IntType(64),
331358
):
359+
"""
360+
Process a single statement in a BPF function.
361+
362+
Args:
363+
func: The LLVM IR function being built
364+
module: The LLVM IR module
365+
builder: LLVM IR builder
366+
stmt: The AST statement node to process
367+
local_sym_tab: Local symbol table
368+
map_sym_tab: Map symbol table
369+
structs_sym_tab: Struct symbol table
370+
did_return: Whether a return has been emitted
371+
ret_type: Expected return type
372+
373+
Returns:
374+
True if a return was emitted, False otherwise
375+
"""
332376
logger.info(f"Processing statement: {ast.dump(stmt)}")
333377
if isinstance(stmt, ast.Expr):
334378
handle_expr(
@@ -363,6 +407,25 @@ def process_stmt(
363407
def allocate_mem(
364408
module, builder, body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab
365409
):
410+
"""
411+
Pre-allocate stack memory for local variables in a BPF function.
412+
413+
This function scans the function body and creates alloca instructions
414+
for all local variables before processing the function statements.
415+
416+
Args:
417+
module: The LLVM IR module
418+
builder: LLVM IR builder
419+
body: List of AST statements in the function body
420+
func: The LLVM IR function being built
421+
ret_type: Expected return type
422+
map_sym_tab: Map symbol table
423+
local_sym_tab: Local symbol table to populate
424+
structs_sym_tab: Struct symbol table
425+
426+
Returns:
427+
Updated local symbol table
428+
"""
366429
for stmt in body:
367430
has_metadata = False
368431
if isinstance(stmt, ast.If):
@@ -556,6 +619,16 @@ def process_bpf_chunk(func_node, module, return_type, map_sym_tab, structs_sym_t
556619

557620

558621
def func_proc(tree, module, chunks, map_sym_tab, structs_sym_tab):
622+
"""
623+
Process all BPF function chunks and generate LLVM IR.
624+
625+
Args:
626+
tree: The Python AST (not used in current implementation)
627+
module: The LLVM IR module to add functions to
628+
chunks: List of AST function nodes decorated with @bpf
629+
map_sym_tab: Map symbol table
630+
structs_sym_tab: Struct symbol table
631+
"""
559632
for func_node in chunks:
560633
is_global = False
561634
for decorator in func_node.decorator_list:
@@ -581,6 +654,18 @@ def func_proc(tree, module, chunks, map_sym_tab, structs_sym_tab):
581654

582655

583656
def infer_return_type(func_node: ast.FunctionDef):
657+
"""
658+
Infer the return type of a BPF function from annotations or return statements.
659+
660+
Args:
661+
func_node: The AST function node
662+
663+
Returns:
664+
String representation of the return type (e.g., 'c_int64')
665+
666+
Raises:
667+
TypeError: If func_node is not a FunctionDef
668+
"""
584669
if not isinstance(func_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
585670
raise TypeError("Expected ast.FunctionDef")
586671
if func_node.returns is not None:

0 commit comments

Comments
 (0)