diff --git a/ir_to_ctypes.py b/ir_to_ctypes.py new file mode 100644 index 0000000..889e573 --- /dev/null +++ b/ir_to_ctypes.py @@ -0,0 +1,84 @@ +import ctypes +from typing import Dict, Type +from llvmlite import ir +import logging + +logger = logging.getLogger(__name__) + + +def ir_type_to_ctypes(ir_type): + """Convert LLVM IR type to ctypes type.""" + if isinstance(ir_type, ir.IntType): + width = ir_type.width + type_map = { + 8: ctypes.c_uint8, + 16: ctypes.c_uint16, + 32: ctypes.c_uint32, + 64: ctypes.c_uint64, + } + if width not in type_map: + raise ValueError(f"Unsupported integer width: {width}") + return type_map[width] + + elif isinstance(ir_type, ir.ArrayType): + count = ir_type.count + element_type = ir_type_to_ctypes(ir_type.element) + return element_type * count + + elif isinstance(ir_type, ir.PointerType): + return ctypes.c_void_p + + else: + raise TypeError(f"Unsupported IR type: {ir_type}") + + +def convert_structs_to_ctypes(structs_sym_tab) -> Dict[str, Type[ctypes.Structure]]: + """Convert PythonBPF's structs_sym_tab to ctypes.Structure classes.""" + if not structs_sym_tab: + return {} + + ctypes_structs = {} + + for struct_name, struct_type_obj in structs_sym_tab.items(): + try: + fields = [] + for field_name, field_ir_type in struct_type_obj.fields.items(): + field_ctypes = ir_type_to_ctypes(field_ir_type) + fields.append((field_name, field_ctypes)) + + struct_class = type( + struct_name, + (ctypes.Structure,), + {'_fields_': fields, '__module__': 'pylibbpf.ir_to_ctypes', '__doc__': f'Auto-generated ctypes structure for {struct_name}', + '__repr__': lambda self: ( + f"<{struct_name} " + + " ".join(f"{name}={getattr(self, name)}" for name, _ in fields) + + ">" + )} + ) + + ctypes_structs[struct_name] = struct_class + # Pretty print field info + field_info = ", ".join(f"{name}: {typ.__name__}" for name, typ in fields) + logger.debug(f" {struct_name}({field_info})") + except Exception as e: + logger.error(f"Failed to convert struct '{struct_name}': {e}") + raise + logger.info(f"Converted struct '{struct_name}' to ctypes") + return ctypes_structs + + +def is_pythonbpf_structs(structs) -> bool: + """Check if structs dict is from PythonBPF.""" + if not isinstance(structs, dict) or not structs: + return False + + first_value = next(iter(structs.values())) + return ( + hasattr(first_value, 'ir_type') and + hasattr(first_value, 'fields') and + hasattr(first_value, 'size') + ) + + +__all__ = ["convert_structs_to_ctypes", "is_pythonbpf_structs"]