mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2026-02-12 16:10:59 +00:00
Compare commits
5 Commits
8bd210cede
...
07580dabf2
| Author | SHA1 | Date | |
|---|---|---|---|
| 07580dabf2 | |||
| ac74b03b14 | |||
| 3bf85e733e | |||
| 73f7c80eca | |||
| 238697469a |
@ -39,7 +39,7 @@ def finalize_module(original_str):
|
|||||||
|
|
||||||
def bpf_passthrough_gen(module):
|
def bpf_passthrough_gen(module):
|
||||||
i32_ty = ir.IntType(32)
|
i32_ty = ir.IntType(32)
|
||||||
ptr_ty = ir.PointerType(ir.IntType(64))
|
ptr_ty = ir.PointerType(ir.IntType(8))
|
||||||
fnty = ir.FunctionType(ptr_ty, [i32_ty, ptr_ty])
|
fnty = ir.FunctionType(ptr_ty, [i32_ty, ptr_ty])
|
||||||
|
|
||||||
# Declare the intrinsic
|
# Declare the intrinsic
|
||||||
|
|||||||
@ -184,3 +184,83 @@ class DebugInfoGenerator:
|
|||||||
"DIGlobalVariableExpression",
|
"DIGlobalVariableExpression",
|
||||||
{"var": global_var, "expr": self.module.add_debug_info("DIExpression", {})},
|
{"var": global_var, "expr": self.module.add_debug_info("DIExpression", {})},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_int64_type(self):
|
||||||
|
return self.get_basic_type("long", 64, dc.DW_ATE_signed)
|
||||||
|
|
||||||
|
def create_subroutine_type(self, return_type, param_types):
|
||||||
|
"""
|
||||||
|
Create a DISubroutineType given return type and list of parameter types.
|
||||||
|
Equivalent to: !DISubroutineType(types: !{ret, args...})
|
||||||
|
"""
|
||||||
|
type_array = [return_type]
|
||||||
|
if isinstance(param_types, (list, tuple)):
|
||||||
|
type_array.extend(param_types)
|
||||||
|
else:
|
||||||
|
type_array.append(param_types)
|
||||||
|
return self.module.add_debug_info("DISubroutineType", {"types": type_array})
|
||||||
|
|
||||||
|
def create_local_variable_debug_info(
|
||||||
|
self, name: str, arg: int, var_type: Any
|
||||||
|
) -> Any:
|
||||||
|
"""
|
||||||
|
Create debug info for a local variable (DILocalVariable) without scope.
|
||||||
|
Example:
|
||||||
|
!DILocalVariable(name: "ctx", arg: 1, file: !3, line: 20, type: !7)
|
||||||
|
"""
|
||||||
|
return self.module.add_debug_info(
|
||||||
|
"DILocalVariable",
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"arg": arg,
|
||||||
|
"file": self.module._file_metadata,
|
||||||
|
"type": var_type,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_scope_to_local_variable(self, local_variable_debug_info, scope_value):
|
||||||
|
"""
|
||||||
|
Add scope information to an existing local variable debug info object.
|
||||||
|
"""
|
||||||
|
# TODO: this is a workaround a flaw in the debug info generation. Fix this if possible in the future.
|
||||||
|
# We should not be touching llvmlite's internals like this.
|
||||||
|
if hasattr(local_variable_debug_info, "operands"):
|
||||||
|
# LLVM metadata operands is a tuple, so we need to rebuild it
|
||||||
|
existing_operands = local_variable_debug_info.operands
|
||||||
|
|
||||||
|
# Convert tuple to list, add scope, convert back to tuple
|
||||||
|
operands_list = list(existing_operands)
|
||||||
|
operands_list.append(("scope", scope_value))
|
||||||
|
|
||||||
|
# Reassign the new tuple
|
||||||
|
local_variable_debug_info.operands = tuple(operands_list)
|
||||||
|
|
||||||
|
def create_subprogram(
|
||||||
|
self, name: str, subroutine_type: Any, retained_nodes: List[Any]
|
||||||
|
) -> Any:
|
||||||
|
"""
|
||||||
|
Create a DISubprogram for a function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Function name
|
||||||
|
subroutine_type: DISubroutineType for the function signature
|
||||||
|
retained_nodes: List of DILocalVariable nodes for function parameters/variables
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DISubprogram metadata
|
||||||
|
"""
|
||||||
|
return self.module.add_debug_info(
|
||||||
|
"DISubprogram",
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"scope": self.module._file_metadata,
|
||||||
|
"file": self.module._file_metadata,
|
||||||
|
"type": subroutine_type,
|
||||||
|
# TODO: the following flags do not exist at the moment in our dwarf constants file. We need to add them.
|
||||||
|
# "flags": dc.DW_FLAG_Prototyped | dc.DW_FLAG_AllCallsDescribed,
|
||||||
|
# "spFlags": dc.DW_SPFLAG_Definition | dc.DW_SPFLAG_Optimized,
|
||||||
|
"unit": self.module._debug_compile_unit,
|
||||||
|
"retainedNodes": retained_nodes,
|
||||||
|
},
|
||||||
|
is_distinct=True,
|
||||||
|
)
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import ast
|
import ast
|
||||||
|
|
||||||
import llvmlite.ir as ir
|
import llvmlite.ir as ir
|
||||||
|
import logging
|
||||||
from pythonbpf.debuginfo import DebugInfoGenerator
|
from pythonbpf.debuginfo import DebugInfoGenerator
|
||||||
from pythonbpf.expr import VmlinuxHandlerRegistry
|
from pythonbpf.expr import VmlinuxHandlerRegistry
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def generate_function_debug_info(
|
def generate_function_debug_info(
|
||||||
@ -12,10 +15,58 @@ def generate_function_debug_info(
|
|||||||
generator = DebugInfoGenerator(module)
|
generator = DebugInfoGenerator(module)
|
||||||
leading_argument = func_node.args.args[0]
|
leading_argument = func_node.args.args[0]
|
||||||
leading_argument_name = leading_argument.arg
|
leading_argument_name = leading_argument.arg
|
||||||
# TODO: add ctypes handling as well here
|
annotation = leading_argument.annotation
|
||||||
print(leading_argument.arg, leading_argument.annotation.id)
|
if func_node.returns is None:
|
||||||
context_debug_info = VmlinuxHandlerRegistry.get_struct_debug_info(
|
# TODO: should check if this logic is consistent with function return type handling elsewhere
|
||||||
name=leading_argument.annotation.id
|
return_type = ctypes.c_int64()
|
||||||
)
|
elif hasattr(func_node.returns, "id"):
|
||||||
print(context_debug_info)
|
return_type = func_node.returns.id
|
||||||
pass
|
if return_type == "c_int32":
|
||||||
|
return_type = generator.get_int32_type()
|
||||||
|
elif return_type == "c_int64":
|
||||||
|
return_type = generator.get_int64_type()
|
||||||
|
elif return_type == "c_uint32":
|
||||||
|
return_type = generator.get_uint32_type()
|
||||||
|
elif return_type == "c_uint64":
|
||||||
|
return_type = generator.get_uint64_type()
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
"Return type should be int32, int64, uint32 or uint64 only. Falling back to int64"
|
||||||
|
)
|
||||||
|
return_type = generator.get_int64_type()
|
||||||
|
else:
|
||||||
|
return_type = ctypes.c_int64()
|
||||||
|
# context processing
|
||||||
|
if annotation is None:
|
||||||
|
logger.warning("Type of context of function not found.")
|
||||||
|
return
|
||||||
|
if hasattr(annotation, "id"):
|
||||||
|
ctype_name = annotation.id
|
||||||
|
if ctype_name == "c_void_p":
|
||||||
|
return
|
||||||
|
elif ctype_name.startswith("ctypes"):
|
||||||
|
raise SyntaxError(
|
||||||
|
"The first argument should always be a pointer to a struct or a void pointer"
|
||||||
|
)
|
||||||
|
context_debug_info = VmlinuxHandlerRegistry.get_struct_debug_info(annotation.id)
|
||||||
|
pointer_to_context_debug_info = generator.create_pointer_type(
|
||||||
|
context_debug_info, 64
|
||||||
|
)
|
||||||
|
subroutine_type = generator.create_subroutine_type(
|
||||||
|
return_type, pointer_to_context_debug_info
|
||||||
|
)
|
||||||
|
context_local_variable = generator.create_local_variable_debug_info(
|
||||||
|
leading_argument_name, 1, pointer_to_context_debug_info
|
||||||
|
)
|
||||||
|
retained_nodes = [context_local_variable]
|
||||||
|
print("function name", func_node.name)
|
||||||
|
subprogram_debug_info = generator.create_subprogram(
|
||||||
|
func_node.name, subroutine_type, retained_nodes
|
||||||
|
)
|
||||||
|
generator.add_scope_to_local_variable(
|
||||||
|
context_local_variable, subprogram_debug_info
|
||||||
|
)
|
||||||
|
func.set_metadata("dbg", subprogram_debug_info)
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.error(f"Invalid annotation type for argument '{leading_argument_name}'")
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class VmlinuxHandler:
|
|||||||
globvar_ir, field_data = self.get_field_type(
|
globvar_ir, field_data = self.get_field_type(
|
||||||
python_type.__name__, field_name
|
python_type.__name__, field_name
|
||||||
)
|
)
|
||||||
builder.function.args[0].type = ir.PointerType(ir.IntType(64))
|
builder.function.args[0].type = ir.PointerType(ir.IntType(8))
|
||||||
print(builder.function.args[0])
|
print(builder.function.args[0])
|
||||||
field_ptr = self.load_ctx_field(
|
field_ptr = self.load_ctx_field(
|
||||||
builder, builder.function.args[0], globvar_ir
|
builder, builder.function.args[0], globvar_ir
|
||||||
@ -125,19 +125,18 @@ class VmlinuxHandler:
|
|||||||
# Load the offset value
|
# Load the offset value
|
||||||
offset = builder.load(offset_global)
|
offset = builder.load(offset_global)
|
||||||
|
|
||||||
# # Ensure ctx_arg is treated as i8* (byte pointer)
|
# Ensure ctx_arg is treated as i8* (byte pointer)
|
||||||
# # i8_type = ir.IntType(8)
|
i8_ptr_type = ir.PointerType()
|
||||||
# i8_ptr_type = ir.PointerType()
|
|
||||||
|
|
||||||
# Cast ctx_arg to i8* if it isn't already
|
# Cast ctx_arg to i8* if it isn't already
|
||||||
# if str(ctx_arg.type) != str(i8_ptr_type):
|
if str(ctx_arg.type) != str(i8_ptr_type):
|
||||||
# ctx_i8_ptr = builder.bitcast(ctx_arg, i8_ptr_type)
|
ctx_i8_ptr = builder.bitcast(ctx_arg, i8_ptr_type)
|
||||||
# else:
|
else:
|
||||||
# ctx_i8_ptr = ctx_arg
|
ctx_i8_ptr = ctx_arg
|
||||||
|
|
||||||
# GEP with explicit type - this is the key fix
|
# GEP with explicit type - this is the key fix
|
||||||
field_ptr = builder.gep(
|
field_ptr = builder.gep(
|
||||||
ctx_arg,
|
ctx_i8_ptr,
|
||||||
[offset],
|
[offset],
|
||||||
inbounds=False,
|
inbounds=False,
|
||||||
)
|
)
|
||||||
@ -151,8 +150,8 @@ class VmlinuxHandler:
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
except (KeyError, AttributeError):
|
except (KeyError, AttributeError):
|
||||||
passthrough_type = ir.FunctionType(
|
passthrough_type = ir.FunctionType(
|
||||||
ir.PointerType(),
|
i8_ptr_type,
|
||||||
[ir.IntType(32), ir.PointerType()],
|
[ir.IntType(32), i8_ptr_type],
|
||||||
)
|
)
|
||||||
passthrough_fn = ir.Function(
|
passthrough_fn = ir.Function(
|
||||||
module,
|
module,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from pythonbpf import bpf, section, bpfglobal, compile_to_ir
|
|||||||
from pythonbpf import compile # noqa: F401
|
from pythonbpf import compile # noqa: F401
|
||||||
from vmlinux import TASK_COMM_LEN # noqa: F401
|
from vmlinux import TASK_COMM_LEN # noqa: F401
|
||||||
from vmlinux import struct_trace_event_raw_sys_enter # noqa: F401
|
from vmlinux import struct_trace_event_raw_sys_enter # noqa: F401
|
||||||
from ctypes import c_int64, c_void_p # noqa: F401
|
from ctypes import c_int64, c_int32, c_void_p # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
# from vmlinux import struct_uinput_device
|
# from vmlinux import struct_uinput_device
|
||||||
|
|||||||
Reference in New Issue
Block a user