add debug info module

This commit is contained in:
2025-09-30 14:29:20 +05:30
parent 26f8f769c5
commit eb73001063
8 changed files with 67 additions and 52 deletions

View File

@ -2,38 +2,39 @@
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#define u64 unsigned long long #define u64 unsigned long long
#define u32 unsigned int
// Define the map // Define the map
struct { struct {
__uint(type, BPF_MAP_TYPE_HASH); __uint(type, BPF_MAP_TYPE_HASH);
__type(key, u64); __type(key, u64);
__type(value, u64); __type(value, u32);
__uint(max_entries, 4); __uint(max_entries, 4);
} last SEC(".maps"); } last SEC(".maps");
// Handler for syscall entry // // Handler for syscall entry
SEC("tracepoint/syscalls/sys_enter_execve") // SEC("tracepoint/syscalls/sys_enter_execve")
int hello(void *ctx) { // int hello(void *ctx) {
bpf_printk("entered"); // bpf_printk("entered");
bpf_printk("multi constant support"); // bpf_printk("multi constant support");
return 0; // return 0;
} // }
// Handler for syscall exit // // Handler for syscall exit
SEC("tracepoint/syscalls/sys_exit_execve") // SEC("tracepoint/syscalls/sys_exit_execve")
long hello_again(void *ctx) { // long hello_again(void *ctx) {
bpf_printk("exited"); // bpf_printk("exited");
// Create a key for map lookup // // Create a key for map lookup
u64 key = 0; // u64 key = 0;
// Simple lookup without conditionals // // Simple lookup without conditionals
u64 *tsp = bpf_map_lookup_elem(&last, &key); // u64 *tsp = bpf_map_lookup_elem(&last, &key);
// Get current timestamp // // Get current timestamp
u64 ts = bpf_ktime_get_ns(); // u64 ts = bpf_ktime_get_ns();
return 0; // return 0;
} // }
char LICENSE[] SEC("license") = "GPL"; char LICENSE[] SEC("license") = "GPL";

View File

@ -1,4 +1,4 @@
from pythonbpf.decorators import bpf, map, section, bpfglobal from pythonbpf import bpf, map, section, bpfglobal, compile_to_ir
from ctypes import c_void_p, c_int64, c_int32, c_uint64 from ctypes import c_void_p, c_int64, c_int32, c_uint64
from pythonbpf.helpers import ktime from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap from pythonbpf.maps import HashMap
@ -10,26 +10,28 @@ def last() -> HashMap:
return HashMap(key=c_uint64, value=c_uint64, max_entries=1) return HashMap(key=c_uint64, value=c_uint64, max_entries=1)
@bpf # @bpf
@section("tracepoint/syscalls/sys_enter_execve") # @section("tracepoint/syscalls/sys_enter_execve")
def hello(ctx: c_void_p) -> c_int32: # def hello(ctx: c_void_p) -> c_int32:
print("entered") # print("entered")
print("multi constant support") # print("multi constant support")
return c_int32(0) # return c_int32(0)
@bpf # @bpf
@section("tracepoint/syscalls/sys_exit_execve") # @section("tracepoint/syscalls/sys_exit_execve")
def hello_again(ctx: c_void_p) -> c_int64: # def hello_again(ctx: c_void_p) -> c_int64:
print("exited") # print("exited")
key = 0 # key = 0
tsp = last().lookup(key) # tsp = last().lookup(key)
print(tsp) # print(tsp)
ts = ktime() # ts = ktime()
return c_int64(0) # return c_int64(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile_to_ir("execve2.py", "execve2.ll")

View File

@ -1,2 +1,4 @@
from .decorators import bpf, map, section, bpfglobal, struct from .decorators import bpf, map, section, bpfglobal, struct
from .codegen import compile_to_ir, compile, BPF from .codegen import compile_to_ir, compile, BPF
from .maps import HashMap, PerfEventArray
from .helpers import pid, XDP_DROP, XDP_PASS, ktime, deref

View File

