Skip to content

Commit c3a512d

Browse files
add global support with broken generation function
1 parent 4a60c42 commit c3a512d

File tree

4 files changed

+127
-12
lines changed

4 files changed

+127
-12
lines changed

pythonbpf/codegen.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .functions_pass import func_proc
55
from .maps import maps_proc
66
from .structs import structs_proc
7-
from .globals_pass import globals_processing
7+
from .globals_pass import globals_list_creation, globals_processing
88
from .debuginfo import DW_LANG_C11, DwarfBehaviorEnum, DebugInfoGenerator
99
import os
1010
import subprocess
@@ -46,6 +46,7 @@ def processor(source_code, filename, module):
4646

4747
license_processing(tree, module)
4848
globals_processing(tree, module)
49+
globals_list_creation(tree, module)
4950

5051

5152
def compile_to_ir(filename: str, output: str, loglevel=logging.WARNING):

pythonbpf/globals_pass.py

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,71 @@
11
from llvmlite import ir
22
import ast
33

4+
from llvmlite import ir
5+
import ast
6+
from logging import Logger
7+
import logging
8+
from .type_deducer import ctypes_to_ir
9+
10+
logger: Logger = logging.getLogger(__name__)
11+
12+
13+
def emit_global(module: ir.Module, node, name):
14+
print("global", node.returns.id)
15+
ty = ctypes_to_ir(node.returns.id)
16+
17+
gvar = ir.GlobalVariable(module, ty, name=name)
18+
gvar.initializer = ir.Constant(ty, initial_value)
19+
gvar.align = 8
20+
gvar.linkage = "dso_local"
21+
gvar.global_constant = False
22+
return gvar
423

5-
def emit_globals(module: ir.Module, names: list[str]):
24+
25+
def globals_processing(tree, module):
26+
"""Process stuff decorated with @bpf and @bpfglobal except license and return the section name"""
27+
global_sym_tab = []
28+
29+
for node in tree.body:
30+
# Skip non-assignment and non-function nodes
31+
if not (isinstance(node, (ast.FunctionDef, ast.AnnAssign, ast.Assign))):
32+
continue
33+
34+
# Get the name based on node type
35+
if isinstance(node, ast.FunctionDef):
36+
name = node.name
37+
else:
38+
continue
39+
40+
# Check for duplicate names
41+
if name in global_sym_tab:
42+
raise SyntaxError(f"ERROR: Global name '{name}' previously defined")
43+
else:
44+
global_sym_tab.append(name)
45+
46+
# Process decorated functions
47+
if isinstance(node, ast.FunctionDef) and node.name != "LICENSE":
48+
# Check decorators
49+
decorators = [
50+
dec.id for dec in node.decorator_list if isinstance(dec, ast.Name)
51+
]
52+
53+
if "bpf" in decorators and "bpfglobal" in decorators:
54+
if (
55+
len(node.body) == 1
56+
and isinstance(node.body[0], ast.Return)
57+
and node.body[0].value is not None
58+
and isinstance(node.body[0].value, (ast.Constant, ast.Name))
59+
):
60+
emit_global(module, node, name)
61+
return node.name
62+
else:
63+
logger.info(f"Invalid global expression for '{node.name}'")
64+
return None
65+
66+
return None
67+
68+
def emit_llvm_compiler_used(module: ir.Module, names: list[str]):
669
"""
770
Emit the @llvm.compiler.used global given a list of function/global names.
871
"""
@@ -24,26 +87,27 @@ def emit_globals(module: ir.Module, names: list[str]):
2487
gv.section = "llvm.metadata"
2588

2689

27-
def globals_processing(tree, module: ir.Module):
90+
def globals_list_creation(tree, module: ir.Module):
2891
collected = ["LICENSE"]
2992

3093
for node in tree.body:
3194
if isinstance(node, ast.FunctionDef):
3295
for dec in node.decorator_list:
3396
if (
34-
isinstance(dec, ast.Call)
35-
and isinstance(dec.func, ast.Name)
36-
and dec.func.id == "section"
37-
and len(dec.args) == 1
38-
and isinstance(dec.args[0], ast.Constant)
39-
and isinstance(dec.args[0].value, str)
97+
isinstance(dec, ast.Call)
98+
and isinstance(dec.func, ast.Name)
99+
and dec.func.id == "section"
100+
and len(dec.args) == 1
101+
and isinstance(dec.args[0], ast.Constant)
102+
and isinstance(dec.args[0].value, str)
40103
):
41104
collected.append(node.name)
42105

43-
elif isinstance(dec, ast.Name) and dec.id == "bpfglobal":
44-
collected.append(node.name)
106+
# NOTE: all globals other than
107+
# elif isinstance(dec, ast.Name) and dec.id == "bpfglobal":
108+
# collected.append(node.name)
45109

46110
elif isinstance(dec, ast.Name) and dec.id == "map":
47111
collected.append(node.name)
48112

49-
emit_globals(module, collected)
113+
emit_llvm_compiler_used(module, collected)

tests/c-form/globals.bpf.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_tracing.h>
5+
#include <linux/types.h>
6+
7+
struct test_struct {
8+
__u64 a;
9+
__u64 b;
10+
};
11+
12+
struct test_struct w = {};
13+
volatile __u64 prev_time = 0;
14+
15+
SEC("tracepoint/syscalls/sys_enter_execve")
16+
int trace_execve(void *ctx)
17+
{
18+
bpf_printk("previous %ul now %ul", w.b, w.a);
19+
__u64 ts = bpf_ktime_get_ns();
20+
bpf_printk("prev %ul now %ul", prev_time, ts);
21+
w.a = ts;
22+
w.b = prev_time;
23+
prev_time = ts;
24+
return 0;
25+
}
26+
27+
char LICENSE[] SEC("license") = "GPL";

tests/failing_tests/globals.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import logging
2+
3+
from pythonbpf import compile, bpf, section, bpfglobal, compile_to_ir
4+
from ctypes import c_void_p, c_int64
5+
6+
@bpf
7+
@bpfglobal
8+
def somevalue() -> c_int64:
9+
return c_int64(0)
10+
11+
@bpf
12+
@section("sometag1")
13+
def sometag(ctx: c_void_p) -> c_int64:
14+
return c_int64(0)
15+
16+
@bpf
17+
@bpfglobal
18+
def LICENSE() -> str:
19+
return "GPL"
20+
21+
22+
compile_to_ir("globals.py", "globals.ll", loglevel=logging.INFO)
23+
compile()

0 commit comments

Comments
 (0)