diff --git a/examples/c-form/Makefile b/examples/c-form/Makefile index 2d1d359..2f83602 100644 --- a/examples/c-form/Makefile +++ b/examples/c-form/Makefile @@ -3,13 +3,17 @@ CFLAGS := -O2 -emit-llvm -target bpf -c SRC := example.bpf.c OUT := example.bpf.ll +OBJECT := example.bpf.o .PHONY: all clean all: $(OUT) + +object: $(SRC) + $(BPF_CLANG) $(CFLAGS) $< -o $(OBJECT) -$(OUT): $(SRC) +$(OUT): $(SRC) object $(BPF_CLANG) $(CFLAGS) -S $< -o $@ clean: - rm -f $(OUT) + rm -f $(OUT) $(OBJECT) diff --git a/examples/execve.py b/examples/execve.py index 2e22bbf..fc1598f 100644 --- a/examples/execve.py +++ b/examples/execve.py @@ -1,8 +1,8 @@ -from pythonbpf.decorators import tracepoint, license +from pythonbpf.decorators import tracepoint @tracepoint("syscalls:sys_enter_execve") def trace_execve(ctx) -> int: print("execve called\n") return 0 -license("GPL") \ No newline at end of file +LICENSE = "GPL" diff --git a/pythonbpf/codegen.py b/pythonbpf/codegen.py index 56fe41b..335eb10 100644 --- a/pythonbpf/codegen.py +++ b/pythonbpf/codegen.py @@ -1,28 +1,20 @@ import ast from llvmlite import ir +from .license_pass import license_processing -def parser(source_code, filename): +def processor(source_code, filename, module): tree = ast.parse(source_code, filename) - - for node in tree.body: - if isinstance(node, ast.FunctionDef): - print("Function:", node.name) - for dec in node.decorator_list: - print(" Decorator AST:", ast.dump(dec)) + license_processing(tree, module) def compile_to_ir(filename: str, output: str): with open(filename) as f: - parser(f.read(), filename) + source = f.read() + module = ir.Module(name=filename) module.data_layout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" module.triple = "bpf" - func_ty = ir.FunctionType(ir.IntType(64), [], False) - func = ir.Function(module, func_ty, name="trace_execve") - - block = func.append_basic_block(name="entry") - builder = ir.IRBuilder(block) - builder.ret(ir.IntType(64)(0)) + processor(source, filename, module) with open(output, "w") as f: f.write(str(module)) diff --git a/pythonbpf/decorators.py b/pythonbpf/decorators.py index 5c69cb4..150bd01 100644 --- a/pythonbpf/decorators.py +++ b/pythonbpf/decorators.py @@ -3,6 +3,3 @@ def tracepoint(name: str): fn._section = f"tracepoint/{name}" return fn return wrapper - -def license(license_type: str): - return license_type diff --git a/pythonbpf/license_pass.py b/pythonbpf/license_pass.py new file mode 100644 index 0000000..7013077 --- /dev/null +++ b/pythonbpf/license_pass.py @@ -0,0 +1,33 @@ +from llvmlite import ir +import ast + +def emit_license(module: ir.Module, license_str: str): + license_bytes = license_str.encode("utf8") + b"\x00" + elems = [ir.Constant(ir.IntType(8), b) for b in license_bytes] + ty = ir.ArrayType(ir.IntType(8), len(elems)) + + gvar = ir.GlobalVariable(module, ty, name="LICENSE") + + gvar.initializer = ir.Constant(ty, elems) # type: ignore + + gvar.align = 1 # type: ignore + gvar.linkage = "dso_local" # type: ignore + gvar.global_constant = False # must be global, not constant + gvar.section = "license" # type: ignore + + return gvar + +def license_processing(tree, module): + count = 0 + for node in tree.body: + if isinstance(node, ast.Assign): + for target in node.targets: + if isinstance(target, ast.Name) and target.id == "LICENSE": + if count == 0: + count += 1 + if isinstance(node.value, ast.Constant) and isinstance(node.value.value, str): + emit_license(module, node.value.value) + else: + print("ERROR: LICENSE must be a string literal") + else: + print("ERROR: LICENSE already assigned")