@ -1,5 +1,7 @@
import ast import ast
from llvmlite import ir from llvmlite import ir
from .debuginfo import DW_LANG_C11, DwarfBehaviorEnum
from .license_pass import license_processing from .license_pass import license_processing
from .functions_pass import func_proc from .functions_pass import func_proc
from .maps_pass import maps_proc from .maps_pass import maps_proc
@ -12,6 +14,7 @@ from pathlib import Path
from pylibbpf import BpfProgram from pylibbpf import BpfProgram
import tempfile import tempfile
version = "v0.1.3"
def find_bpf_chunks(tree): def find_bpf_chunks(tree):
"""Find all functions decorated with @bpf in the AST.""" """Find all functions decorated with @bpf in the AST."""
@ -50,15 +53,15 @@ def compile_to_ir(filename: str, output: str):
module.triple = "bpf" module.triple = "bpf"
if not hasattr(module, '_debug_compile_unit'): if not hasattr(module, '_debug_compile_unit'):
module._file_metadata = module.add_debug_info("DIFile", { # type: ignore module._file_metadata = module.add_debug_info("DIFile", { # type: ignore
"filename": filename, "filename": filename,
"directory": os.path.dirname(filename) "directory": os.path.dirname(filename)
}) })
module._debug_compile_unit = module.add_debug_info("DICompileUnit", { # type: ignore module._debug_compile_unit = module.add_debug_info("DICompileUnit", { # type: ignore
"language": 29, # DW_LANG_C11 "language": DW_LANG_C11,
"file": module._file_metadata, # type: ignore "file": module._file_metadata, # type: ignore
"producer": "PythonBPF DSL Compiler", "producer": f"PythonBPF {version}",
"isOptimized": True, "isOptimized": True,
"runtimeVersion": 0, "runtimeVersion": 0,
"emissionKind": 1, "emissionKind": 1,
@ -67,32 +70,32 @@ def compile_to_ir(filename: str, output: str):
}, is_distinct=True) }, is_distinct=True)
module.add_named_metadata( module.add_named_metadata(
"llvm.dbg.cu", module._debug_compile_unit) # type: ignore "llvm.dbg.cu", module._debug_compile_unit) # type: ignore
processor(source, filename, module) processor(source, filename, module)
wchar_size = module.add_metadata([ir.Constant(ir.IntType(32), 1), wchar_size = module.add_metadata([DwarfBehaviorEnum.ERROR_IF_MISMATCH,
"wchar_size", "wchar_size",
ir.Constant(ir.IntType(32), 4)]) ir.Constant(ir.IntType(32), 4)])
frame_pointer = module.add_metadata([ir.Constant(ir.IntType(32), 7), frame_pointer = module.add_metadata([DwarfBehaviorEnum.OVERRIDE_USE_LARGEST,
"frame-pointer", "frame-pointer",
ir.Constant(ir.IntType(32), 2)]) ir.Constant(ir.IntType(32), 2)])
# Add Debug Info Version (3 = DWARF v3, which LLVM expects) # Add Debug Info Version (3 = DWARF v3, which LLVM expects)
debug_info_version = module.add_metadata([ir.Constant(ir.IntType(32), 2), debug_info_version = module.add_metadata([DwarfBehaviorEnum.WARNING_IF_MISMATCH,
"Debug Info Version", "Debug Info Version",
ir.Constant(ir.IntType(32), 3)]) ir.Constant(ir.IntType(32), 3)])
# Add explicit DWARF version (4 is common, works with LLVM BPF backend) # Add explicit DWARF version (4 is common, works with LLVM BPF backend)
dwarf_version = module.add_metadata([ir.Constant(ir.IntType(32), 2), dwarf_version = module.add_metadata([DwarfBehaviorEnum.OVERRIDE_USE_LARGEST,
"Dwarf Version", "Dwarf Version",
ir.Constant(ir.IntType(32), 4)]) ir.Constant(ir.IntType(32), 5)])
module.add_named_metadata("llvm.module.flags", wchar_size) module.add_named_metadata("llvm.module.flags", wchar_size)
module.add_named_metadata("llvm.module.flags", frame_pointer) module.add_named_metadata("llvm.module.flags", frame_pointer)
module.add_named_metadata("llvm.module.flags", debug_info_version) module.add_named_metadata("llvm.module.flags", debug_info_version)
module.add_named_metadata("llvm.module.flags", dwarf_version) module.add_named_metadata("llvm.module.flags", dwarf_version)
module.add_named_metadata("llvm.ident", ["llvmlite PythonBPF v0.0.1"]) module.add_named_metadata("llvm.ident", [f"PythonBPF {version}"])
print(f"IR written to {output}") print(f"IR written to {output}")
with open(output, "w") as f: with open(output, "w") as f:
@ -125,8 +128,8 @@ def BPF() -> BpfProgram:
caller_frame = inspect.stack()[1] caller_frame = inspect.stack()[1]
src = inspect.getsource(caller_frame.frame) src = inspect.getsource(caller_frame.frame)
with tempfile.NamedTemporaryFile(mode="w+", delete=True, suffix=".py") as f, \ with tempfile.NamedTemporaryFile(mode="w+", delete=True, suffix=".py") as f, \
tempfile.NamedTemporaryFile(mode="w+", delete=True, suffix=".ll") as inter, \ tempfile.NamedTemporaryFile(mode="w+", delete=True, suffix=".ll") as inter, \
tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".o") as obj_file: tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".o") as obj_file:
f.write(src) f.write(src)
f.flush() f.flush()
source = f.name source = f.name

View File

@ -0,0 +1,2 @@
from .dwarf_constants import *
from .dtypes import *

View File

@ -0,0 +1,6 @@
import llvmlite.ir as ir
class DwarfBehaviorEnum:
ERROR_IF_MISMATCH = ir.Constant(ir.IntType(32), 1)
WARNING_IF_MISMATCH = ir.Constant(ir.IntType(32), 2)
OVERRIDE_USE_LARGEST = ir.Constant(ir.IntType(32), 7)

View File

@ -1,7 +1,6 @@
import ast import ast
from llvmlite import ir from llvmlite import ir
from .type_deducer import ctypes_to_ir from .debuginfo import dwarf_constants as dc
from . import dwarf_constants as dc
map_sym_tab = {} map_sym_tab = {}