mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2026-03-25 14:41:29 +00:00
Add remaining docstrings to complete documentation coverage
Co-authored-by: varun-r-mallya <100590632+varun-r-mallya@users.noreply.github.com>
This commit is contained in:
@ -1,3 +1,5 @@
|
|||||||
|
"""Debug information generation for BPF programs (DWARF/BTF)."""
|
||||||
|
|
||||||
from .dwarf_constants import * # noqa: F403
|
from .dwarf_constants import * # noqa: F403
|
||||||
from .dtypes import * # noqa: F403
|
from .dtypes import * # noqa: F403
|
||||||
from .debug_info_generator import DebugInfoGenerator
|
from .debug_info_generator import DebugInfoGenerator
|
||||||
|
|||||||
@ -8,11 +8,31 @@ from typing import Any, List
|
|||||||
|
|
||||||
|
|
||||||
class DebugInfoGenerator:
|
class DebugInfoGenerator:
|
||||||
|
"""
|
||||||
|
Generator for DWARF/BTF debug information in LLVM IR modules.
|
||||||
|
|
||||||
|
This class provides methods to create debug metadata for BPF programs,
|
||||||
|
including types, structs, globals, and compilation units.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
|
"""
|
||||||
|
Initialize the debug info generator.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module: LLVM IR module to attach debug info to
|
||||||
|
"""
|
||||||
self.module = module
|
self.module = module
|
||||||
self._type_cache = {} # Cache for common debug types
|
self._type_cache = {} # Cache for common debug types
|
||||||
|
|
||||||
def generate_file_metadata(self, filename, dirname):
|
def generate_file_metadata(self, filename, dirname):
|
||||||
|
"""
|
||||||
|
Generate file metadata for debug info.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: Name of the source file
|
||||||
|
dirname: Directory containing the source file
|
||||||
|
"""
|
||||||
self.module._file_metadata = self.module.add_debug_info(
|
self.module._file_metadata = self.module.add_debug_info(
|
||||||
"DIFile",
|
"DIFile",
|
||||||
{ # type: ignore
|
{ # type: ignore
|
||||||
@ -24,6 +44,15 @@ class DebugInfoGenerator:
|
|||||||
def generate_debug_cu(
|
def generate_debug_cu(
|
||||||
self, language, producer: str, is_optimized: bool, is_distinct: bool
|
self, language, producer: str, is_optimized: bool, is_distinct: bool
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Generate debug compile unit metadata.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
language: DWARF language code (e.g., DW_LANG_C11)
|
||||||
|
producer: Compiler/producer string
|
||||||
|
is_optimized: Whether the code is optimized
|
||||||
|
is_distinct: Whether the compile unit should be distinct
|
||||||
|
"""
|
||||||
self.module._debug_compile_unit = self.module.add_debug_info(
|
self.module._debug_compile_unit = self.module.add_debug_info(
|
||||||
"DICompileUnit",
|
"DICompileUnit",
|
||||||
{ # type: ignore
|
{ # type: ignore
|
||||||
@ -83,6 +112,16 @@ class DebugInfoGenerator:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _compute_array_size(base_type: Any, count: int) -> int:
|
def _compute_array_size(base_type: Any, count: int) -> int:
|
||||||
|
"""
|
||||||
|
Compute the size of an array in bits.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_type: The base type of the array
|
||||||
|
count: Number of elements in the array
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Total size in bits
|
||||||
|
"""
|
||||||
# Extract size from base_type if possible
|
# Extract size from base_type if possible
|
||||||
# For simplicity, assuming base_type has a size attribute
|
# For simplicity, assuming base_type has a size attribute
|
||||||
return getattr(base_type, "size", 32) * count
|
return getattr(base_type, "size", 32) * count
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
"""Debug information types and constants."""
|
||||||
|
|
||||||
import llvmlite.ir as ir
|
import llvmlite.ir as ir
|
||||||
|
|
||||||
|
|
||||||
class DwarfBehaviorEnum:
|
class DwarfBehaviorEnum:
|
||||||
|
"""DWARF module flag behavior constants for LLVM."""
|
||||||
ERROR_IF_MISMATCH = ir.Constant(ir.IntType(32), 1)
|
ERROR_IF_MISMATCH = ir.Constant(ir.IntType(32), 1)
|
||||||
WARNING_IF_MISMATCH = ir.Constant(ir.IntType(32), 2)
|
WARNING_IF_MISMATCH = ir.Constant(ir.IntType(32), 2)
|
||||||
OVERRIDE_USE_LARGEST = ir.Constant(ir.IntType(32), 7)
|
OVERRIDE_USE_LARGEST = ir.Constant(ir.IntType(32), 7)
|
||||||
|
|||||||
@ -41,6 +41,7 @@ def section(name: str):
|
|||||||
A decorator function that marks the function with the section name
|
A decorator function that marks the function with the section name
|
||||||
"""
|
"""
|
||||||
def wrapper(fn):
|
def wrapper(fn):
|
||||||
|
"""Decorator that sets the section name on the function."""
|
||||||
fn._section = name
|
fn._section = name
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
"""Registry for statement handler functions."""
|
||||||
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
@ -11,6 +13,7 @@ class StatementHandlerRegistry:
|
|||||||
"""Register a handler for a specific statement type."""
|
"""Register a handler for a specific statement type."""
|
||||||
|
|
||||||
def decorator(handler):
|
def decorator(handler):
|
||||||
|
"""Decorator that registers the handler."""
|
||||||
cls._handlers[stmt_type] = handler
|
cls._handlers[stmt_type] = handler
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
|||||||
@ -25,11 +25,20 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LocalSymbol:
|
class LocalSymbol:
|
||||||
|
"""
|
||||||
|
Represents a local variable in a BPF function.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
var: LLVM IR alloca instruction for the variable
|
||||||
|
ir_type: LLVM IR type of the variable
|
||||||
|
metadata: Optional metadata (e.g., struct type name)
|
||||||
|
"""
|
||||||
var: ir.AllocaInstr
|
var: ir.AllocaInstr
|
||||||
ir_type: ir.Type
|
ir_type: ir.Type
|
||||||
metadata: Any = None
|
metadata: Any = None
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
"""Support tuple unpacking of LocalSymbol."""
|
||||||
yield self.var
|
yield self.var
|
||||||
yield self.ir_type
|
yield self.ir_type
|
||||||
yield self.metadata
|
yield self.metadata
|
||||||
@ -692,6 +701,7 @@ def infer_return_type(func_node: ast.FunctionDef):
|
|||||||
found_type = None
|
found_type = None
|
||||||
|
|
||||||
def _expr_type(e):
|
def _expr_type(e):
|
||||||
|
"""Helper function to extract type from an expression."""
|
||||||
if e is None:
|
if e is None:
|
||||||
return "None"
|
return "None"
|
||||||
if isinstance(e, ast.Constant):
|
if isinstance(e, ast.Constant):
|
||||||
|
|||||||
@ -24,6 +24,7 @@ logger: Logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class BPFHelperID(Enum):
|
class BPFHelperID(Enum):
|
||||||
|
"""Enumeration of BPF helper function IDs."""
|
||||||
BPF_MAP_LOOKUP_ELEM = 1
|
BPF_MAP_LOOKUP_ELEM = 1
|
||||||
BPF_MAP_UPDATE_ELEM = 2
|
BPF_MAP_UPDATE_ELEM = 2
|
||||||
BPF_MAP_DELETE_ELEM = 3
|
BPF_MAP_DELETE_ELEM = 3
|
||||||
@ -260,6 +261,11 @@ def bpf_perf_event_output_handler(
|
|||||||
local_sym_tab=None,
|
local_sym_tab=None,
|
||||||
struct_sym_tab=None,
|
struct_sym_tab=None,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Emit LLVM IR for bpf_perf_event_output helper function call.
|
||||||
|
|
||||||
|
This allows sending data to userspace via a perf event array.
|
||||||
|
"""
|
||||||
if len(call.args) != 1:
|
if len(call.args) != 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Perf event output expects exactly one argument, got {len(call.args)}"
|
f"Perf event output expects exactly one argument, got {len(call.args)}"
|
||||||
@ -310,6 +316,7 @@ def handle_helper_call(
|
|||||||
|
|
||||||
# Helper function to get map pointer and invoke handler
|
# Helper function to get map pointer and invoke handler
|
||||||
def invoke_helper(method_name, map_ptr=None):
|
def invoke_helper(method_name, map_ptr=None):
|
||||||
|
"""Helper function to look up and invoke a registered handler."""
|
||||||
handler = HelperHandlerRegistry.get_handler(method_name)
|
handler = HelperHandlerRegistry.get_handler(method_name)
|
||||||
if not handler:
|
if not handler:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class HelperHandlerRegistry:
|
|||||||
"""Decorator to register a handler function for a helper"""
|
"""Decorator to register a handler function for a helper"""
|
||||||
|
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
|
"""Decorator that registers the handler function."""
|
||||||
cls._handlers[helper_name] = func
|
cls._handlers[helper_name] = func
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ def is_map(func_node):
|
|||||||
|
|
||||||
|
|
||||||
class BPFMapType(Enum):
|
class BPFMapType(Enum):
|
||||||
|
"""Enumeration of BPF map types."""
|
||||||
UNSPEC = 0
|
UNSPEC = 0
|
||||||
HASH = 1
|
HASH = 1
|
||||||
ARRAY = 2
|
ARRAY = 2
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
"""Registry for BPF map processor functions."""
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -12,6 +14,7 @@ class MapProcessorRegistry:
|
|||||||
"""Decorator to register a processor function for a map type"""
|
"""Decorator to register a processor function for a map type"""
|
||||||
|
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
|
"""Decorator that registers the processor function."""
|
||||||
cls._processors[map_type_name] = func
|
cls._processors[map_type_name] = func
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user