Get ex2 running

This commit is contained in:
2025-09-07 19:19:58 +05:30
parent 734a49b295
commit c0559639f2
11 changed files with 72 additions and 35 deletions

View File

@ -1,13 +1,13 @@
compile: compile:
chmod +x ./tools/compile.py chmod +x ./tools/compile.py
./tools/compile.py ./examples/execve.py ./tools/compile.py ./examples/execve2.py
install: install:
pip install -e . pip install -e .
clean: clean:
rm -rf build dist *.egg-info rm -rf build dist *.egg-info
rm -rf examples/execve.ll examples/execve.o rm -rf examples/*.ll examples/*.o
all: install compile all: install compile

View File

@ -8,6 +8,9 @@ Step 2. Run `make` to see the compilation output of the example.
Step 3. Run `check.sh` to check if generated object file passes through the verifier inside the examples directory. Step 3. Run `check.sh` to check if generated object file passes through the verifier inside the examples directory.
Step 4. Run `make` in the `examples/c-form` directory to modify the example C BPF program to check the actual LLVM IR generated by clang. Step 4. Run `make` in the `examples/c-form` directory to modify the example C BPF program to check the actual LLVM IR generated by clang.
### Development Notes
Run ` ./check.sh run execve2.o;` in examples folder
## Authors ## Authors
- [@r41k0u](https://github.com/r41k0u) - [@r41k0u](https://github.com/r41k0u)
- [@varun-r-mallya](https://github.com/varun-r-mallya) - [@varun-r-mallya](https://github.com/varun-r-mallya)

View File

@ -1,19 +1,19 @@
BPF_CLANG := clang BPF_CLANG := clang
CFLAGS := -O2 -emit-llvm -target bpf -c CFLAGS := -O2 -emit-llvm -target bpf -c
SRC := ex3.bpf.c SRC := $(wildcard *.bpf.c)
OUT := ex3.bpf.ll LL := $(SRC:.bpf.c=.bpf.ll)
OBJECT := ex3.bpf.o OBJ := $(SRC:.bpf.c=.bpf.o)
.PHONY: all clean .PHONY: all clean
all: $(OUT) all: $(LL) $(OBJ)
object: $(SRC)
$(BPF_CLANG) -O2 -g -target bpf -c $< -o $(OBJECT)
$(OUT): $(SRC) object %.bpf.o: %.bpf.c
$(BPF_CLANG) -O2 -target bpf -c $< -o $@
%.bpf.ll: %.bpf.c
$(BPF_CLANG) $(CFLAGS) -S $< -o $@ $(BPF_CLANG) $(CFLAGS) -S $< -o $@
clean: clean:
rm -f $(OUT) $(OBJECT) rm -f $(LL) $(OBJ)

View File

@ -1,7 +1,7 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
SEC("kprobe/sys_clone") SEC("tracepoint/syscalls/sys_enter_execve")
int hello(struct pt_regs *ctx) { int hello(struct pt_regs *ctx) {
bpf_printk("Hello, World!\n"); bpf_printk("Hello, World!\n");
return 0; return 0;

View File

@ -1,2 +1,33 @@
#!/bin/bash #!/bin/bash
sudo bpftool prog -d load $1 /sys/fs/bpf/tmp && sudo rm -f /sys/fs/bpf/tmp
PIN_PATH="/sys/fs/bpf/bpf_prog"
FILE="$2"
case "$1" in
check)
echo "[*] Checking $FILE"
echo $(sudo bpftool prog load -d "$FILE" "$PIN_PATH")
sudo rm -f "$PIN_PATH"
echo "[+] Verification succeeded"
;;
run)
echo "[*] Loading and running $FILE"
sudo bpftool prog load "$FILE" "$PIN_PATH" autoattach
echo "[+] Program loaded. Press Ctrl+C to stop"
sudo cat /sys/kernel/debug/tracing/trace_pipe
sudo rm -f "$PIN_PATH"
echo "[+] Stopped"
;;
stop)
echo "[*] Stopping program"
sudo rm -f "$PIN_PATH"
echo "[+] Stopped"
;;
*)
echo "Usage: $0 <check|run|stop> <file.o>"
echo "Examples:"
echo " $0 check program.bpf.o"
echo " $0 run program.bpf.o"
echo " $0 stop"
exit 1
;;
esac

View File

@ -1,13 +1,11 @@
from pythonbpf.decorators import bpf, section from pythonbpf.decorators import bpf, section
# from pythonbpf.decorators import tracepoint, syscalls
from ctypes import c_void_p, c_int32 from ctypes import c_void_p, c_int32
@bpf @bpf
@section("kprobe/sys_clone") @section("tracepoint/syscalls/sys_enter_execve")
def hello(ctx: c_void_p) -> c_int32: def hello(ctx: c_void_p) -> c_int32:
print("Hello, World!") print("Hello, World!")
return c_int32(0) return c_int32(0)
LICENSE = "GPL" LICENSE = "GPL"

View File

@ -1,11 +1,15 @@
from pythonbpf.decorators import tracepoint, syscalls # This is what it is going to look like
# pylint: disable-all# type: ignore
from pythonbpf.decorators import tracepoint, syscalls, bpfglobal, bpf
from ctypes import c_void_p, c_int32 from ctypes import c_void_p, c_int32
@bpf
@tracepoint(syscalls.sys_clone) @tracepoint(syscalls.sys_clone)
def trace_clone(ctx: c_void_p) -> c_int32: def trace_clone(ctx: c_void_p) -> c_int32:
print("Hello, World!") print("Hello, World!")
return c_int32(0) return c_int32(0)
@bpf
LICENSE = "GPL" @bpfglobal
def LICENSE() -> str:
return "GPL"

View File

@ -1,8 +1,8 @@
import ast import ast
from llvmlite import ir from llvmlite import ir
from .license_pass import license_processing from .license_pass import license_processing
from .functions_pass import func_proc, functions_processing from .functions_pass import func_proc
from .constants_pass import constants_processing # from .constants_pass import constants_processing
from .globals_pass import globals_processing from .globals_pass import globals_processing
@ -28,12 +28,10 @@ def processor(source_code, filename, module):
func_proc(tree, module, bpf_chunks) func_proc(tree, module, bpf_chunks)
# For now, we will parse the BPF specific parts of AST # For now, we will parse the BPF specific parts of AST
# Big rewrite
# will worry later
# constants_processing(tree, module) # constants_processing(tree, module)
# license_processing(tree, module) license_processing(tree, module)
# globals_processing(tree, module) globals_processing(tree, module)
# functions_processing(tree, module) # functions_processing(tree, module)
@ -57,6 +55,7 @@ def compile_to_ir(filename: str, output: str):
module.add_named_metadata("llvm.ident", ["llvmlite PythonBPF v0.0.0"]) module.add_named_metadata("llvm.ident", ["llvmlite PythonBPF v0.0.0"])
with open(output, "w") as f: with open(output, "w") as f:
f.write(f"source_filename = \"{filename}\"\n")
f.write(str(module)) f.write(str(module))
return output return output

View File

@ -13,9 +13,9 @@ def emit_function(module: ir.Module, name: str):
param.add_attribute("nocapture") param.add_attribute("nocapture")
func.attributes.add("nounwind") func.attributes.add("nounwind")
# func.attributes.add("\"frame-pointer\"=\"all\"") # func.attributes.add("\"frame-pointer\"=\"all\"")
# func.attributes.add("no-trapping-math", "true") # func.attributes.add("no-trapping-math", "true")
# func.attributes.add("stack-protector-buffer-size", "8") # func.attributes.add("stack-protector-buffer-size", "8")
block = func.append_basic_block(name="entry") block = func.append_basic_block(name="entry")
builder = ir.IRBuilder(block) builder = ir.IRBuilder(block)
@ -70,17 +70,17 @@ def process_func_body(module, builder, func_node, func):
# Handle print statement # Handle print statement
for arg in call.args: for arg in call.args:
if isinstance(arg, ast.Constant) and isinstance(arg.value, str): if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
fmt_str = arg.value + "\n" fmt_str = arg.value + "\n" + "\0"
# Create a global variable for the format string # Create a global variable for the format string
fmt_gvar = ir.GlobalVariable( fmt_gvar = ir.GlobalVariable(
module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=f"{func.name}____fmt") module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=f"{func.name}____fmt")
fmt_gvar.global_constant = True fmt_gvar.global_constant = True
fmt_gvar.initializer = ir.Constant( fmt_gvar.initializer = ir.Constant( # type: ignore
ir.ArrayType(ir.IntType(8), len(fmt_str)), ir.ArrayType(ir.IntType(8), len(fmt_str)),
bytearray(fmt_str.encode("utf8")) bytearray(fmt_str.encode("utf8"))
) )
fmt_gvar.linkage = "internal" fmt_gvar.linkage = "internal"
fmt_gvar.align = 1 fmt_gvar.align = 1 # type: ignore
# Cast the global variable to i8* # Cast the global variable to i8*
fmt_ptr = builder.bitcast( fmt_ptr = builder.bitcast(
@ -129,6 +129,8 @@ def process_bpf_chunk(func_node, module):
func.linkage = "dso_local" func.linkage = "dso_local"
func.attributes.add("nounwind") func.attributes.add("nounwind")
func.attributes.add("noinline")
func.attributes.add("optnone")
if func_node.args.args: if func_node.args.args:
# Only look at the first argument for now # Only look at the first argument for now

View File

@ -31,8 +31,8 @@ def globals_processing(tree, module: ir.Module):
collected = ["LICENSE"] collected = ["LICENSE"]
for node in tree.body: for node in tree.body:
if isinstance(node, ast.FunctionDef) and len(node.decorator_list) == 1: if isinstance(node, ast.FunctionDef) and len(node.decorator_list) == 2:
dec = node.decorator_list[0] dec = node.decorator_list[1]
if ( if (
isinstance(dec, ast.Call) isinstance(dec, ast.Call)
and isinstance(dec.func, ast.Name) and isinstance(dec.func, ast.Name)

View File

@ -14,7 +14,7 @@ def main():
codegen.compile_to_ir(args.source, ll_file) codegen.compile_to_ir(args.source, ll_file)
print("[+] Running llc -march=bpf") print("[+] Running llc -march=bpf")
subprocess.run(["llc", "-march=bpf", "-filetype=obj", ll_file, "-o", o_file], check=True) subprocess.run(["llc", "-march=bpf", "-filetype=obj", "-O2", ll_file, "-o", o_file], check=True)
if __name__ == "__main__": if __name__ == "__main__":
main() main()