Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions demo/bcc.py

This file was deleted.

File renamed without changes.
12 changes: 1 addition & 11 deletions examples/execve3.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,10 @@
def last() -> HashMap:
return HashMap(key=c_uint64, value=c_uint64, max_entries=3)


@bpf
@section("tracepoint/syscalls/sys_enter_execve")
def hello(ctx: c_void_p) -> c_int32:
print("entered")
print("multi constant support")
return c_int32(0)


@bpf
@section("tracepoint/syscalls/sys_exit_execve")
def hello_again(ctx: c_void_p) -> c_int64:
print("multi constant support")
print("exited")
key = 0
delta = 0
Expand All @@ -45,11 +37,9 @@ def hello_again(ctx: c_void_p) -> c_int64:

return c_int64(0)


@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"


compile()
1 change: 0 additions & 1 deletion examples/execve4.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
def last() -> HashMap:
return HashMap(key=c_uint64, value=c_uint64, max_entries=3)


@bpf
@section("blk_start_request")
def trace_start(ctx: c_void_p) -> c_int32:
Expand Down
15 changes: 0 additions & 15 deletions examples/hello_world.py

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
33 changes: 19 additions & 14 deletions pythonbpf/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
from pythonbpf.maps import maps_proc
from .structs.structs_pass import structs_proc
from .globals_pass import globals_processing
from .debuginfo import DW_LANG_C11, DwarfBehaviorEnum
import os
import subprocess
import inspect
from pathlib import Path
from pylibbpf import BpfProgram
import tempfile

VERSION = "v0.1.3"


def find_bpf_chunks(tree):
"""Find all functions decorated with @bpf in the AST."""
Expand Down Expand Up @@ -50,49 +53,51 @@ def compile_to_ir(filename: str, output: str):
module.triple = "bpf"

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,
"directory": os.path.dirname(filename)
})

module._debug_compile_unit = module.add_debug_info("DICompileUnit", { # type: ignore
"language": 29, # DW_LANG_C11
"file": module._file_metadata, # type: ignore
"producer": "PythonBPF DSL Compiler",
"isOptimized": True,
module._debug_compile_unit = module.add_debug_info("DICompileUnit", { # type: ignore
"language": DW_LANG_C11,
"file": module._file_metadata, # type: ignore
"producer": f"PythonBPF {VERSION}",
"isOptimized": True, # TODO: This is probably not true
# TODO: add a global field here that keeps track of all the globals. Works without it, but I think it might
# be required for kprobes.
"runtimeVersion": 0,
"emissionKind": 1,
"splitDebugInlining": False,
"nameTableKind": 0
}, is_distinct=True)

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)

wchar_size = module.add_metadata([ir.Constant(ir.IntType(32), 1),
wchar_size = module.add_metadata([DwarfBehaviorEnum.ERROR_IF_MISMATCH,
"wchar_size",
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",
ir.Constant(ir.IntType(32), 2)])
# 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",
ir.Constant(ir.IntType(32), 3)])

# Add explicit DWARF version (4 is common, works with LLVM BPF backend)
dwarf_version = module.add_metadata([ir.Constant(ir.IntType(32), 2),
# Add explicit DWARF version 5
dwarf_version = module.add_metadata([DwarfBehaviorEnum.OVERRIDE_USE_LARGEST,
"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", frame_pointer)
module.add_named_metadata("llvm.module.flags", debug_info_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}")
with open(output, "w") as f:
Expand Down
3 changes: 3 additions & 0 deletions pythonbpf/debuginfo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .dwarf_constants import *
from .dtypes import *
from .debug_info_generator import DebugInfoGenerator
92 changes: 92 additions & 0 deletions pythonbpf/debuginfo/debug_info_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Debug information generation module for Python-BPF
Provides utilities for generating DWARF/BTF debug information
"""

from . import dwarf_constants as dc
from typing import Dict, Any, List, Optional, Union


class DebugInfoGenerator:
def __init__(self, module):
self.module = module
self._type_cache = {} # Cache for common debug types

def get_basic_type(self, name: str, size: int, encoding: int) -> Any:
"""Get or create a basic type with caching"""
key = (name, size, encoding)
if key not in self._type_cache:
self._type_cache[key] = self.module.add_debug_info("DIBasicType", {
"name": name,
"size": size,
"encoding": encoding
})
return self._type_cache[key]

def get_uint32_type(self) -> Any:
"""Get debug info for unsigned 32-bit integer"""
return self.get_basic_type("unsigned int", 32, dc.DW_ATE_unsigned)

def get_uint64_type(self) -> Any:
"""Get debug info for unsigned 64-bit integer"""
return self.get_basic_type("unsigned long long", 64, dc.DW_ATE_unsigned)

def create_pointer_type(self, base_type: Any, size: int = 64) -> Any:
"""Create a pointer type to the given base type"""
return self.module.add_debug_info("DIDerivedType", {
"tag": dc.DW_TAG_pointer_type,
"baseType": base_type,
"size": size
})

def create_array_type(self, base_type: Any, count: int) -> Any:
"""Create an array type of the given base type with specified count"""
subrange = self.module.add_debug_info("DISubrange", {"count": count})
return self.module.add_debug_info("DICompositeType", {
"tag": dc.DW_TAG_array_type,
"baseType": base_type,
"size": self._compute_array_size(base_type, count),
"elements": [subrange]
})

@staticmethod
def _compute_array_size(base_type: Any, count: int) -> int:
# Extract size from base_type if possible
# For simplicity, assuming base_type has a size attribute
return getattr(base_type, "size", 32) * count

def create_struct_member(self, name: str, base_type: Any, offset: int) -> Any:
"""Create a struct member with the given name, type, and offset"""
return self.module.add_debug_info("DIDerivedType", {
"tag": dc.DW_TAG_member,
"name": name,
"file": self.module._file_metadata,
"baseType": base_type,
"size": getattr(base_type, "size", 64),
"offset": offset
})

def create_struct_type(self, members: List[Any], size: int, is_distinct: bool) -> Any:
"""Create a struct type with the given members and size"""
return self.module.add_debug_info("DICompositeType", {
"tag": dc.DW_TAG_structure_type,
"file": self.module._file_metadata,
"size": size,
"elements": members,
}, is_distinct=is_distinct)

def create_global_var_debug_info(self, name: str, var_type: Any, is_local: bool = False) -> Any:
"""Create debug info for a global variable"""
global_var = self.module.add_debug_info("DIGlobalVariable", {
"name": name,
"scope": self.module._debug_compile_unit,
"file": self.module._file_metadata,
"type": var_type,
"isLocal": is_local,
"isDefinition": True
}, is_distinct=True)

return self.module.add_debug_info("DIGlobalVariableExpression", {
"var": global_var,
"expr": self.module.add_debug_info("DIExpression", {})
})
6 changes: 6 additions & 0 deletions pythonbpf/debuginfo/dtypes.py
Original file line number Diff line number Diff line change
@@ -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)
File renamed without changes.
Loading