format chore and pre commit hook addition

This commit is contained in:
2025-10-01 00:41:00 +05:30
parent 8658143b16
commit 8d5067996f
37 changed files with 83187 additions and 82671 deletions

22
.github/workflows/format.yml vendored Normal file
View File

@ -0,0 +1,22 @@
# This is a format job. Pre-commit has a first-party GitHub action, so we use
# that: https://github.com/pre-commit/action
name: Format
on:
workflow_dispatch:
pull_request:
push:
branches:
- master
jobs:
pre-commit:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: pre-commit/action@v3.0.1

60
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,60 @@
# To use:
#
# pre-commit run -a
#
# Or:
#
# pre-commit install # (runs every time you commit in git)
#
# To update this file:
#
# pre-commit autoupdate
#
# See https://github.com/pre-commit/pre-commit
exclude: 'vmlinux.*\.py$'
ci:
autoupdate_commit_msg: "chore: update pre-commit hooks"
autofix_commit_msg: "style: pre-commit fixes"
repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-yaml
exclude: ^conda\.recipe/meta\.yaml$
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: requirements-txt-fixer
- id: trailing-whitespace
#- repo: https://github.com/astral-sh/ruff-pre-commit
# rev: "v0.4.2"
# hooks:
# - id: ruff
# args: ["--fix", "--show-fixes"]
# - id: ruff-format
# exclude: ^(docs)
## Checking static types
#- repo: https://github.com/pre-commit/mirrors-mypy
# rev: "v1.10.0"
# hooks:
# - id: mypy
# files: "setup.py"
# args: []
# additional_dependencies: [types-setuptools]
# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
- id: remove-tabs
exclude: '^(docs)|.*/Makefile$|Makefile$'

View File

@ -200,4 +200,3 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.

View File

@ -10,6 +10,7 @@ from ctypes import c_void_p, c_int64, c_uint64
# 3. Run the program with sudo: sudo tools/check.sh run examples/binops_demo.py # 3. Run the program with sudo: sudo tools/check.sh run examples/binops_demo.py
# 4. Start up any program and watch the output # 4. Start up any program and watch the output
@bpf @bpf
@map @map
def last() -> HashMap: def last() -> HashMap:
@ -23,9 +24,9 @@ def do_trace(ctx: c_void_p) -> c_int64:
tsp = last().lookup(key) tsp = last().lookup(key)
if tsp: if tsp:
kt = ktime() kt = ktime()
delta = (kt - tsp) delta = kt - tsp
if delta < 1000000000: if delta < 1000000000:
time_ms = (delta // 1000000) time_ms = delta // 1000000
print(f"Execve syscall entered within last second, last {time_ms} ms ago") print(f"Execve syscall entered within last second, last {time_ms} ms ago")
last().delete(key) last().delete(key)
else: else:
@ -33,16 +34,18 @@ def do_trace(ctx: c_void_p) -> c_int64:
last().update(key, kt) last().update(key, kt)
return c_int64(0) return c_int64(0)
@bpf @bpf
@section("tracepoint/syscalls/sys_exit_execve") @section("tracepoint/syscalls/sys_exit_execve")
def do_exit(ctx: c_void_p) -> c_int64: def do_exit(ctx: c_void_p) -> c_int64:
va = 8 va = 8
nm = 5 ^ va nm = 5 ^ va
al = 6 & 3 al = 6 & 3
ru = (nm + al) ru = nm + al
print(f"this is a variable {ru}") print(f"this is a variable {ru}")
return c_int64(0) return c_int64(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:

View File

@ -1,8 +1,8 @@
from pythonbpf import bpf, map, section, bpfglobal, compile from pythonbpf import bpf, map, section, bpfglobal, compile
from pythonbpf.helpers import ktime, deref from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64, c_int32, c_uint64 from ctypes import c_void_p, c_int32, c_uint64
@bpf @bpf
@ -10,11 +10,12 @@ from ctypes import c_void_p, c_int64, c_int32, c_uint64
def last() -> HashMap: def last() -> HashMap:
return HashMap(key=c_uint64, value=c_uint64, max_entries=3) return HashMap(key=c_uint64, value=c_uint64, max_entries=3)
@bpf @bpf
@section("blk_start_request") @section("blk_start_request")
def trace_start(ctx: c_void_p) -> c_int32: def trace_start(ctx: c_void_p) -> c_int32:
ts = ktime() ts = ktime()
print("req started") print(f"req started {ts}")
return c_int32(0) return c_int32(0)

View File

@ -14,11 +14,13 @@ import matplotlib.pyplot as plt
# Everything is done with Python only code and with the new pylibbpf library. # Everything is done with Python only code and with the new pylibbpf library.
# Run `sudo /path/to/python/binary/ clone_plot.py` # Run `sudo /path/to/python/binary/ clone_plot.py`
@bpf @bpf
@map @map
def hist() -> HashMap: def hist() -> HashMap:
return HashMap(key=c_int32, value=c_uint64, max_entries=4096) return HashMap(key=c_int32, value=c_uint64, max_entries=4096)
@bpf @bpf
@section("tracepoint/syscalls/sys_enter_clone") @section("tracepoint/syscalls/sys_enter_clone")
def hello(ctx: c_void_p) -> c_int64: def hello(ctx: c_void_p) -> c_int64:

View File

@ -1,4 +1,4 @@
from pythonbpf import bpf, section, bpfglobal, compile, BPF from pythonbpf import bpf, section, bpfglobal, BPF
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
# Instructions to how to run this program # Instructions to how to run this program
@ -13,11 +13,13 @@ def hello_world(ctx: c_void_p) -> c_int64:
print("Hello, World!") print("Hello, World!")
return c_int64(0) return c_int64(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
b = BPF() b = BPF()
b.load_and_attach() b.load_and_attach()
if b.is_loaded() and b.is_attached(): if b.is_loaded() and b.is_attached():

View File

@ -2,7 +2,7 @@ from pythonbpf import bpf, map, struct, section, bpfglobal, compile
from pythonbpf.helpers import ktime, pid from pythonbpf.helpers import ktime, pid
from pythonbpf.maps import PerfEventArray from pythonbpf.maps import PerfEventArray
from ctypes import c_void_p, c_int64, c_int32, c_uint64 from ctypes import c_void_p, c_int32, c_uint64
@bpf @bpf

View File

@ -10,6 +10,7 @@ from ctypes import c_void_p, c_int64, c_uint64
# 3. Run the program with sudo: sudo tools/check.sh run examples/sys_sync.o # 3. Run the program with sudo: sudo tools/check.sh run examples/sys_sync.o
# 4. Start a Python repl and `import os` and then keep entering `os.sync()` to see reponses. # 4. Start a Python repl and `import os` and then keep entering `os.sync()` to see reponses.
@bpf @bpf
@map @map
def last() -> HashMap: def last() -> HashMap:
@ -23,9 +24,9 @@ def do_trace(ctx: c_void_p) -> c_int64:
tsp = last().lookup(key) tsp = last().lookup(key)
if tsp: if tsp:
kt = ktime() kt = ktime()
delta = (kt - tsp) delta = kt - tsp
if delta < 1000000000: if delta < 1000000000:
time_ms = (delta // 1000000) time_ms = delta // 1000000
print(f"sync called within last second, last {time_ms} ms ago") print(f"sync called within last second, last {time_ms} ms ago")
last().delete(key) last().delete(key)
else: else:

View File

@ -149,7 +149,7 @@ class FunctionFactoryStub:
# libraries['FIXME_STUB'] explanation # libraries['FIXME_STUB'] explanation
# As you did not list (-l libraryname.so) a library that exports this function # As you did not list (-l libraryname.so) a library that exports this function
# This is a non-working stub instead. # This is a non-working stub instead.
# You can either re-run clan2py with -l /path/to/library.so # You can either re-run clan2py with -l /path/to/library.so
# Or manually fix this by comment the ctypes.CDLL loading # Or manually fix this by comment the ctypes.CDLL loading
_libraries = {} _libraries = {}

View File

@ -11,6 +11,7 @@ from ctypes import c_void_p, c_int64
# 4. Attach object file to any network device with something like ./check.sh xdp examples/xdp_pass.o tailscale0 # 4. Attach object file to any network device with something like ./check.sh xdp examples/xdp_pass.o tailscale0
# 5. send traffic through the device and observe effects # 5. send traffic through the device and observe effects
@bpf @bpf
@map @map
def count() -> HashMap: def count() -> HashMap:
@ -33,9 +34,11 @@ def hello_world(ctx: c_void_p) -> c_int64:
return XDP_PASS return XDP_PASS
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -3,7 +3,7 @@ from llvmlite import ir
def recursive_dereferencer(var, builder): def recursive_dereferencer(var, builder):
""" dereference until primitive type comes out""" """dereference until primitive type comes out"""
if var.type == ir.PointerType(ir.PointerType(ir.IntType(64))): if var.type == ir.PointerType(ir.PointerType(ir.IntType(64))):
a = builder.load(var) a = builder.load(var)
return recursive_dereferencer(a, builder) return recursive_dereferencer(a, builder)
@ -46,37 +46,26 @@ def handle_binary_op(rval, module, builder, var_name, local_sym_tab, map_sym_tab
print(f"left is {left}, right is {right}, op is {op}") print(f"left is {left}, right is {right}, op is {op}")
if isinstance(op, ast.Add): if isinstance(op, ast.Add):
builder.store(builder.add(left, right), builder.store(builder.add(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.Sub): elif isinstance(op, ast.Sub):
builder.store(builder.sub(left, right), builder.store(builder.sub(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.Mult): elif isinstance(op, ast.Mult):
builder.store(builder.mul(left, right), builder.store(builder.mul(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.Div): elif isinstance(op, ast.Div):
builder.store(builder.sdiv(left, right), builder.store(builder.sdiv(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.Mod): elif isinstance(op, ast.Mod):
builder.store(builder.srem(left, right), builder.store(builder.srem(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.LShift): elif isinstance(op, ast.LShift):
builder.store(builder.shl(left, right), builder.store(builder.shl(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.RShift): elif isinstance(op, ast.RShift):
builder.store(builder.lshr(left, right), builder.store(builder.lshr(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.BitOr): elif isinstance(op, ast.BitOr):
builder.store(builder.or_(left, right), builder.store(builder.or_(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.BitXor): elif isinstance(op, ast.BitXor):
builder.store(builder.xor(left, right), builder.store(builder.xor(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.BitAnd): elif isinstance(op, ast.BitAnd):
builder.store(builder.and_(left, right), builder.store(builder.and_(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
elif isinstance(op, ast.FloorDiv): elif isinstance(op, ast.FloorDiv):
builder.store(builder.udiv(left, right), builder.store(builder.udiv(left, right), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
else: else:
raise SyntaxError("Unsupported binary operation") raise SyntaxError("Unsupported binary operation")

View File

@ -3,7 +3,16 @@ from llvmlite import ir
from .expr_pass import eval_expr from .expr_pass import eval_expr
def bpf_ktime_get_ns_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_ktime_get_ns_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
""" """
Emit LLVM IR for bpf_ktime_get_ns helper function call. Emit LLVM IR for bpf_ktime_get_ns helper function call.
""" """
@ -16,13 +25,23 @@ def bpf_ktime_get_ns_emitter(call, map_ptr, module, builder, func, local_sym_tab
return result, ir.IntType(64) return result, ir.IntType(64)
def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_map_lookup_elem_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
""" """
Emit LLVM IR for bpf_map_lookup_elem helper function call. Emit LLVM IR for bpf_map_lookup_elem helper function call.
""" """
if call.args and len(call.args) != 1: if call.args and len(call.args) != 1:
raise ValueError("Map lookup expects exactly one argument, got " raise ValueError(
f"{len(call.args)}") "Map lookup expects exactly one argument, got " f"{len(call.args)}"
)
key_arg = call.args[0] key_arg = call.args[0]
if isinstance(key_arg, ast.Name): if isinstance(key_arg, ast.Name):
key_name = key_arg.id key_name = key_arg.id
@ -30,7 +49,8 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, func, local_sym_
key_ptr = local_sym_tab[key_name][0] key_ptr = local_sym_tab[key_name][0]
else: else:
raise ValueError( raise ValueError(
f"Key variable {key_name} not found in local symbol table.") f"Key variable {key_name} not found in local symbol table."
)
elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int): elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int):
# handle constant integer keys # handle constant integer keys
key_val = key_arg.value key_val = key_arg.value
@ -40,7 +60,8 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, func, local_sym_
builder.store(ir.Constant(key_type, key_val), key_ptr) builder.store(ir.Constant(key_type, key_val), key_ptr)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple variable names are supported as keys in map lookup.") "Only simple variable names are supported as keys in map lookup."
)
if key_ptr is None: if key_ptr is None:
raise ValueError("Key pointer is None.") raise ValueError("Key pointer is None.")
@ -50,7 +71,7 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, func, local_sym_
fn_type = ir.FunctionType( fn_type = ir.FunctionType(
ir.PointerType(), # Return type: void* ir.PointerType(), # Return type: void*
[ir.PointerType(), ir.PointerType()], # Args: (void*, void*) [ir.PointerType(), ir.PointerType()], # Args: (void*, void*)
var_arg=False var_arg=False,
) )
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
@ -63,7 +84,16 @@ def bpf_map_lookup_elem_emitter(call, map_ptr, module, builder, func, local_sym_
return result, ir.PointerType() return result, ir.PointerType()
def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_printk_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
if not hasattr(func, "_fmt_counter"): if not hasattr(func, "_fmt_counter"):
func._fmt_counter = 0 func._fmt_counter = 0
@ -84,7 +114,8 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
exprs.append(ir.Constant(ir.IntType(64), value.value)) exprs.append(ir.Constant(ir.IntType(64), value.value))
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only string and integer constants are supported in f-string.") "Only string and integer constants are supported in f-string."
)
elif isinstance(value, ast.FormattedValue): elif isinstance(value, ast.FormattedValue):
print("Formatted value:", ast.dump(value)) print("Formatted value:", ast.dump(value))
# TODO: Dirty handling here, only checks for int or str # TODO: Dirty handling here, only checks for int or str
@ -100,13 +131,19 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
exprs.append(value.value) exprs.append(value.value)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only integer and pointer types are supported in formatted values.") "Only integer and pointer types are supported in formatted values."
)
else: else:
raise ValueError( raise ValueError(
f"Variable {value.value.id} not found in local symbol table.") f"Variable {value.value.id} not found in local symbol table."
)
elif isinstance(value.value, ast.Attribute): elif isinstance(value.value, ast.Attribute):
# object field access from struct # object field access from struct
if isinstance(value.value.value, ast.Name) and local_sym_tab and value.value.value.id in local_sym_tab: if (
isinstance(value.value.value, ast.Name)
and local_sym_tab
and value.value.value.id in local_sym_tab
):
var_name = value.value.value.id var_name = value.value.value.id
field_name = value.value.attr field_name = value.value.attr
if local_var_metadata and var_name in local_var_metadata: if local_var_metadata and var_name in local_var_metadata:
@ -114,8 +151,7 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
if var_type in struct_sym_tab: if var_type in struct_sym_tab:
struct_info = struct_sym_tab[var_type] struct_info = struct_sym_tab[var_type]
if field_name in struct_info.fields: if field_name in struct_info.fields:
field_type = struct_info.field_type( field_type = struct_info.field_type(field_name)
field_name)
if isinstance(field_type, ir.IntType): if isinstance(field_type, ir.IntType):
fmt_parts.append("%lld") fmt_parts.append("%lld")
exprs.append(value.value) exprs.append(value.value)
@ -124,39 +160,44 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
exprs.append(value.value) exprs.append(value.value)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only integer and pointer types are supported in formatted values.") "Only integer and pointer types are supported in formatted values."
)
else: else:
raise ValueError( raise ValueError(
f"Field {field_name} not found in struct {var_type}.") f"Field {field_name} not found in struct {var_type}."
)
else: else:
raise ValueError( raise ValueError(
f"Struct type {var_type} for variable {var_name} not found in struct symbol table.") f"Struct type {var_type} for variable {var_name} not found in struct symbol table."
)
else: else:
raise ValueError( raise ValueError(
f"Metadata for variable {var_name} not found in local variable metadata.") f"Metadata for variable {var_name} not found in local variable metadata."
)
else: else:
raise ValueError( raise ValueError(
f"Variable {value.value.value.id} not found in local symbol table.") f"Variable {value.value.value.id} not found in local symbol table."
)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple variable names are supported in formatted values.") "Only simple variable names are supported in formatted values."
)
else: else:
raise NotImplementedError( raise NotImplementedError("Unsupported value type in f-string.")
"Unsupported value type in f-string.")
fmt_str = "".join(fmt_parts) + "\n" + "\0" fmt_str = "".join(fmt_parts) + "\n" + "\0"
fmt_name = f"{func.name}____fmt{func._fmt_counter}" fmt_name = f"{func.name}____fmt{func._fmt_counter}"
func._fmt_counter += 1 func._fmt_counter += 1
fmt_gvar = ir.GlobalVariable( fmt_gvar = ir.GlobalVariable(
module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=fmt_name) module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=fmt_name
)
fmt_gvar.global_constant = True fmt_gvar.global_constant = True
fmt_gvar.initializer = ir.Constant( # type: ignore fmt_gvar.initializer = ir.Constant( # type: ignore
ir.ArrayType(ir.IntType(8), len(fmt_str)), ir.ArrayType(ir.IntType(8), len(fmt_str)), bytearray(fmt_str.encode("utf8"))
bytearray(fmt_str.encode("utf8"))
) )
fmt_gvar.linkage = "internal" fmt_gvar.linkage = "internal"
fmt_gvar.align = 1 # type: ignore fmt_gvar.align = 1 # type: ignore
fmt_ptr = builder.bitcast(fmt_gvar, ir.PointerType()) fmt_ptr = builder.bitcast(fmt_gvar, ir.PointerType())
@ -165,12 +206,21 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
# Only 3 args supported in bpf_printk # Only 3 args supported in bpf_printk
if len(exprs) > 3: if len(exprs) > 3:
print( print(
"Warning: bpf_printk supports up to 3 arguments, extra arguments will be ignored.") "Warning: bpf_printk supports up to 3 arguments, extra arguments will be ignored."
)
for expr in exprs[:3]: for expr in exprs[:3]:
print(f"{ast.dump(expr)}") print(f"{ast.dump(expr)}")
val, _ = eval_expr(func, module, builder, val, _ = eval_expr(
expr, local_sym_tab, None, struct_sym_tab, local_var_metadata) func,
module,
builder,
expr,
local_sym_tab,
None,
struct_sym_tab,
local_var_metadata,
)
if val: if val:
if isinstance(val.type, ir.PointerType): if isinstance(val.type, ir.PointerType):
val = builder.ptrtoint(val, ir.IntType(64)) val = builder.ptrtoint(val, ir.IntType(64))
@ -179,15 +229,18 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
val = builder.sext(val, ir.IntType(64)) val = builder.sext(val, ir.IntType(64))
else: else:
print( print(
"Warning: Only integer and pointer types are supported in bpf_printk arguments. Others will be converted to 0.") "Warning: Only integer and pointer types are supported in bpf_printk arguments. Others will be converted to 0."
)
val = ir.Constant(ir.IntType(64), 0) val = ir.Constant(ir.IntType(64), 0)
args.append(val) args.append(val)
else: else:
print( print(
"Warning: Failed to evaluate expression for bpf_printk argument. It will be converted to 0.") "Warning: Failed to evaluate expression for bpf_printk argument. It will be converted to 0."
)
args.append(ir.Constant(ir.IntType(64), 0)) args.append(ir.Constant(ir.IntType(64), 0))
fn_type = ir.FunctionType(ir.IntType( fn_type = ir.FunctionType(
64), [ir.PointerType(), ir.IntType(32)], var_arg=True) ir.IntType(64), [ir.PointerType(), ir.IntType(32)], var_arg=True
)
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
fn_addr = ir.Constant(ir.IntType(64), 6) fn_addr = ir.Constant(ir.IntType(64), 6)
fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type) fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type)
@ -200,36 +253,50 @@ def bpf_printk_emitter(call, map_ptr, module, builder, func, local_sym_tab=None,
func._fmt_counter += 1 func._fmt_counter += 1
fmt_gvar = ir.GlobalVariable( fmt_gvar = ir.GlobalVariable(
module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=fmt_name) module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=fmt_name
)
fmt_gvar.global_constant = True fmt_gvar.global_constant = True
fmt_gvar.initializer = ir.Constant( # type: ignore fmt_gvar.initializer = ir.Constant( # type: ignore
ir.ArrayType(ir.IntType(8), len(fmt_str)), ir.ArrayType(ir.IntType(8), len(fmt_str)),
bytearray(fmt_str.encode("utf8")) bytearray(fmt_str.encode("utf8")),
) )
fmt_gvar.linkage = "internal" fmt_gvar.linkage = "internal"
fmt_gvar.align = 1 # type: ignore fmt_gvar.align = 1 # type: ignore
fmt_ptr = builder.bitcast(fmt_gvar, ir.PointerType()) fmt_ptr = builder.bitcast(fmt_gvar, ir.PointerType())
fn_type = ir.FunctionType(ir.IntType( fn_type = ir.FunctionType(
64), [ir.PointerType(), ir.IntType(32)], var_arg=True) ir.IntType(64), [ir.PointerType(), ir.IntType(32)], var_arg=True
)
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
fn_addr = ir.Constant(ir.IntType(64), 6) fn_addr = ir.Constant(ir.IntType(64), 6)
fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type) fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type)
builder.call(fn_ptr, [fmt_ptr, ir.Constant( builder.call(
ir.IntType(32), len(fmt_str))], tail=True) fn_ptr, [fmt_ptr, ir.Constant(ir.IntType(32), len(fmt_str))], tail=True
)
return None return None
def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_map_update_elem_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
""" """
Emit LLVM IR for bpf_map_update_elem helper function call. Emit LLVM IR for bpf_map_update_elem helper function call.
Expected call signature: map.update(key, value, flags=0) Expected call signature: map.update(key, value, flags=0)
""" """
if not call.args or len(call.args) < 2 or len(call.args) > 3: if not call.args or len(call.args) < 2 or len(call.args) > 3:
raise ValueError("Map update expects 2 or 3 arguments (key, value, flags), got " raise ValueError(
f"{len(call.args)}") "Map update expects 2 or 3 arguments (key, value, flags), got "
f"{len(call.args)}"
)
key_arg = call.args[0] key_arg = call.args[0]
value_arg = call.args[1] value_arg = call.args[1]
@ -242,7 +309,8 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
key_ptr = local_sym_tab[key_name][0] key_ptr = local_sym_tab[key_name][0]
else: else:
raise ValueError( raise ValueError(
f"Key variable {key_name} not found in local symbol table.") f"Key variable {key_name} not found in local symbol table."
)
elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int): elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int):
# Handle constant integer keys # Handle constant integer keys
key_val = key_arg.value key_val = key_arg.value
@ -252,7 +320,8 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
builder.store(ir.Constant(key_type, key_val), key_ptr) builder.store(ir.Constant(key_type, key_val), key_ptr)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple variable names and integer constants are supported as keys in map update.") "Only simple variable names and integer constants are supported as keys in map update."
)
# Handle value # Handle value
if isinstance(value_arg, ast.Name): if isinstance(value_arg, ast.Name):
@ -261,7 +330,8 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
value_ptr = local_sym_tab[value_name][0] value_ptr = local_sym_tab[value_name][0]
else: else:
raise ValueError( raise ValueError(
f"Value variable {value_name} not found in local symbol table.") f"Value variable {value_name} not found in local symbol table."
)
elif isinstance(value_arg, ast.Constant) and isinstance(value_arg.value, int): elif isinstance(value_arg, ast.Constant) and isinstance(value_arg.value, int):
# Handle constant integers # Handle constant integers
value_val = value_arg.value value_val = value_arg.value
@ -271,7 +341,8 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
builder.store(ir.Constant(value_type, value_val), value_ptr) builder.store(ir.Constant(value_type, value_val), value_ptr)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple variable names and integer constants are supported as values in map update.") "Only simple variable names and integer constants are supported as values in map update."
)
# Handle flags argument (defaults to 0) # Handle flags argument (defaults to 0)
if flags_arg is not None: if flags_arg is not None:
@ -285,10 +356,12 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
flags_val = builder.load(flags_ptr) flags_val = builder.load(flags_ptr)
else: else:
raise ValueError( raise ValueError(
f"Flags variable {flags_name} not found in local symbol table.") f"Flags variable {flags_name} not found in local symbol table."
)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only integer constants and simple variable names are supported as flags in map update.") "Only integer constants and simple variable names are supported as flags in map update."
)
else: else:
flags_val = 0 flags_val = 0
@ -299,7 +372,7 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
fn_type = ir.FunctionType( fn_type = ir.FunctionType(
ir.IntType(64), ir.IntType(64),
[ir.PointerType(), ir.PointerType(), ir.PointerType(), ir.IntType(64)], [ir.PointerType(), ir.PointerType(), ir.PointerType(), ir.IntType(64)],
var_arg=False var_arg=False,
) )
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
@ -313,20 +386,31 @@ def bpf_map_update_elem_emitter(call, map_ptr, module, builder, func, local_sym_
flags_const = flags_val flags_const = flags_val
result = builder.call( result = builder.call(
fn_ptr, [map_void_ptr, key_ptr, value_ptr, flags_const], tail=False) fn_ptr, [map_void_ptr, key_ptr, value_ptr, flags_const], tail=False
)
return result, None return result, None
def bpf_map_delete_elem_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_map_delete_elem_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
""" """
Emit LLVM IR for bpf_map_delete_elem helper function call. Emit LLVM IR for bpf_map_delete_elem helper function call.
Expected call signature: map.delete(key) Expected call signature: map.delete(key)
""" """
# Check for correct number of arguments # Check for correct number of arguments
if not call.args or len(call.args) != 1: if not call.args or len(call.args) != 1:
raise ValueError("Map delete expects exactly 1 argument (key), got " raise ValueError(
f"{len(call.args)}") "Map delete expects exactly 1 argument (key), got " f"{len(call.args)}"
)
key_arg = call.args[0] key_arg = call.args[0]
@ -337,7 +421,8 @@ def bpf_map_delete_elem_emitter(call, map_ptr, module, builder, func, local_sym_
key_ptr = local_sym_tab[key_name][0] key_ptr = local_sym_tab[key_name][0]
else: else:
raise ValueError( raise ValueError(
f"Key variable {key_name} not found in local symbol table.") f"Key variable {key_name} not found in local symbol table."
)
elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int): elif isinstance(key_arg, ast.Constant) and isinstance(key_arg.value, int):
# Handle constant integer keys # Handle constant integer keys
key_val = key_arg.value key_val = key_arg.value
@ -347,7 +432,8 @@ def bpf_map_delete_elem_emitter(call, map_ptr, module, builder, func, local_sym_
builder.store(ir.Constant(key_type, key_val), key_ptr) builder.store(ir.Constant(key_type, key_val), key_ptr)
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple variable names and integer constants are supported as keys in map delete.") "Only simple variable names and integer constants are supported as keys in map delete."
)
if key_ptr is None: if key_ptr is None:
raise ValueError("Key pointer is None.") raise ValueError("Key pointer is None.")
@ -359,7 +445,7 @@ def bpf_map_delete_elem_emitter(call, map_ptr, module, builder, func, local_sym_
fn_type = ir.FunctionType( fn_type = ir.FunctionType(
ir.IntType(64), # Return type: int64 (status code) ir.IntType(64), # Return type: int64 (status code)
[ir.PointerType(), ir.PointerType()], # Args: (void*, void*) [ir.PointerType(), ir.PointerType()], # Args: (void*, void*)
var_arg=False var_arg=False,
) )
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
@ -373,7 +459,16 @@ def bpf_map_delete_elem_emitter(call, map_ptr, module, builder, func, local_sym_
return result, None return result, None
def bpf_get_current_pid_tgid_emitter(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_get_current_pid_tgid_emitter(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
""" """
Emit LLVM IR for bpf_get_current_pid_tgid helper function call. Emit LLVM IR for bpf_get_current_pid_tgid helper function call.
""" """
@ -390,10 +485,21 @@ def bpf_get_current_pid_tgid_emitter(call, map_ptr, module, builder, func, local
return pid, ir.IntType(64) return pid, ir.IntType(64)
def bpf_perf_event_output_handler(call, map_ptr, module, builder, func, local_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def bpf_perf_event_output_handler(
call,
map_ptr,
module,
builder,
func,
local_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
if len(call.args) != 1: if len(call.args) != 1:
raise ValueError("Perf event output expects exactly one argument (data), got " raise ValueError(
f"{len(call.args)}") "Perf event output expects exactly one argument (data), got "
f"{len(call.args)}"
)
data_arg = call.args[0] data_arg = call.args[0]
ctx_ptr = func.args[0] # First argument to the function is ctx ctx_ptr = func.args[0] # First argument to the function is ctx
@ -403,7 +509,8 @@ def bpf_perf_event_output_handler(call, map_ptr, module, builder, func, local_sy
data_ptr = local_sym_tab[data_name][0] data_ptr = local_sym_tab[data_name][0]
else: else:
raise ValueError( raise ValueError(
f"Data variable {data_name} not found in local symbol table.") f"Data variable {data_name} not found in local symbol table."
)
# Check is data_name is a struct # Check is data_name is a struct
if local_var_metadata and data_name in local_var_metadata: if local_var_metadata and data_name in local_var_metadata:
data_type = local_var_metadata[data_name] data_type = local_var_metadata[data_name]
@ -412,10 +519,12 @@ def bpf_perf_event_output_handler(call, map_ptr, module, builder, func, local_sy
size_val = ir.Constant(ir.IntType(64), struct_info.size) size_val = ir.Constant(ir.IntType(64), struct_info.size)
else: else:
raise ValueError( raise ValueError(
f"Struct type {data_type} for variable {data_name} not found in struct symbol table.") f"Struct type {data_type} for variable {data_name} not found in struct symbol table."
)
else: else:
raise ValueError( raise ValueError(
f"Metadata for variable {data_name} not found in local variable metadata.") f"Metadata for variable {data_name} not found in local variable metadata."
)
# BPF_F_CURRENT_CPU is -1 in 32 bit # BPF_F_CURRENT_CPU is -1 in 32 bit
flags_val = ir.Constant(ir.IntType(64), 0xFFFFFFFF) flags_val = ir.Constant(ir.IntType(64), 0xFFFFFFFF)
@ -424,9 +533,14 @@ def bpf_perf_event_output_handler(call, map_ptr, module, builder, func, local_sy
data_void_ptr = builder.bitcast(data_ptr, ir.PointerType()) data_void_ptr = builder.bitcast(data_ptr, ir.PointerType())
fn_type = ir.FunctionType( fn_type = ir.FunctionType(
ir.IntType(64), ir.IntType(64),
[ir.PointerType(ir.IntType(8)), ir.PointerType(), ir.IntType(64), [
ir.PointerType(), ir.IntType(64)], ir.PointerType(ir.IntType(8)),
var_arg=False ir.PointerType(),
ir.IntType(64),
ir.PointerType(),
ir.IntType(64),
],
var_arg=False,
) )
fn_ptr_type = ir.PointerType(fn_type) fn_ptr_type = ir.PointerType(fn_type)
@ -435,11 +549,15 @@ def bpf_perf_event_output_handler(call, map_ptr, module, builder, func, local_sy
fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type) fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type)
result = builder.call( result = builder.call(
fn_ptr, [ctx_ptr, map_void_ptr, flags_val, data_void_ptr, size_val], tail=False) fn_ptr,
[ctx_ptr, map_void_ptr, flags_val, data_void_ptr, size_val],
tail=False,
)
return result, None return result, None
else: else:
raise NotImplementedError( raise NotImplementedError(
"Only simple object names are supported as data in perf event output.") "Only simple object names are supported as data in perf event output."
)
helper_func_list = { helper_func_list = {
@ -453,19 +571,40 @@ helper_func_list = {
} }
def handle_helper_call(call, module, builder, func, local_sym_tab=None, map_sym_tab=None, struct_sym_tab=None, local_var_metadata=None): def handle_helper_call(
call,
module,
builder,
func,
local_sym_tab=None,
map_sym_tab=None,
struct_sym_tab=None,
local_var_metadata=None,
):
print(local_var_metadata) print(local_var_metadata)
if isinstance(call.func, ast.Name): if isinstance(call.func, ast.Name):
func_name = call.func.id func_name = call.func.id
if func_name in helper_func_list: if func_name in helper_func_list:
# it is not a map method call # it is not a map method call
return helper_func_list[func_name](call, None, module, builder, func, local_sym_tab, struct_sym_tab, local_var_metadata) return helper_func_list[func_name](
call,
None,
module,
builder,
func,
local_sym_tab,
struct_sym_tab,
local_var_metadata,
)
else: else:
raise NotImplementedError( raise NotImplementedError(
f"Function {func_name} is not implemented as a helper function.") f"Function {func_name} is not implemented as a helper function."
)
elif isinstance(call.func, ast.Attribute): elif isinstance(call.func, ast.Attribute):
# likely a map method call # likely a map method call
if isinstance(call.func.value, ast.Call) and isinstance(call.func.value.func, ast.Name): if isinstance(call.func.value, ast.Call) and isinstance(
call.func.value.func, ast.Name
):
map_name = call.func.value.func.id map_name = call.func.value.func.id
method_name = call.func.attr method_name = call.func.attr
if map_sym_tab and map_name in map_sym_tab: if map_sym_tab and map_name in map_sym_tab:
@ -473,13 +612,21 @@ def handle_helper_call(call, module, builder, func, local_sym_tab=None, map_sym_
if method_name in helper_func_list: if method_name in helper_func_list:
print(local_var_metadata) print(local_var_metadata)
return helper_func_list[method_name]( return helper_func_list[method_name](
call, map_ptr, module, builder, func, local_sym_tab, struct_sym_tab, local_var_metadata) call,
map_ptr,
module,
builder,
func,
local_sym_tab,
struct_sym_tab,
local_var_metadata,
)
else: else:
raise NotImplementedError( raise NotImplementedError(
f"Map method {method_name} is not implemented as a helper function.") f"Map method {method_name} is not implemented as a helper function."
)
else: else:
raise ValueError( raise ValueError(f"Map variable {map_name} not found in symbol tables.")
f"Map variable {map_name} not found in symbol tables.")
elif isinstance(call.func.value, ast.Name): elif isinstance(call.func.value, ast.Name):
obj_name = call.func.value.id obj_name = call.func.value.id
method_name = call.func.attr method_name = call.func.attr
@ -487,14 +634,21 @@ def handle_helper_call(call, module, builder, func, local_sym_tab=None, map_sym_
map_ptr = map_sym_tab[obj_name] map_ptr = map_sym_tab[obj_name]
if method_name in helper_func_list: if method_name in helper_func_list:
return helper_func_list[method_name]( return helper_func_list[method_name](
call, map_ptr, module, builder, func, local_sym_tab, struct_sym_tab, local_var_metadata) call,
map_ptr,
module,
builder,
func,
local_sym_tab,
struct_sym_tab,
local_var_metadata,
)
else: else:
raise NotImplementedError( raise NotImplementedError(
f"Map method {method_name} is not implemented as a helper function.") f"Map method {method_name} is not implemented as a helper function."
)
else: else:
raise ValueError( raise ValueError(f"Map variable {obj_name} not found in symbol tables.")
f"Map variable {obj_name} not found in symbol tables.")
else: else:
raise NotImplementedError( raise NotImplementedError("Attribute not supported for map method calls.")
"Attribute not supported for map method calls.")
return None return None

View File

@ -52,45 +52,67 @@ def compile_to_ir(filename: str, output: str):
module.data_layout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" module.data_layout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
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(
"filename": filename, "DIFile",
"directory": os.path.dirname(filename) { # type: ignore
}) "filename": 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(
"language": DW_LANG_C11, "DICompileUnit",
"file": module._file_metadata, # type: ignore { # type: ignore
"producer": f"PythonBPF {VERSION}", "language": DW_LANG_C11,
"isOptimized": True, # TODO: This is probably not true "file": module._file_metadata, # type: ignore
# TODO: add a global field here that keeps track of all the globals. Works without it, but I think it might "producer": f"PythonBPF {VERSION}",
# be required for kprobes. "isOptimized": True, # TODO: This is probably not true
"runtimeVersion": 0, # TODO: add a global field here that keeps track of all the globals. Works without it, but I think it might
"emissionKind": 1, # be required for kprobes.
"splitDebugInlining": False, "runtimeVersion": 0,
"nameTableKind": 0 "emissionKind": 1,
}, is_distinct=True) "splitDebugInlining": False,
"nameTableKind": 0,
},
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([DwarfBehaviorEnum.ERROR_IF_MISMATCH, wchar_size = module.add_metadata(
"wchar_size", [
ir.Constant(ir.IntType(32), 4)]) DwarfBehaviorEnum.ERROR_IF_MISMATCH,
frame_pointer = module.add_metadata([DwarfBehaviorEnum.OVERRIDE_USE_LARGEST, "wchar_size",
"frame-pointer", ir.Constant(ir.IntType(32), 4),
ir.Constant(ir.IntType(32), 2)]) ]
)
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) # Add Debug Info Version (3 = DWARF v3, which LLVM expects)
debug_info_version = module.add_metadata([DwarfBehaviorEnum.WARNING_IF_MISMATCH, debug_info_version = module.add_metadata(
"Debug Info Version", [
ir.Constant(ir.IntType(32), 3)]) DwarfBehaviorEnum.WARNING_IF_MISMATCH,
"Debug Info Version",
ir.Constant(ir.IntType(32), 3),
]
)
# Add explicit DWARF version 5 # Add explicit DWARF version 5
dwarf_version = module.add_metadata([DwarfBehaviorEnum.OVERRIDE_USE_LARGEST, dwarf_version = module.add_metadata(
"Dwarf Version", [
ir.Constant(ir.IntType(32), 5)]) DwarfBehaviorEnum.OVERRIDE_USE_LARGEST,
"Dwarf Version",
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)
@ -101,7 +123,7 @@ def compile_to_ir(filename: str, output: str):
print(f"IR written to {output}") print(f"IR written to {output}")
with open(output, "w") as f: with open(output, "w") as f:
f.write(f"source_filename = \"{filename}\"\n") f.write(f'source_filename = "{filename}"\n')
f.write(str(module)) f.write(str(module))
f.write("\n") f.write("\n")
@ -119,10 +141,21 @@ def compile() -> bool:
success = True success = True
success = compile_to_ir(str(caller_file), str(ll_file)) and success success = compile_to_ir(str(caller_file), str(ll_file)) and success
success = subprocess.run([ success = (
"llc", "-march=bpf", "-filetype=obj", "-O2", subprocess.run(
str(ll_file), "-o", str(o_file) [
], check=True) and success "llc",
"-march=bpf",
"-filetype=obj",
"-O2",
str(ll_file),
"-o",
str(o_file),
],
check=True,
)
and success
)
print(f"Object written to {o_file}") print(f"Object written to {o_file}")
return success return success
@ -131,16 +164,28 @@ def compile() -> bool:
def BPF() -> BpfProgram: 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(
tempfile.NamedTemporaryFile(mode="w+", delete=True, suffix=".ll") as inter, \ mode="w+", delete=True, suffix=".py"
tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".o") as obj_file: ) as f, tempfile.NamedTemporaryFile(
mode="w+", delete=True, suffix=".ll"
) as inter, 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
compile_to_ir(source, str(inter.name)) compile_to_ir(source, str(inter.name))
subprocess.run([ subprocess.run(
"llc", "-march=bpf", "-filetype=obj", "-O2", [
str(inter.name), "-o", str(obj_file.name) "llc",
], check=True) "-march=bpf",
"-filetype=obj",
"-O2",
str(inter.name),
"-o",
str(obj_file.name),
],
check=True,
)
return BpfProgram(str(obj_file.name)) return BpfProgram(str(obj_file.name))

View File

@ -4,7 +4,7 @@ Provides utilities for generating DWARF/BTF debug information
""" """
from . import dwarf_constants as dc from . import dwarf_constants as dc
from typing import Dict, Any, List, Optional, Union from typing import Any, List
class DebugInfoGenerator: class DebugInfoGenerator:
@ -16,11 +16,9 @@ class DebugInfoGenerator:
"""Get or create a basic type with caching""" """Get or create a basic type with caching"""
key = (name, size, encoding) key = (name, size, encoding)
if key not in self._type_cache: if key not in self._type_cache:
self._type_cache[key] = self.module.add_debug_info("DIBasicType", { self._type_cache[key] = self.module.add_debug_info(
"name": name, "DIBasicType", {"name": name, "size": size, "encoding": encoding}
"size": size, )
"encoding": encoding
})
return self._type_cache[key] return self._type_cache[key]
def get_uint32_type(self) -> Any: def get_uint32_type(self) -> Any:
@ -33,21 +31,23 @@ class DebugInfoGenerator:
def create_pointer_type(self, base_type: Any, size: int = 64) -> Any: def create_pointer_type(self, base_type: Any, size: int = 64) -> Any:
"""Create a pointer type to the given base type""" """Create a pointer type to the given base type"""
return self.module.add_debug_info("DIDerivedType", { return self.module.add_debug_info(
"tag": dc.DW_TAG_pointer_type, "DIDerivedType",
"baseType": base_type, {"tag": dc.DW_TAG_pointer_type, "baseType": base_type, "size": size},
"size": size )
})
def create_array_type(self, base_type: Any, count: int) -> Any: def create_array_type(self, base_type: Any, count: int) -> Any:
"""Create an array type of the given base type with specified count""" """Create an array type of the given base type with specified count"""
subrange = self.module.add_debug_info("DISubrange", {"count": count}) subrange = self.module.add_debug_info("DISubrange", {"count": count})
return self.module.add_debug_info("DICompositeType", { return self.module.add_debug_info(
"tag": dc.DW_TAG_array_type, "DICompositeType",
"baseType": base_type, {
"size": self._compute_array_size(base_type, count), "tag": dc.DW_TAG_array_type,
"elements": [subrange] "baseType": base_type,
}) "size": self._compute_array_size(base_type, count),
"elements": [subrange],
},
)
@staticmethod @staticmethod
def _compute_array_size(base_type: Any, count: int) -> int: def _compute_array_size(base_type: Any, count: int) -> int:
@ -57,36 +57,51 @@ class DebugInfoGenerator:
def create_struct_member(self, name: str, base_type: Any, offset: int) -> Any: def create_struct_member(self, name: str, base_type: Any, offset: int) -> Any:
"""Create a struct member with the given name, type, and offset""" """Create a struct member with the given name, type, and offset"""
return self.module.add_debug_info("DIDerivedType", { return self.module.add_debug_info(
"tag": dc.DW_TAG_member, "DIDerivedType",
"name": name, {
"file": self.module._file_metadata, "tag": dc.DW_TAG_member,
"baseType": base_type, "name": name,
"size": getattr(base_type, "size", 64), "file": self.module._file_metadata,
"offset": offset "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: def create_struct_type(
self, members: List[Any], size: int, is_distinct: bool
) -> Any:
"""Create a struct type with the given members and size""" """Create a struct type with the given members and size"""
return self.module.add_debug_info("DICompositeType", { return self.module.add_debug_info(
"tag": dc.DW_TAG_structure_type, "DICompositeType",
"file": self.module._file_metadata, {
"size": size, "tag": dc.DW_TAG_structure_type,
"elements": members, "file": self.module._file_metadata,
}, is_distinct=is_distinct) "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: def create_global_var_debug_info(
self, name: str, var_type: Any, is_local: bool = False
) -> Any:
"""Create debug info for a global variable""" """Create debug info for a global variable"""
global_var = self.module.add_debug_info("DIGlobalVariable", { global_var = self.module.add_debug_info(
"name": name, "DIGlobalVariable",
"scope": self.module._debug_compile_unit, {
"file": self.module._file_metadata, "name": name,
"type": var_type, "scope": self.module._debug_compile_unit,
"isLocal": is_local, "file": self.module._file_metadata,
"isDefinition": True "type": var_type,
}, is_distinct=True) "isLocal": is_local,
"isDefinition": True,
},
is_distinct=True,
)
return self.module.add_debug_info("DIGlobalVariableExpression", { return self.module.add_debug_info(
"var": global_var, "DIGlobalVariableExpression",
"expr": self.module.add_debug_info("DIExpression", {}) {"var": global_var, "expr": self.module.add_debug_info("DIExpression", {})},
}) )

View File

@ -1,5 +1,6 @@
import llvmlite.ir as ir import llvmlite.ir as ir
class DwarfBehaviorEnum: class DwarfBehaviorEnum:
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)

View File

@ -7,7 +7,7 @@ DW_UT_skeleton = 0x04
DW_UT_split_compile = 0x05 DW_UT_split_compile = 0x05
DW_UT_split_type = 0x06 DW_UT_split_type = 0x06
DW_UT_lo_user = 0x80 DW_UT_lo_user = 0x80
DW_UT_hi_user = 0xff DW_UT_hi_user = 0xFF
DW_TAG_array_type = 0x01 DW_TAG_array_type = 0x01
DW_TAG_class_type = 0x02 DW_TAG_class_type = 0x02
@ -15,10 +15,10 @@ DW_TAG_entry_point = 0x03
DW_TAG_enumeration_type = 0x04 DW_TAG_enumeration_type = 0x04
DW_TAG_formal_parameter = 0x05 DW_TAG_formal_parameter = 0x05
DW_TAG_imported_declaration = 0x08 DW_TAG_imported_declaration = 0x08
DW_TAG_label = 0x0a DW_TAG_label = 0x0A
DW_TAG_lexical_block = 0x0b DW_TAG_lexical_block = 0x0B
DW_TAG_member = 0x0d DW_TAG_member = 0x0D
DW_TAG_pointer_type = 0x0f DW_TAG_pointer_type = 0x0F
DW_TAG_reference_type = 0x10 DW_TAG_reference_type = 0x10
DW_TAG_compile_unit = 0x11 DW_TAG_compile_unit = 0x11
DW_TAG_string_type = 0x12 DW_TAG_string_type = 0x12
@ -28,12 +28,12 @@ DW_TAG_typedef = 0x16
DW_TAG_union_type = 0x17 DW_TAG_union_type = 0x17
DW_TAG_unspecified_parameters = 0x18 DW_TAG_unspecified_parameters = 0x18
DW_TAG_variant = 0x19 DW_TAG_variant = 0x19
DW_TAG_common_block = 0x1a DW_TAG_common_block = 0x1A
DW_TAG_common_inclusion = 0x1b DW_TAG_common_inclusion = 0x1B
DW_TAG_inheritance = 0x1c DW_TAG_inheritance = 0x1C
DW_TAG_inlined_subroutine = 0x1d DW_TAG_inlined_subroutine = 0x1D
DW_TAG_module = 0x1e DW_TAG_module = 0x1E
DW_TAG_ptr_to_member_type = 0x1f DW_TAG_ptr_to_member_type = 0x1F
DW_TAG_set_type = 0x20 DW_TAG_set_type = 0x20
DW_TAG_subrange_type = 0x21 DW_TAG_subrange_type = 0x21
DW_TAG_with_stmt = 0x22 DW_TAG_with_stmt = 0x22
@ -44,12 +44,12 @@ DW_TAG_const_type = 0x26
DW_TAG_constant = 0x27 DW_TAG_constant = 0x27
DW_TAG_enumerator = 0x28 DW_TAG_enumerator = 0x28
DW_TAG_file_type = 0x29 DW_TAG_file_type = 0x29
DW_TAG_friend = 0x2a DW_TAG_friend = 0x2A
DW_TAG_namelist = 0x2b DW_TAG_namelist = 0x2B
DW_TAG_namelist_item = 0x2c DW_TAG_namelist_item = 0x2C
DW_TAG_packed_type = 0x2d DW_TAG_packed_type = 0x2D
DW_TAG_subprogram = 0x2e DW_TAG_subprogram = 0x2E
DW_TAG_template_type_parameter = 0x2f DW_TAG_template_type_parameter = 0x2F
DW_TAG_template_value_parameter = 0x30 DW_TAG_template_value_parameter = 0x30
DW_TAG_thrown_type = 0x31 DW_TAG_thrown_type = 0x31
DW_TAG_try_block = 0x32 DW_TAG_try_block = 0x32
@ -60,11 +60,11 @@ DW_TAG_dwarf_procedure = 0x36
DW_TAG_restrict_type = 0x37 DW_TAG_restrict_type = 0x37
DW_TAG_interface_type = 0x38 DW_TAG_interface_type = 0x38
DW_TAG_namespace = 0x39 DW_TAG_namespace = 0x39
DW_TAG_imported_module = 0x3a DW_TAG_imported_module = 0x3A
DW_TAG_unspecified_type = 0x3b DW_TAG_unspecified_type = 0x3B
DW_TAG_partial_unit = 0x3c DW_TAG_partial_unit = 0x3C
DW_TAG_imported_unit = 0x3d DW_TAG_imported_unit = 0x3D
DW_TAG_condition = 0x3f DW_TAG_condition = 0x3F
DW_TAG_shared_type = 0x40 DW_TAG_shared_type = 0x40
DW_TAG_type_unit = 0x41 DW_TAG_type_unit = 0x41
DW_TAG_rvalue_reference_type = 0x42 DW_TAG_rvalue_reference_type = 0x42
@ -75,8 +75,8 @@ DW_TAG_dynamic_type = 0x46
DW_TAG_atomic_type = 0x47 DW_TAG_atomic_type = 0x47
DW_TAG_call_site = 0x48 DW_TAG_call_site = 0x48
DW_TAG_call_site_parameter = 0x49 DW_TAG_call_site_parameter = 0x49
DW_TAG_skeleton_unit = 0x4a DW_TAG_skeleton_unit = 0x4A
DW_TAG_immutable_type = 0x4b DW_TAG_immutable_type = 0x4B
DW_TAG_lo_user = 0x4080 DW_TAG_lo_user = 0x4080
DW_TAG_MIPS_loop = 0x4081 DW_TAG_MIPS_loop = 0x4081
DW_TAG_format_label = 0x4101 DW_TAG_format_label = 0x4101
@ -88,8 +88,8 @@ DW_TAG_GNU_template_template_param = 0x4106
DW_TAG_GNU_template_parameter_pack = 0x4107 DW_TAG_GNU_template_parameter_pack = 0x4107
DW_TAG_GNU_formal_parameter_pack = 0x4108 DW_TAG_GNU_formal_parameter_pack = 0x4108
DW_TAG_GNU_call_site = 0x4109 DW_TAG_GNU_call_site = 0x4109
DW_TAG_GNU_call_site_parameter = 0x410a DW_TAG_GNU_call_site_parameter = 0x410A
DW_TAG_hi_user = 0xffff DW_TAG_hi_user = 0xFFFF
DW_CHILDREN_no = 0 DW_CHILDREN_no = 0
DW_CHILDREN_yes = 1 DW_CHILDREN_yes = 1
@ -98,9 +98,9 @@ DW_AT_sibling = 0x01
DW_AT_location = 0x02 DW_AT_location = 0x02
DW_AT_name = 0x03 DW_AT_name = 0x03
DW_AT_ordering = 0x09 DW_AT_ordering = 0x09
DW_AT_byte_size = 0x0b DW_AT_byte_size = 0x0B
DW_AT_bit_offset = 0x0c DW_AT_bit_offset = 0x0C
DW_AT_bit_size = 0x0d DW_AT_bit_size = 0x0D
DW_AT_stmt_list = 0x10 DW_AT_stmt_list = 0x10
DW_AT_low_pc = 0x11 DW_AT_low_pc = 0x11
DW_AT_high_pc = 0x12 DW_AT_high_pc = 0x12
@ -110,20 +110,20 @@ DW_AT_discr_value = 0x16
DW_AT_visibility = 0x17 DW_AT_visibility = 0x17
DW_AT_import = 0x18 DW_AT_import = 0x18
DW_AT_string_length = 0x19 DW_AT_string_length = 0x19
DW_AT_common_reference = 0x1a DW_AT_common_reference = 0x1A
DW_AT_comp_dir = 0x1b DW_AT_comp_dir = 0x1B
DW_AT_const_value = 0x1c DW_AT_const_value = 0x1C
DW_AT_containing_type = 0x1d DW_AT_containing_type = 0x1D
DW_AT_default_value = 0x1e DW_AT_default_value = 0x1E
DW_AT_inline = 0x20 DW_AT_inline = 0x20
DW_AT_is_optional = 0x21 DW_AT_is_optional = 0x21
DW_AT_lower_bound = 0x22 DW_AT_lower_bound = 0x22
DW_AT_producer = 0x25 DW_AT_producer = 0x25
DW_AT_prototyped = 0x27 DW_AT_prototyped = 0x27
DW_AT_return_addr = 0x2a DW_AT_return_addr = 0x2A
DW_AT_start_scope = 0x2c DW_AT_start_scope = 0x2C
DW_AT_bit_stride = 0x2e DW_AT_bit_stride = 0x2E
DW_AT_upper_bound = 0x2f DW_AT_upper_bound = 0x2F
DW_AT_abstract_origin = 0x31 DW_AT_abstract_origin = 0x31
DW_AT_accessibility = 0x32 DW_AT_accessibility = 0x32
DW_AT_address_class = 0x33 DW_AT_address_class = 0x33
@ -133,12 +133,12 @@ DW_AT_calling_convention = 0x36
DW_AT_count = 0x37 DW_AT_count = 0x37
DW_AT_data_member_location = 0x38 DW_AT_data_member_location = 0x38
DW_AT_decl_column = 0x39 DW_AT_decl_column = 0x39
DW_AT_decl_file = 0x3a DW_AT_decl_file = 0x3A
DW_AT_decl_line = 0x3b DW_AT_decl_line = 0x3B
DW_AT_declaration = 0x3c DW_AT_declaration = 0x3C
DW_AT_discr_list = 0x3d DW_AT_discr_list = 0x3D
DW_AT_encoding = 0x3e DW_AT_encoding = 0x3E
DW_AT_external = 0x3f DW_AT_external = 0x3F
DW_AT_frame_base = 0x40 DW_AT_frame_base = 0x40
DW_AT_friend = 0x41 DW_AT_friend = 0x41
DW_AT_identifier_case = 0x42 DW_AT_identifier_case = 0x42
@ -149,12 +149,12 @@ DW_AT_segment = 0x46
DW_AT_specification = 0x47 DW_AT_specification = 0x47
DW_AT_static_link = 0x48 DW_AT_static_link = 0x48
DW_AT_type = 0x49 DW_AT_type = 0x49
DW_AT_use_location = 0x4a DW_AT_use_location = 0x4A
DW_AT_variable_parameter = 0x4b DW_AT_variable_parameter = 0x4B
DW_AT_virtuality = 0x4c DW_AT_virtuality = 0x4C
DW_AT_vtable_elem_location = 0x4d DW_AT_vtable_elem_location = 0x4D
DW_AT_allocated = 0x4e DW_AT_allocated = 0x4E
DW_AT_associated = 0x4f DW_AT_associated = 0x4F
DW_AT_data_location = 0x50 DW_AT_data_location = 0x50
DW_AT_byte_stride = 0x51 DW_AT_byte_stride = 0x51
DW_AT_entry_pc = 0x52 DW_AT_entry_pc = 0x52
@ -165,12 +165,12 @@ DW_AT_trampoline = 0x56
DW_AT_call_column = 0x57 DW_AT_call_column = 0x57
DW_AT_call_file = 0x58 DW_AT_call_file = 0x58
DW_AT_call_line = 0x59 DW_AT_call_line = 0x59
DW_AT_description = 0x5a DW_AT_description = 0x5A
DW_AT_binary_scale = 0x5b DW_AT_binary_scale = 0x5B
DW_AT_decimal_scale = 0x5c DW_AT_decimal_scale = 0x5C
DW_AT_small = 0x5d DW_AT_small = 0x5D
DW_AT_decimal_sign = 0x5e DW_AT_decimal_sign = 0x5E
DW_AT_digit_count = 0x5f DW_AT_digit_count = 0x5F
DW_AT_picture_string = 0x60 DW_AT_picture_string = 0x60
DW_AT_mutable = 0x61 DW_AT_mutable = 0x61
DW_AT_threads_scaled = 0x62 DW_AT_threads_scaled = 0x62
@ -181,12 +181,12 @@ DW_AT_elemental = 0x66
DW_AT_pure = 0x67 DW_AT_pure = 0x67
DW_AT_recursive = 0x68 DW_AT_recursive = 0x68
DW_AT_signature = 0x69 DW_AT_signature = 0x69
DW_AT_main_subprogram = 0x6a DW_AT_main_subprogram = 0x6A
DW_AT_data_bit_offset = 0x6b DW_AT_data_bit_offset = 0x6B
DW_AT_const_expr = 0x6c DW_AT_const_expr = 0x6C
DW_AT_enum_class = 0x6d DW_AT_enum_class = 0x6D
DW_AT_linkage_name = 0x6e DW_AT_linkage_name = 0x6E
DW_AT_string_length_bit_size = 0x6f DW_AT_string_length_bit_size = 0x6F
DW_AT_string_length_byte_size = 0x70 DW_AT_string_length_byte_size = 0x70
DW_AT_rank = 0x71 DW_AT_rank = 0x71
DW_AT_str_offsets_base = 0x72 DW_AT_str_offsets_base = 0x72
@ -196,12 +196,12 @@ DW_AT_dwo_name = 0x76
DW_AT_reference = 0x77 DW_AT_reference = 0x77
DW_AT_rvalue_reference = 0x78 DW_AT_rvalue_reference = 0x78
DW_AT_macros = 0x79 DW_AT_macros = 0x79
DW_AT_call_all_calls = 0x7a DW_AT_call_all_calls = 0x7A
DW_AT_call_all_source_calls = 0x7b DW_AT_call_all_source_calls = 0x7B
DW_AT_call_all_tail_calls = 0x7c DW_AT_call_all_tail_calls = 0x7C
DW_AT_call_return_pc = 0x7d DW_AT_call_return_pc = 0x7D
DW_AT_call_value = 0x7e DW_AT_call_value = 0x7E
DW_AT_call_origin = 0x7f DW_AT_call_origin = 0x7F
DW_AT_call_parameter = 0x80 DW_AT_call_parameter = 0x80
DW_AT_call_pc = 0x81 DW_AT_call_pc = 0x81
DW_AT_call_tail_call = 0x82 DW_AT_call_tail_call = 0x82
@ -212,9 +212,9 @@ DW_AT_call_data_value = 0x86
DW_AT_noreturn = 0x87 DW_AT_noreturn = 0x87
DW_AT_alignment = 0x88 DW_AT_alignment = 0x88
DW_AT_export_symbols = 0x89 DW_AT_export_symbols = 0x89
DW_AT_deleted = 0x8a DW_AT_deleted = 0x8A
DW_AT_defaulted = 0x8b DW_AT_defaulted = 0x8B
DW_AT_loclists_base = 0x8c DW_AT_loclists_base = 0x8C
DW_AT_lo_user = 0x2000 DW_AT_lo_user = 0x2000
DW_AT_MIPS_fde = 0x2001 DW_AT_MIPS_fde = 0x2001
DW_AT_MIPS_loop_begin = 0x2002 DW_AT_MIPS_loop_begin = 0x2002
@ -225,12 +225,12 @@ DW_AT_MIPS_software_pipeline_depth = 0x2006
DW_AT_MIPS_linkage_name = 0x2007 DW_AT_MIPS_linkage_name = 0x2007
DW_AT_MIPS_stride = 0x2008 DW_AT_MIPS_stride = 0x2008
DW_AT_MIPS_abstract_name = 0x2009 DW_AT_MIPS_abstract_name = 0x2009
DW_AT_MIPS_clone_origin = 0x200a DW_AT_MIPS_clone_origin = 0x200A
DW_AT_MIPS_has_inlines = 0x200b DW_AT_MIPS_has_inlines = 0x200B
DW_AT_MIPS_stride_byte = 0x200c DW_AT_MIPS_stride_byte = 0x200C
DW_AT_MIPS_stride_elem = 0x200d DW_AT_MIPS_stride_elem = 0x200D
DW_AT_MIPS_ptr_dopetype = 0x200e DW_AT_MIPS_ptr_dopetype = 0x200E
DW_AT_MIPS_allocatable_dopetype = 0x200f DW_AT_MIPS_allocatable_dopetype = 0x200F
DW_AT_MIPS_assumed_shape_dopetype = 0x2010 DW_AT_MIPS_assumed_shape_dopetype = 0x2010
DW_AT_MIPS_assumed_size = 0x2011 DW_AT_MIPS_assumed_size = 0x2011
DW_AT_sf_names = 0x2101 DW_AT_sf_names = 0x2101
@ -242,12 +242,12 @@ DW_AT_body_end = 0x2106
DW_AT_GNU_vector = 0x2107 DW_AT_GNU_vector = 0x2107
DW_AT_GNU_guarded_by = 0x2108 DW_AT_GNU_guarded_by = 0x2108
DW_AT_GNU_pt_guarded_by = 0x2109 DW_AT_GNU_pt_guarded_by = 0x2109
DW_AT_GNU_guarded = 0x210a DW_AT_GNU_guarded = 0x210A
DW_AT_GNU_pt_guarded = 0x210b DW_AT_GNU_pt_guarded = 0x210B
DW_AT_GNU_locks_excluded = 0x210c DW_AT_GNU_locks_excluded = 0x210C
DW_AT_GNU_exclusive_locks_required = 0x210d DW_AT_GNU_exclusive_locks_required = 0x210D
DW_AT_GNU_shared_locks_required = 0x210e DW_AT_GNU_shared_locks_required = 0x210E
DW_AT_GNU_odr_signature = 0x210f DW_AT_GNU_odr_signature = 0x210F
DW_AT_GNU_template_name = 0x2110 DW_AT_GNU_template_name = 0x2110
DW_AT_GNU_call_site_value = 0x2111 DW_AT_GNU_call_site_value = 0x2111
DW_AT_GNU_call_site_data_value = 0x2112 DW_AT_GNU_call_site_data_value = 0x2112
@ -260,7 +260,7 @@ DW_AT_GNU_all_source_call_sites = 0x2118
DW_AT_GNU_locviews = 0x2137 DW_AT_GNU_locviews = 0x2137
DW_AT_GNU_entry_view = 0x2138 DW_AT_GNU_entry_view = 0x2138
DW_AT_GNU_macros = 0x2119 DW_AT_GNU_macros = 0x2119
DW_AT_GNU_deleted = 0x211a DW_AT_GNU_deleted = 0x211A
DW_AT_GNU_dwo_name = 0x2130 DW_AT_GNU_dwo_name = 0x2130
DW_AT_GNU_dwo_id = 0x2131 DW_AT_GNU_dwo_id = 0x2131
DW_AT_GNU_ranges_base = 0x2132 DW_AT_GNU_ranges_base = 0x2132
@ -270,7 +270,7 @@ DW_AT_GNU_pubtypes = 0x2135
DW_AT_GNU_numerator = 0x2303 DW_AT_GNU_numerator = 0x2303
DW_AT_GNU_denominator = 0x2304 DW_AT_GNU_denominator = 0x2304
DW_AT_GNU_bias = 0x2305 DW_AT_GNU_bias = 0x2305
DW_AT_hi_user = 0x3fff DW_AT_hi_user = 0x3FFF
DW_FORM_addr = 0x01 DW_FORM_addr = 0x01
DW_FORM_block2 = 0x03 DW_FORM_block2 = 0x03
@ -280,12 +280,12 @@ DW_FORM_data4 = 0x06
DW_FORM_data8 = 0x07 DW_FORM_data8 = 0x07
DW_FORM_string = 0x08 DW_FORM_string = 0x08
DW_FORM_block = 0x09 DW_FORM_block = 0x09
DW_FORM_block1 = 0x0a DW_FORM_block1 = 0x0A
DW_FORM_data1 = 0x0b DW_FORM_data1 = 0x0B
DW_FORM_flag = 0x0c DW_FORM_flag = 0x0C
DW_FORM_sdata = 0x0d DW_FORM_sdata = 0x0D
DW_FORM_strp = 0x0e DW_FORM_strp = 0x0E
DW_FORM_udata = 0x0f DW_FORM_udata = 0x0F
DW_FORM_ref_addr = 0x10 DW_FORM_ref_addr = 0x10
DW_FORM_ref1 = 0x11 DW_FORM_ref1 = 0x11
DW_FORM_ref2 = 0x12 DW_FORM_ref2 = 0x12
@ -296,12 +296,12 @@ DW_FORM_indirect = 0x16
DW_FORM_sec_offset = 0x17 DW_FORM_sec_offset = 0x17
DW_FORM_exprloc = 0x18 DW_FORM_exprloc = 0x18
DW_FORM_flag_present = 0x19 DW_FORM_flag_present = 0x19
DW_FORM_strx = 0x1a DW_FORM_strx = 0x1A
DW_FORM_addrx = 0x1b DW_FORM_addrx = 0x1B
DW_FORM_ref_sup4 = 0x1c DW_FORM_ref_sup4 = 0x1C
DW_FORM_strp_sup = 0x1d DW_FORM_strp_sup = 0x1D
DW_FORM_data16 = 0x1e DW_FORM_data16 = 0x1E
DW_FORM_line_strp = 0x1f DW_FORM_line_strp = 0x1F
DW_FORM_ref_sig8 = 0x20 DW_FORM_ref_sig8 = 0x20
DW_FORM_implicit_const = 0x21 DW_FORM_implicit_const = 0x21
DW_FORM_loclistx = 0x22 DW_FORM_loclistx = 0x22
@ -312,24 +312,24 @@ DW_FORM_strx2 = 0x26
DW_FORM_strx3 = 0x27 DW_FORM_strx3 = 0x27
DW_FORM_strx4 = 0x28 DW_FORM_strx4 = 0x28
DW_FORM_addrx1 = 0x29 DW_FORM_addrx1 = 0x29
DW_FORM_addrx2 = 0x2a DW_FORM_addrx2 = 0x2A
DW_FORM_addrx3 = 0x2b DW_FORM_addrx3 = 0x2B
DW_FORM_addrx4 = 0x2c DW_FORM_addrx4 = 0x2C
DW_FORM_GNU_addr_index = 0x1f01 DW_FORM_GNU_addr_index = 0x1F01
DW_FORM_GNU_str_index = 0x1f02 DW_FORM_GNU_str_index = 0x1F02
DW_FORM_GNU_ref_alt = 0x1f20 DW_FORM_GNU_ref_alt = 0x1F20
DW_FORM_GNU_strp_alt = 0x1f21 DW_FORM_GNU_strp_alt = 0x1F21
DW_OP_addr = 0x03 DW_OP_addr = 0x03
DW_OP_deref = 0x06 DW_OP_deref = 0x06
DW_OP_const1u = 0x08 DW_OP_const1u = 0x08
DW_OP_const1s = 0x09 DW_OP_const1s = 0x09
DW_OP_const2u = 0x0a DW_OP_const2u = 0x0A
DW_OP_const2s = 0x0b DW_OP_const2s = 0x0B
DW_OP_const4u = 0x0c DW_OP_const4u = 0x0C
DW_OP_const4s = 0x0d DW_OP_const4s = 0x0D
DW_OP_const8u = 0x0e DW_OP_const8u = 0x0E
DW_OP_const8s = 0x0f DW_OP_const8s = 0x0F
DW_OP_constu = 0x10 DW_OP_constu = 0x10
DW_OP_consts = 0x11 DW_OP_consts = 0x11
DW_OP_dup = 0x12 DW_OP_dup = 0x12
@ -340,12 +340,12 @@ DW_OP_swap = 0x16
DW_OP_rot = 0x17 DW_OP_rot = 0x17
DW_OP_xderef = 0x18 DW_OP_xderef = 0x18
DW_OP_abs = 0x19 DW_OP_abs = 0x19
DW_OP_and = 0x1a DW_OP_and = 0x1A
DW_OP_div = 0x1b DW_OP_div = 0x1B
DW_OP_minus = 0x1c DW_OP_minus = 0x1C
DW_OP_mod = 0x1d DW_OP_mod = 0x1D
DW_OP_mul = 0x1e DW_OP_mul = 0x1E
DW_OP_neg = 0x1f DW_OP_neg = 0x1F
DW_OP_not = 0x20 DW_OP_not = 0x20
DW_OP_or = 0x21 DW_OP_or = 0x21
DW_OP_plus = 0x22 DW_OP_plus = 0x22
@ -356,12 +356,12 @@ DW_OP_shra = 0x26
DW_OP_xor = 0x27 DW_OP_xor = 0x27
DW_OP_bra = 0x28 DW_OP_bra = 0x28
DW_OP_eq = 0x29 DW_OP_eq = 0x29
DW_OP_ge = 0x2a DW_OP_ge = 0x2A
DW_OP_gt = 0x2b DW_OP_gt = 0x2B
DW_OP_le = 0x2c DW_OP_le = 0x2C
DW_OP_lt = 0x2d DW_OP_lt = 0x2D
DW_OP_ne = 0x2e DW_OP_ne = 0x2E
DW_OP_skip = 0x2f DW_OP_skip = 0x2F
DW_OP_lit0 = 0x30 DW_OP_lit0 = 0x30
DW_OP_lit1 = 0x31 DW_OP_lit1 = 0x31
DW_OP_lit2 = 0x32 DW_OP_lit2 = 0x32
@ -372,12 +372,12 @@ DW_OP_lit6 = 0x36
DW_OP_lit7 = 0x37 DW_OP_lit7 = 0x37
DW_OP_lit8 = 0x38 DW_OP_lit8 = 0x38
DW_OP_lit9 = 0x39 DW_OP_lit9 = 0x39
DW_OP_lit10 = 0x3a DW_OP_lit10 = 0x3A
DW_OP_lit11 = 0x3b DW_OP_lit11 = 0x3B
DW_OP_lit12 = 0x3c DW_OP_lit12 = 0x3C
DW_OP_lit13 = 0x3d DW_OP_lit13 = 0x3D
DW_OP_lit14 = 0x3e DW_OP_lit14 = 0x3E
DW_OP_lit15 = 0x3f DW_OP_lit15 = 0x3F
DW_OP_lit16 = 0x40 DW_OP_lit16 = 0x40
DW_OP_lit17 = 0x41 DW_OP_lit17 = 0x41
DW_OP_lit18 = 0x42 DW_OP_lit18 = 0x42
@ -388,12 +388,12 @@ DW_OP_lit22 = 0x46
DW_OP_lit23 = 0x47 DW_OP_lit23 = 0x47
DW_OP_lit24 = 0x48 DW_OP_lit24 = 0x48
DW_OP_lit25 = 0x49 DW_OP_lit25 = 0x49
DW_OP_lit26 = 0x4a DW_OP_lit26 = 0x4A
DW_OP_lit27 = 0x4b DW_OP_lit27 = 0x4B
DW_OP_lit28 = 0x4c DW_OP_lit28 = 0x4C
DW_OP_lit29 = 0x4d DW_OP_lit29 = 0x4D
DW_OP_lit30 = 0x4e DW_OP_lit30 = 0x4E
DW_OP_lit31 = 0x4f DW_OP_lit31 = 0x4F
DW_OP_reg0 = 0x50 DW_OP_reg0 = 0x50
DW_OP_reg1 = 0x51 DW_OP_reg1 = 0x51
DW_OP_reg2 = 0x52 DW_OP_reg2 = 0x52
@ -404,12 +404,12 @@ DW_OP_reg6 = 0x56
DW_OP_reg7 = 0x57 DW_OP_reg7 = 0x57
DW_OP_reg8 = 0x58 DW_OP_reg8 = 0x58
DW_OP_reg9 = 0x59 DW_OP_reg9 = 0x59
DW_OP_reg10 = 0x5a DW_OP_reg10 = 0x5A
DW_OP_reg11 = 0x5b DW_OP_reg11 = 0x5B
DW_OP_reg12 = 0x5c DW_OP_reg12 = 0x5C
DW_OP_reg13 = 0x5d DW_OP_reg13 = 0x5D
DW_OP_reg14 = 0x5e DW_OP_reg14 = 0x5E
DW_OP_reg15 = 0x5f DW_OP_reg15 = 0x5F
DW_OP_reg16 = 0x60 DW_OP_reg16 = 0x60
DW_OP_reg17 = 0x61 DW_OP_reg17 = 0x61
DW_OP_reg18 = 0x62 DW_OP_reg18 = 0x62
@ -420,12 +420,12 @@ DW_OP_reg22 = 0x66
DW_OP_reg23 = 0x67 DW_OP_reg23 = 0x67
DW_OP_reg24 = 0x68 DW_OP_reg24 = 0x68
DW_OP_reg25 = 0x69 DW_OP_reg25 = 0x69
DW_OP_reg26 = 0x6a DW_OP_reg26 = 0x6A
DW_OP_reg27 = 0x6b DW_OP_reg27 = 0x6B
DW_OP_reg28 = 0x6c DW_OP_reg28 = 0x6C
DW_OP_reg29 = 0x6d DW_OP_reg29 = 0x6D
DW_OP_reg30 = 0x6e DW_OP_reg30 = 0x6E
DW_OP_reg31 = 0x6f DW_OP_reg31 = 0x6F
DW_OP_breg0 = 0x70 DW_OP_breg0 = 0x70
DW_OP_breg1 = 0x71 DW_OP_breg1 = 0x71
DW_OP_breg2 = 0x72 DW_OP_breg2 = 0x72
@ -436,12 +436,12 @@ DW_OP_breg6 = 0x76
DW_OP_breg7 = 0x77 DW_OP_breg7 = 0x77
DW_OP_breg8 = 0x78 DW_OP_breg8 = 0x78
DW_OP_breg9 = 0x79 DW_OP_breg9 = 0x79
DW_OP_breg10 = 0x7a DW_OP_breg10 = 0x7A
DW_OP_breg11 = 0x7b DW_OP_breg11 = 0x7B
DW_OP_breg12 = 0x7c DW_OP_breg12 = 0x7C
DW_OP_breg13 = 0x7d DW_OP_breg13 = 0x7D
DW_OP_breg14 = 0x7e DW_OP_breg14 = 0x7E
DW_OP_breg15 = 0x7f DW_OP_breg15 = 0x7F
DW_OP_breg16 = 0x80 DW_OP_breg16 = 0x80
DW_OP_breg17 = 0x81 DW_OP_breg17 = 0x81
DW_OP_breg18 = 0x82 DW_OP_breg18 = 0x82
@ -452,12 +452,12 @@ DW_OP_breg22 = 0x86
DW_OP_breg23 = 0x87 DW_OP_breg23 = 0x87
DW_OP_breg24 = 0x88 DW_OP_breg24 = 0x88
DW_OP_breg25 = 0x89 DW_OP_breg25 = 0x89
DW_OP_breg26 = 0x8a DW_OP_breg26 = 0x8A
DW_OP_breg27 = 0x8b DW_OP_breg27 = 0x8B
DW_OP_breg28 = 0x8c DW_OP_breg28 = 0x8C
DW_OP_breg29 = 0x8d DW_OP_breg29 = 0x8D
DW_OP_breg30 = 0x8e DW_OP_breg30 = 0x8E
DW_OP_breg31 = 0x8f DW_OP_breg31 = 0x8F
DW_OP_regx = 0x90 DW_OP_regx = 0x90
DW_OP_fbreg = 0x91 DW_OP_fbreg = 0x91
DW_OP_bregx = 0x92 DW_OP_bregx = 0x92
@ -468,38 +468,38 @@ DW_OP_nop = 0x96
DW_OP_push_object_address = 0x97 DW_OP_push_object_address = 0x97
DW_OP_call2 = 0x98 DW_OP_call2 = 0x98
DW_OP_call4 = 0x99 DW_OP_call4 = 0x99
DW_OP_call_ref = 0x9a DW_OP_call_ref = 0x9A
DW_OP_form_tls_address = 0x9b DW_OP_form_tls_address = 0x9B
DW_OP_call_frame_cfa = 0x9c DW_OP_call_frame_cfa = 0x9C
DW_OP_bit_piece = 0x9d DW_OP_bit_piece = 0x9D
DW_OP_implicit_value = 0x9e DW_OP_implicit_value = 0x9E
DW_OP_stack_value = 0x9f DW_OP_stack_value = 0x9F
DW_OP_implicit_pointer = 0xa0 DW_OP_implicit_pointer = 0xA0
DW_OP_addrx = 0xa1 DW_OP_addrx = 0xA1
DW_OP_constx = 0xa2 DW_OP_constx = 0xA2
DW_OP_entry_value = 0xa3 DW_OP_entry_value = 0xA3
DW_OP_const_type = 0xa4 DW_OP_const_type = 0xA4
DW_OP_regval_type = 0xa5 DW_OP_regval_type = 0xA5
DW_OP_deref_type = 0xa6 DW_OP_deref_type = 0xA6
DW_OP_xderef_type = 0xa7 DW_OP_xderef_type = 0xA7
DW_OP_convert = 0xa8 DW_OP_convert = 0xA8
DW_OP_reinterpret = 0xa9 DW_OP_reinterpret = 0xA9
DW_OP_GNU_push_tls_address = 0xe0 DW_OP_GNU_push_tls_address = 0xE0
DW_OP_GNU_uninit = 0xf0 DW_OP_GNU_uninit = 0xF0
DW_OP_GNU_encoded_addr = 0xf1 DW_OP_GNU_encoded_addr = 0xF1
DW_OP_GNU_implicit_pointer = 0xf2 DW_OP_GNU_implicit_pointer = 0xF2
DW_OP_GNU_entry_value = 0xf3 DW_OP_GNU_entry_value = 0xF3
DW_OP_GNU_const_type = 0xf4 DW_OP_GNU_const_type = 0xF4
DW_OP_GNU_regval_type = 0xf5 DW_OP_GNU_regval_type = 0xF5
DW_OP_GNU_deref_type = 0xf6 DW_OP_GNU_deref_type = 0xF6
DW_OP_GNU_convert = 0xf7 DW_OP_GNU_convert = 0xF7
DW_OP_GNU_reinterpret = 0xf9 DW_OP_GNU_reinterpret = 0xF9
DW_OP_GNU_parameter_ref = 0xfa DW_OP_GNU_parameter_ref = 0xFA
DW_OP_GNU_addr_index = 0xfb DW_OP_GNU_addr_index = 0xFB
DW_OP_GNU_const_index = 0xfc DW_OP_GNU_const_index = 0xFC
DW_OP_GNU_variable_value = 0xfd DW_OP_GNU_variable_value = 0xFD
DW_OP_lo_user = 0xe0 DW_OP_lo_user = 0xE0
DW_OP_hi_user = 0xff DW_OP_hi_user = 0xFF
DW_ATE_void = 0x0 DW_ATE_void = 0x0
DW_ATE_address = 0x1 DW_ATE_address = 0x1
@ -511,17 +511,17 @@ DW_ATE_signed_char = 0x6
DW_ATE_unsigned = 0x7 DW_ATE_unsigned = 0x7
DW_ATE_unsigned_char = 0x8 DW_ATE_unsigned_char = 0x8
DW_ATE_imaginary_float = 0x9 DW_ATE_imaginary_float = 0x9
DW_ATE_packed_decimal = 0xa DW_ATE_packed_decimal = 0xA
DW_ATE_numeric_string = 0xb DW_ATE_numeric_string = 0xB
DW_ATE_edited = 0xc DW_ATE_edited = 0xC
DW_ATE_signed_fixed = 0xd DW_ATE_signed_fixed = 0xD
DW_ATE_unsigned_fixed = 0xe DW_ATE_unsigned_fixed = 0xE
DW_ATE_decimal_float = 0xf DW_ATE_decimal_float = 0xF
DW_ATE_UTF = 0x10 DW_ATE_UTF = 0x10
DW_ATE_UCS = 0x11 DW_ATE_UCS = 0x11
DW_ATE_ASCII = 0x12 DW_ATE_ASCII = 0x12
DW_ATE_lo_user = 0x80 DW_ATE_lo_user = 0x80
DW_ATE_hi_user = 0xff DW_ATE_hi_user = 0xFF
DW_DS_unsigned = 1 DW_DS_unsigned = 1
DW_DS_leading_overpunch = 2 DW_DS_leading_overpunch = 2
@ -533,7 +533,7 @@ DW_END_default = 0
DW_END_big = 1 DW_END_big = 1
DW_END_little = 2 DW_END_little = 2
DW_END_lo_user = 0x40 DW_END_lo_user = 0x40
DW_END_hi_user = 0xff DW_END_hi_user = 0xFF
DW_ACCESS_public = 1 DW_ACCESS_public = 1
DW_ACCESS_protected = 2 DW_ACCESS_protected = 2
@ -556,12 +556,12 @@ DW_LANG_Cobol85 = 0x0006
DW_LANG_Fortran77 = 0x0007 DW_LANG_Fortran77 = 0x0007
DW_LANG_Fortran90 = 0x0008 DW_LANG_Fortran90 = 0x0008
DW_LANG_Pascal83 = 0x0009 DW_LANG_Pascal83 = 0x0009
DW_LANG_Modula2 = 0x000a DW_LANG_Modula2 = 0x000A
DW_LANG_Java = 0x000b DW_LANG_Java = 0x000B
DW_LANG_C99 = 0x000c DW_LANG_C99 = 0x000C
DW_LANG_Ada95 = 0x000d DW_LANG_Ada95 = 0x000D
DW_LANG_Fortran95 = 0x000e DW_LANG_Fortran95 = 0x000E
DW_LANG_PLI = 0x000f DW_LANG_PLI = 0x000F
DW_LANG_ObjC = 0x0010 DW_LANG_ObjC = 0x0010
DW_LANG_ObjC_plus_plus = 0x0011 DW_LANG_ObjC_plus_plus = 0x0011
DW_LANG_UPC = 0x0012 DW_LANG_UPC = 0x0012
@ -572,12 +572,12 @@ DW_LANG_Go = 0x0016
DW_LANG_Modula3 = 0x0017 DW_LANG_Modula3 = 0x0017
DW_LANG_Haskell = 0x0018 DW_LANG_Haskell = 0x0018
DW_LANG_C_plus_plus_03 = 0x0019 DW_LANG_C_plus_plus_03 = 0x0019
DW_LANG_C_plus_plus_11 = 0x001a DW_LANG_C_plus_plus_11 = 0x001A
DW_LANG_OCaml = 0x001b DW_LANG_OCaml = 0x001B
DW_LANG_Rust = 0x001c DW_LANG_Rust = 0x001C
DW_LANG_C11 = 0x001d DW_LANG_C11 = 0x001D
DW_LANG_Swift = 0x001e DW_LANG_Swift = 0x001E
DW_LANG_Julia = 0x001f DW_LANG_Julia = 0x001F
DW_LANG_Dylan = 0x0020 DW_LANG_Dylan = 0x0020
DW_LANG_C_plus_plus_14 = 0x0021 DW_LANG_C_plus_plus_14 = 0x0021
DW_LANG_Fortran03 = 0x0022 DW_LANG_Fortran03 = 0x0022
@ -586,7 +586,7 @@ DW_LANG_RenderScript = 0x0024
DW_LANG_BLISS = 0x0025 DW_LANG_BLISS = 0x0025
DW_LANG_lo_user = 0x8000 DW_LANG_lo_user = 0x8000
DW_LANG_Mips_Assembler = 0x8001 DW_LANG_Mips_Assembler = 0x8001
DW_LANG_hi_user = 0xffff DW_LANG_hi_user = 0xFFFF
DW_ID_case_sensitive = 0 DW_ID_case_sensitive = 0
DW_ID_up_case = 1 DW_ID_up_case = 1
@ -599,7 +599,7 @@ DW_CC_nocall = 0x3
DW_CC_pass_by_reference = 0x4 DW_CC_pass_by_reference = 0x4
DW_CC_pass_by_value = 0x5 DW_CC_pass_by_value = 0x5
DW_CC_lo_user = 0x40 DW_CC_lo_user = 0x40
DW_CC_hi_user = 0xff DW_CC_hi_user = 0xFF
DW_INL_not_inlined = 0 DW_INL_not_inlined = 0
DW_INL_inlined = 1 DW_INL_inlined = 1
@ -622,7 +622,7 @@ DW_LNCT_timestamp = 0x3
DW_LNCT_size = 0x4 DW_LNCT_size = 0x4
DW_LNCT_MD5 = 0x5 DW_LNCT_MD5 = 0x5
DW_LNCT_lo_user = 0x2000 DW_LNCT_lo_user = 0x2000
DW_LNCT_hi_user = 0x3fff DW_LNCT_hi_user = 0x3FFF
DW_LNS_copy = 1 DW_LNS_copy = 1
DW_LNS_advance_pc = 2 DW_LNS_advance_pc = 2
@ -659,11 +659,11 @@ DW_MACRO_undef_strp = 0x06
DW_MACRO_import = 0x07 DW_MACRO_import = 0x07
DW_MACRO_define_sup = 0x08 DW_MACRO_define_sup = 0x08
DW_MACRO_undef_sup = 0x09 DW_MACRO_undef_sup = 0x09
DW_MACRO_import_sup = 0x0a DW_MACRO_import_sup = 0x0A
DW_MACRO_define_strx = 0x0b DW_MACRO_define_strx = 0x0B
DW_MACRO_undef_strx = 0x0c DW_MACRO_undef_strx = 0x0C
DW_MACRO_lo_user = 0xe0 DW_MACRO_lo_user = 0xE0
DW_MACRO_hi_user = 0xff DW_MACRO_hi_user = 0xFF
DW_RLE_end_of_list = 0x0 DW_RLE_end_of_list = 0x0
DW_RLE_base_addressx = 0x1 DW_RLE_base_addressx = 0x1
@ -691,7 +691,7 @@ DW_LLE_GNU_start_length_entry = 0x3
DW_CFA_advance_loc = 0x40 DW_CFA_advance_loc = 0x40
DW_CFA_offset = 0x80 DW_CFA_offset = 0x80
DW_CFA_restore = 0xc0 DW_CFA_restore = 0xC0
DW_CFA_extended = 0 DW_CFA_extended = 0
DW_CFA_nop = 0x00 DW_CFA_nop = 0x00
DW_CFA_set_loc = 0x01 DW_CFA_set_loc = 0x01
@ -703,12 +703,12 @@ DW_CFA_restore_extended = 0x06
DW_CFA_undefined = 0x07 DW_CFA_undefined = 0x07
DW_CFA_same_value = 0x08 DW_CFA_same_value = 0x08
DW_CFA_register = 0x09 DW_CFA_register = 0x09
DW_CFA_remember_state = 0x0a DW_CFA_remember_state = 0x0A
DW_CFA_restore_state = 0x0b DW_CFA_restore_state = 0x0B
DW_CFA_def_cfa = 0x0c DW_CFA_def_cfa = 0x0C
DW_CFA_def_cfa_register = 0x0d DW_CFA_def_cfa_register = 0x0D
DW_CFA_def_cfa_offset = 0x0e DW_CFA_def_cfa_offset = 0x0E
DW_CFA_def_cfa_expression = 0x0f DW_CFA_def_cfa_expression = 0x0F
DW_CFA_expression = 0x10 DW_CFA_expression = 0x10
DW_CFA_offset_extended_sf = 0x11 DW_CFA_offset_extended_sf = 0x11
DW_CFA_def_cfa_sf = 0x12 DW_CFA_def_cfa_sf = 0x12
@ -716,26 +716,26 @@ DW_CFA_def_cfa_offset_sf = 0x13
DW_CFA_val_offset = 0x14 DW_CFA_val_offset = 0x14
DW_CFA_val_offset_sf = 0x15 DW_CFA_val_offset_sf = 0x15
DW_CFA_val_expression = 0x16 DW_CFA_val_expression = 0x16
DW_CFA_low_user = 0x1c DW_CFA_low_user = 0x1C
DW_CFA_MIPS_advance_loc8 = 0x1d DW_CFA_MIPS_advance_loc8 = 0x1D
DW_CFA_GNU_window_save = 0x2d DW_CFA_GNU_window_save = 0x2D
DW_CFA_GNU_args_size = 0x2e DW_CFA_GNU_args_size = 0x2E
DW_CFA_GNU_negative_offset_extended = 0x2f DW_CFA_GNU_negative_offset_extended = 0x2F
DW_CFA_high_user = 0x3f DW_CFA_high_user = 0x3F
DW_CIE_ID_32 = 0xffffffff DW_CIE_ID_32 = 0xFFFFFFFF
DW_CIE_ID_64 = 0xffffffffffffffff DW_CIE_ID_64 = 0xFFFFFFFFFFFFFFFF
DW_EH_PE_absptr = 0x00 DW_EH_PE_absptr = 0x00
DW_EH_PE_omit = 0xff DW_EH_PE_omit = 0xFF
DW_EH_PE_uleb128 = 0x01 DW_EH_PE_uleb128 = 0x01
DW_EH_PE_udata2 = 0x02 DW_EH_PE_udata2 = 0x02
DW_EH_PE_udata4 = 0x03 DW_EH_PE_udata4 = 0x03
DW_EH_PE_udata8 = 0x04 DW_EH_PE_udata8 = 0x04
DW_EH_PE_sleb128 = 0x09 DW_EH_PE_sleb128 = 0x09
DW_EH_PE_sdata2 = 0x0a DW_EH_PE_sdata2 = 0x0A
DW_EH_PE_sdata4 = 0x0b DW_EH_PE_sdata4 = 0x0B
DW_EH_PE_sdata8 = 0x0c DW_EH_PE_sdata8 = 0x0C
DW_EH_PE_signed = 0x08 DW_EH_PE_signed = 0x08
DW_EH_PE_pcrel = 0x10 DW_EH_PE_pcrel = 0x10
DW_EH_PE_textrel = 0x20 DW_EH_PE_textrel = 0x20

View File

@ -26,8 +26,10 @@ def section(name: str):
def wrapper(fn): def wrapper(fn):
fn._section = name fn._section = name
return fn return fn
return wrapper return wrapper
# from types import SimpleNamespace # from types import SimpleNamespace
# syscalls = SimpleNamespace( # syscalls = SimpleNamespace(

View File

@ -2,7 +2,16 @@ import ast
from llvmlite import ir from llvmlite import ir
def eval_expr(func, module, builder, expr, local_sym_tab, map_sym_tab, structs_sym_tab=None, local_var_metadata=None): def eval_expr(
func,
module,
builder,
expr,
local_sym_tab,
map_sym_tab,
structs_sym_tab=None,
local_var_metadata=None,
):
print(f"Evaluating expression: {ast.dump(expr)}") print(f"Evaluating expression: {ast.dump(expr)}")
print(local_var_metadata) print(local_var_metadata)
if isinstance(expr, ast.Name): if isinstance(expr, ast.Name):
@ -33,7 +42,11 @@ def eval_expr(func, module, builder, expr, local_sym_tab, map_sym_tab, structs_s
print("deref takes exactly one argument") print("deref takes exactly one argument")
return None return None
arg = expr.args[0] arg = expr.args[0]
if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Name) and arg.func.id == "deref": if (
isinstance(arg, ast.Call)
and isinstance(arg.func, ast.Name)
and arg.func.id == "deref"
):
print("Multiple deref not supported") print("Multiple deref not supported")
return None return None
if isinstance(arg, ast.Name): if isinstance(arg, ast.Name):
@ -52,29 +65,54 @@ def eval_expr(func, module, builder, expr, local_sym_tab, map_sym_tab, structs_s
# check for helpers # check for helpers
if expr.func.id in helper_func_list: if expr.func.id in helper_func_list:
return handle_helper_call( return handle_helper_call(
expr, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata) expr,
module,
builder,
func,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
elif isinstance(expr.func, ast.Attribute): elif isinstance(expr.func, ast.Attribute):
print(f"Handling method call: {ast.dump(expr.func)}") print(f"Handling method call: {ast.dump(expr.func)}")
if isinstance(expr.func.value, ast.Call) and isinstance(expr.func.value.func, ast.Name): if isinstance(expr.func.value, ast.Call) and isinstance(
expr.func.value.func, ast.Name
):
method_name = expr.func.attr method_name = expr.func.attr
if method_name in helper_func_list: if method_name in helper_func_list:
return handle_helper_call( return handle_helper_call(
expr, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata) expr,
module,
builder,
func,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
elif isinstance(expr.func.value, ast.Name): elif isinstance(expr.func.value, ast.Name):
obj_name = expr.func.value.id obj_name = expr.func.value.id
method_name = expr.func.attr method_name = expr.func.attr
if obj_name in map_sym_tab: if obj_name in map_sym_tab:
if method_name in helper_func_list: if method_name in helper_func_list:
return handle_helper_call( return handle_helper_call(
expr, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata) expr,
module,
builder,
func,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
elif isinstance(expr, ast.Attribute): elif isinstance(expr, ast.Attribute):
if isinstance(expr.value, ast.Name): if isinstance(expr.value, ast.Name):
var_name = expr.value.id var_name = expr.value.id
attr_name = expr.attr attr_name = expr.attr
if var_name in local_sym_tab: if var_name in local_sym_tab:
var_ptr, var_type = local_sym_tab[var_name] var_ptr, var_type = local_sym_tab[var_name]
print(f"Loading attribute " print(f"Loading attribute " f"{attr_name} from variable {var_name}")
f"{attr_name} from variable {var_name}")
print(f"Variable type: {var_type}, Variable ptr: {var_ptr}") print(f"Variable type: {var_type}, Variable ptr: {var_ptr}")
print(local_var_metadata) print(local_var_metadata)
if local_var_metadata and var_name in local_var_metadata: if local_var_metadata and var_name in local_var_metadata:
@ -88,13 +126,30 @@ def eval_expr(func, module, builder, expr, local_sym_tab, map_sym_tab, structs_s
return None return None
def handle_expr(func, module, builder, expr, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata): def handle_expr(
func,
module,
builder,
expr,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
):
"""Handle expression statements in the function body.""" """Handle expression statements in the function body."""
print(f"Handling expression: {ast.dump(expr)}") print(f"Handling expression: {ast.dump(expr)}")
print(local_var_metadata) print(local_var_metadata)
call = expr.value call = expr.value
if isinstance(call, ast.Call): if isinstance(call, ast.Call):
eval_expr(func, module, builder, call, local_sym_tab, eval_expr(
map_sym_tab, structs_sym_tab, local_var_metadata) func,
module,
builder,
call,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
else: else:
print("Unsupported expression type") print("Unsupported expression type")

View File

@ -27,7 +27,9 @@ def get_probe_string(func_node):
return "helper" return "helper"
def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab): def handle_assign(
func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab
):
"""Handle assignment statements in the function body.""" """Handle assignment statements in the function body."""
if len(stmt.targets) != 1: if len(stmt.targets) != 1:
print("Unsupported multiassignment") print("Unsupported multiassignment")
@ -51,10 +53,20 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
if field_name in struct_info.fields: if field_name in struct_info.fields:
field_ptr = struct_info.gep( field_ptr = struct_info.gep(
builder, local_sym_tab[var_name][0], field_name) builder, local_sym_tab[var_name][0], field_name
val = eval_expr(func, module, builder, rval, )
local_sym_tab, map_sym_tab, structs_sym_tab) val = eval_expr(
if isinstance(struct_info.field_type(field_name), ir.ArrayType) and val[1] == ir.PointerType(ir.IntType(8)): func,
module,
builder,
rval,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
)
if isinstance(struct_info.field_type(field_name), ir.ArrayType) and val[
1
] == ir.PointerType(ir.IntType(8)):
# TODO: Figure it out, not a priority rn # TODO: Figure it out, not a priority rn
# Special case for string assignment to char array # Special case for string assignment to char array
# str_len = struct_info["field_types"][field_idx].count # str_len = struct_info["field_types"][field_idx].count
@ -71,31 +83,31 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
elif isinstance(rval, ast.Constant): elif isinstance(rval, ast.Constant):
if isinstance(rval.value, bool): if isinstance(rval.value, bool):
if rval.value: if rval.value:
builder.store(ir.Constant(ir.IntType(1), 1), builder.store(ir.Constant(ir.IntType(1), 1), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
else: else:
builder.store(ir.Constant(ir.IntType(1), 0), builder.store(ir.Constant(ir.IntType(1), 0), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
print(f"Assigned constant {rval.value} to {var_name}") print(f"Assigned constant {rval.value} to {var_name}")
elif isinstance(rval.value, int): elif isinstance(rval.value, int):
# Assume c_int64 for now # Assume c_int64 for now
# var = builder.alloca(ir.IntType(64), name=var_name) # var = builder.alloca(ir.IntType(64), name=var_name)
# var.align = 8 # var.align = 8
builder.store(ir.Constant(ir.IntType(64), rval.value), builder.store(
local_sym_tab[var_name][0]) ir.Constant(ir.IntType(64), rval.value), local_sym_tab[var_name][0]
)
# local_sym_tab[var_name] = var # local_sym_tab[var_name] = var
print(f"Assigned constant {rval.value} to {var_name}") print(f"Assigned constant {rval.value} to {var_name}")
elif isinstance(rval.value, str): elif isinstance(rval.value, str):
str_val = rval.value.encode('utf-8') + b'\x00' str_val = rval.value.encode("utf-8") + b"\x00"
str_const = ir.Constant(ir.ArrayType( str_const = ir.Constant(
ir.IntType(8), len(str_val)), bytearray(str_val)) ir.ArrayType(ir.IntType(8), len(str_val)), bytearray(str_val)
)
global_str = ir.GlobalVariable( global_str = ir.GlobalVariable(
module, str_const.type, name=f"{var_name}_str") module, str_const.type, name=f"{var_name}_str"
global_str.linkage = 'internal' )
global_str.linkage = "internal"
global_str.global_constant = True global_str.global_constant = True
global_str.initializer = str_const global_str.initializer = str_const
str_ptr = builder.bitcast( str_ptr = builder.bitcast(global_str, ir.PointerType(ir.IntType(8)))
global_str, ir.PointerType(ir.IntType(8)))
builder.store(str_ptr, local_sym_tab[var_name][0]) builder.store(str_ptr, local_sym_tab[var_name][0])
print(f"Assigned string constant '{rval.value}' to {var_name}") print(f"Assigned string constant '{rval.value}' to {var_name}")
else: else:
@ -104,27 +116,50 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
if isinstance(rval.func, ast.Name): if isinstance(rval.func, ast.Name):
call_type = rval.func.id call_type = rval.func.id
print(f"Assignment call type: {call_type}") print(f"Assignment call type: {call_type}")
if call_type in num_types and len(rval.args) == 1 and isinstance(rval.args[0], ast.Constant) and isinstance(rval.args[0].value, int): if (
call_type in num_types
and len(rval.args) == 1
and isinstance(rval.args[0], ast.Constant)
and isinstance(rval.args[0].value, int)
):
ir_type = ctypes_to_ir(call_type) ir_type = ctypes_to_ir(call_type)
# var = builder.alloca(ir_type, name=var_name) # var = builder.alloca(ir_type, name=var_name)
# var.align = ir_type.width // 8 # var.align = ir_type.width // 8
builder.store(ir.Constant( builder.store(
ir_type, rval.args[0].value), local_sym_tab[var_name][0]) ir.Constant(ir_type, rval.args[0].value), local_sym_tab[var_name][0]
print(f"Assigned {call_type} constant " )
f"{rval.args[0].value} to {var_name}") print(
f"Assigned {call_type} constant "
f"{rval.args[0].value} to {var_name}"
)
# local_sym_tab[var_name] = var # local_sym_tab[var_name] = var
elif call_type in helper_func_list: elif call_type in helper_func_list:
# var = builder.alloca(ir.IntType(64), name=var_name) # var = builder.alloca(ir.IntType(64), name=var_name)
# var.align = 8 # var.align = 8
val = handle_helper_call( val = handle_helper_call(
rval, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata) rval,
module,
builder,
func,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
builder.store(val[0], local_sym_tab[var_name][0]) builder.store(val[0], local_sym_tab[var_name][0])
# local_sym_tab[var_name] = var # local_sym_tab[var_name] = var
print(f"Assigned constant {rval.func.id} to {var_name}") print(f"Assigned constant {rval.func.id} to {var_name}")
elif call_type == "deref" and len(rval.args) == 1: elif call_type == "deref" and len(rval.args) == 1:
print(f"Handling deref assignment {ast.dump(rval)}") print(f"Handling deref assignment {ast.dump(rval)}")
val = eval_expr(func, module, builder, rval, val = eval_expr(
local_sym_tab, map_sym_tab, structs_sym_tab) func,
module,
builder,
rval,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
)
if val is None: if val is None:
print("Failed to evaluate deref argument") print("Failed to evaluate deref argument")
return return
@ -137,8 +172,7 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
ir_type = struct_info.ir_type ir_type = struct_info.ir_type
# var = builder.alloca(ir_type, name=var_name) # var = builder.alloca(ir_type, name=var_name)
# Null init # Null init
builder.store(ir.Constant(ir_type, None), builder.store(ir.Constant(ir_type, None), local_sym_tab[var_name][0])
local_sym_tab[var_name][0])
local_var_metadata[var_name] = call_type local_var_metadata[var_name] = call_type
print(f"Assigned struct {call_type} to {var_name}") print(f"Assigned struct {call_type} to {var_name}")
# local_sym_tab[var_name] = var # local_sym_tab[var_name] = var
@ -149,14 +183,24 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
if isinstance(rval.func.value, ast.Name): if isinstance(rval.func.value, ast.Name):
# TODO: probably a struct access # TODO: probably a struct access
print(f"TODO STRUCT ACCESS {ast.dump(rval)}") print(f"TODO STRUCT ACCESS {ast.dump(rval)}")
elif isinstance(rval.func.value, ast.Call) and isinstance(rval.func.value.func, ast.Name): elif isinstance(rval.func.value, ast.Call) and isinstance(
rval.func.value.func, ast.Name
):
map_name = rval.func.value.func.id map_name = rval.func.value.func.id
method_name = rval.func.attr method_name = rval.func.attr
if map_name in map_sym_tab: if map_name in map_sym_tab:
map_ptr = map_sym_tab[map_name] map_ptr = map_sym_tab[map_name]
if method_name in helper_func_list: if method_name in helper_func_list:
val = handle_helper_call( val = handle_helper_call(
rval, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab, local_var_metadata) rval,
module,
builder,
func,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
# var = builder.alloca(ir.IntType(64), name=var_name) # var = builder.alloca(ir.IntType(64), name=var_name)
# var.align = 8 # var.align = 8
builder.store(val[0], local_sym_tab[var_name][0]) builder.store(val[0], local_sym_tab[var_name][0])
@ -166,8 +210,9 @@ def handle_assign(func, module, builder, stmt, map_sym_tab, local_sym_tab, struc
else: else:
print("Unsupported assignment call function type") print("Unsupported assignment call function type")
elif isinstance(rval, ast.BinOp): elif isinstance(rval, ast.BinOp):
handle_binary_op(rval, module, builder, var_name, handle_binary_op(
local_sym_tab, map_sym_tab, func) rval, module, builder, var_name, local_sym_tab, map_sym_tab, func
)
else: else:
print("Unsupported assignment value type") print("Unsupported assignment value type")
@ -199,13 +244,13 @@ def handle_cond(func, module, builder, cond, local_sym_tab, map_sym_tab):
print(f"Undefined variable {cond.id} in condition") print(f"Undefined variable {cond.id} in condition")
return None return None
elif isinstance(cond, ast.Compare): elif isinstance(cond, ast.Compare):
lhs = eval_expr(func, module, builder, cond.left, lhs = eval_expr(func, module, builder, cond.left, local_sym_tab, map_sym_tab)[0]
local_sym_tab, map_sym_tab)[0]
if len(cond.ops) != 1 or len(cond.comparators) != 1: if len(cond.ops) != 1 or len(cond.comparators) != 1:
print("Unsupported complex comparison") print("Unsupported complex comparison")
return None return None
rhs = eval_expr(func, module, builder, rhs = eval_expr(
cond.comparators[0], local_sym_tab, map_sym_tab)[0] func, module, builder, cond.comparators[0], local_sym_tab, map_sym_tab
)[0]
op = cond.ops[0] op = cond.ops[0]
if lhs.type != rhs.type: if lhs.type != rhs.type:
@ -239,7 +284,9 @@ def handle_cond(func, module, builder, cond, local_sym_tab, map_sym_tab):
return None return None
def handle_if(func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab=None): def handle_if(
func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab=None
):
"""Handle if statements in the function body.""" """Handle if statements in the function body."""
print("Handling if statement") print("Handling if statement")
start = builder.block.parent start = builder.block.parent
@ -250,8 +297,7 @@ def handle_if(func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_s
else: else:
else_block = None else_block = None
cond = handle_cond(func, module, builder, stmt.test, cond = handle_cond(func, module, builder, stmt.test, local_sym_tab, map_sym_tab)
local_sym_tab, map_sym_tab)
if else_block: if else_block:
builder.cbranch(cond, then_block, else_block) builder.cbranch(cond, then_block, else_block)
else: else:
@ -259,48 +305,84 @@ def handle_if(func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_s
builder.position_at_end(then_block) builder.position_at_end(then_block)
for s in stmt.body: for s in stmt.body:
process_stmt(func, module, builder, s, process_stmt(
local_sym_tab, map_sym_tab, structs_sym_tab, False) func, module, builder, s, local_sym_tab, map_sym_tab, structs_sym_tab, False
)
if not builder.block.is_terminated: if not builder.block.is_terminated:
builder.branch(merge_block) builder.branch(merge_block)
if else_block: if else_block:
builder.position_at_end(else_block) builder.position_at_end(else_block)
for s in stmt.orelse: for s in stmt.orelse:
process_stmt(func, module, builder, s, process_stmt(
local_sym_tab, map_sym_tab, structs_sym_tab, False) func,
module,
builder,
s,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
False,
)
if not builder.block.is_terminated: if not builder.block.is_terminated:
builder.branch(merge_block) builder.branch(merge_block)
builder.position_at_end(merge_block) builder.position_at_end(merge_block)
def process_stmt(func, module, builder, stmt, local_sym_tab, map_sym_tab, structs_sym_tab, did_return, ret_type=ir.IntType(64)): def process_stmt(
func,
module,
builder,
stmt,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
did_return,
ret_type=ir.IntType(64),
):
print(f"Processing statement: {ast.dump(stmt)}") print(f"Processing statement: {ast.dump(stmt)}")
if isinstance(stmt, ast.Expr): if isinstance(stmt, ast.Expr):
print(local_var_metadata) print(local_var_metadata)
handle_expr(func, module, builder, stmt, local_sym_tab, handle_expr(
map_sym_tab, structs_sym_tab, local_var_metadata) func,
module,
builder,
stmt,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
local_var_metadata,
)
elif isinstance(stmt, ast.Assign): elif isinstance(stmt, ast.Assign):
handle_assign(func, module, builder, stmt, map_sym_tab, handle_assign(
local_sym_tab, structs_sym_tab) func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab
)
elif isinstance(stmt, ast.AugAssign): elif isinstance(stmt, ast.AugAssign):
raise SyntaxError("Augmented assignment not supported") raise SyntaxError("Augmented assignment not supported")
elif isinstance(stmt, ast.If): elif isinstance(stmt, ast.If):
handle_if(func, module, builder, stmt, map_sym_tab, handle_if(
local_sym_tab, structs_sym_tab) func, module, builder, stmt, map_sym_tab, local_sym_tab, structs_sym_tab
)
elif isinstance(stmt, ast.Return): elif isinstance(stmt, ast.Return):
if stmt.value is None: if stmt.value is None:
builder.ret(ir.Constant(ir.IntType(32), 0)) builder.ret(ir.Constant(ir.IntType(32), 0))
did_return = True did_return = True
elif isinstance(stmt.value, ast.Call) and isinstance(stmt.value.func, ast.Name) and len(stmt.value.args) == 1 and isinstance(stmt.value.args[0], ast.Constant) and isinstance(stmt.value.args[0].value, int): elif (
isinstance(stmt.value, ast.Call)
and isinstance(stmt.value.func, ast.Name)
and len(stmt.value.args) == 1
and isinstance(stmt.value.args[0], ast.Constant)
and isinstance(stmt.value.args[0].value, int)
):
call_type = stmt.value.func.id call_type = stmt.value.func.id
if ctypes_to_ir(call_type) != ret_type: if ctypes_to_ir(call_type) != ret_type:
raise ValueError("Return type mismatch: expected" raise ValueError(
f"{ctypes_to_ir(call_type)}, got {call_type}") "Return type mismatch: expected"
f"{ctypes_to_ir(call_type)}, got {call_type}"
)
else: else:
builder.ret(ir.Constant( builder.ret(ir.Constant(ret_type, stmt.value.args[0].value))
ret_type, stmt.value.args[0].value))
did_return = True did_return = True
elif isinstance(stmt.value, ast.Name): elif isinstance(stmt.value, ast.Name):
if stmt.value.id == "XDP_PASS": if stmt.value.id == "XDP_PASS":
@ -316,15 +398,33 @@ def process_stmt(func, module, builder, stmt, local_sym_tab, map_sym_tab, struct
return did_return return did_return
def allocate_mem(module, builder, body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab): def allocate_mem(
module, builder, body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab
):
for stmt in body: for stmt in body:
if isinstance(stmt, ast.If): if isinstance(stmt, ast.If):
if stmt.body: if stmt.body:
local_sym_tab = allocate_mem( local_sym_tab = allocate_mem(
module, builder, stmt.body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab) module,
builder,
stmt.body,
func,
ret_type,
map_sym_tab,
local_sym_tab,
structs_sym_tab,
)
if stmt.orelse: if stmt.orelse:
local_sym_tab = allocate_mem( local_sym_tab = allocate_mem(
module, builder, stmt.orelse, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab) module,
builder,
stmt.orelse,
func,
ret_type,
map_sym_tab,
local_sym_tab,
structs_sym_tab,
)
elif isinstance(stmt, ast.Assign): elif isinstance(stmt, ast.Assign):
if len(stmt.targets) != 1: if len(stmt.targets) != 1:
print("Unsupported multiassignment") print("Unsupported multiassignment")
@ -342,35 +442,32 @@ def allocate_mem(module, builder, body, func, ret_type, map_sym_tab, local_sym_t
ir_type = ctypes_to_ir(call_type) ir_type = ctypes_to_ir(call_type)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = ir_type.width // 8 var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} of type {call_type}")
f"Pre-allocated variable {var_name} of type {call_type}")
elif call_type in helper_func_list: elif call_type in helper_func_list:
# Assume return type is int64 for now # Assume return type is int64 for now
ir_type = ir.IntType(64) ir_type = ir.IntType(64)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = ir_type.width // 8 var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} for helper")
f"Pre-allocated variable {var_name} for helper")
elif call_type == "deref" and len(rval.args) == 1: elif call_type == "deref" and len(rval.args) == 1:
# Assume return type is int64 for now # Assume return type is int64 for now
ir_type = ir.IntType(64) ir_type = ir.IntType(64)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = ir_type.width // 8 var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} for deref")
f"Pre-allocated variable {var_name} for deref")
elif call_type in structs_sym_tab: elif call_type in structs_sym_tab:
struct_info = structs_sym_tab[call_type] struct_info = structs_sym_tab[call_type]
ir_type = struct_info.ir_type ir_type = struct_info.ir_type
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
local_var_metadata[var_name] = call_type local_var_metadata[var_name] = call_type
print( print(
f"Pre-allocated variable {var_name} for struct {call_type}") f"Pre-allocated variable {var_name} for struct {call_type}"
)
elif isinstance(rval.func, ast.Attribute): elif isinstance(rval.func, ast.Attribute):
ir_type = ir.PointerType(ir.IntType(64)) ir_type = ir.PointerType(ir.IntType(64))
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
# var.align = ir_type.width // 8 # var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} for map")
f"Pre-allocated variable {var_name} for map")
else: else:
print("Unsupported assignment call function type") print("Unsupported assignment call function type")
continue continue
@ -379,31 +476,27 @@ def allocate_mem(module, builder, body, func, ret_type, map_sym_tab, local_sym_t
ir_type = ir.IntType(1) ir_type = ir.IntType(1)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = 1 var.align = 1
print( print(f"Pre-allocated variable {var_name} of type c_bool")
f"Pre-allocated variable {var_name} of type c_bool")
elif isinstance(rval.value, int): elif isinstance(rval.value, int):
# Assume c_int64 for now # Assume c_int64 for now
ir_type = ir.IntType(64) ir_type = ir.IntType(64)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = ir_type.width // 8 var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} of type c_int64")
f"Pre-allocated variable {var_name} of type c_int64")
elif isinstance(rval.value, str): elif isinstance(rval.value, str):
ir_type = ir.PointerType(ir.IntType(8)) ir_type = ir.PointerType(ir.IntType(8))
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = 8 var.align = 8
print( print(f"Pre-allocated variable {var_name} of type string")
f"Pre-allocated variable {var_name} of type string")
else: else:
print(f"Unsupported constant type") print("Unsupported constant type")
continue continue
elif isinstance(rval, ast.BinOp): elif isinstance(rval, ast.BinOp):
# Assume c_int64 for now # Assume c_int64 for now
ir_type = ir.IntType(64) ir_type = ir.IntType(64)
var = builder.alloca(ir_type, name=var_name) var = builder.alloca(ir_type, name=var_name)
var.align = ir_type.width // 8 var.align = ir_type.width // 8
print( print(f"Pre-allocated variable {var_name} of type c_int64")
f"Pre-allocated variable {var_name} of type c_int64")
else: else:
print("Unsupported assignment value type") print("Unsupported assignment value type")
continue continue
@ -411,7 +504,9 @@ def allocate_mem(module, builder, body, func, ret_type, map_sym_tab, local_sym_t
return local_sym_tab return local_sym_tab
def process_func_body(module, builder, func_node, func, ret_type, map_sym_tab, structs_sym_tab): def process_func_body(
module, builder, func_node, func, ret_type, map_sym_tab, structs_sym_tab
):
"""Process the body of a bpf function""" """Process the body of a bpf function"""
# TODO: A lot. We just have print -> bpf_trace_printk for now # TODO: A lot. We just have print -> bpf_trace_printk for now
did_return = False did_return = False
@ -420,13 +515,30 @@ def process_func_body(module, builder, func_node, func, ret_type, map_sym_tab, s
# pre-allocate dynamic variables # pre-allocate dynamic variables
local_sym_tab = allocate_mem( local_sym_tab = allocate_mem(
module, builder, func_node.body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab) module,
builder,
func_node.body,
func,
ret_type,
map_sym_tab,
local_sym_tab,
structs_sym_tab,
)
print(f"Local symbol table: {local_sym_tab.keys()}") print(f"Local symbol table: {local_sym_tab.keys()}")
for stmt in func_node.body: for stmt in func_node.body:
did_return = process_stmt(func, module, builder, stmt, local_sym_tab, did_return = process_stmt(
map_sym_tab, structs_sym_tab, did_return, ret_type) func,
module,
builder,
stmt,
local_sym_tab,
map_sym_tab,
structs_sym_tab,
did_return,
ret_type,
)
if not did_return: if not did_return:
builder.ret(ir.Constant(ir.IntType(32), 0)) builder.ret(ir.Constant(ir.IntType(32), 0))
@ -465,8 +577,9 @@ def process_bpf_chunk(func_node, module, return_type, map_sym_tab, structs_sym_t
block = func.append_basic_block(name="entry") block = func.append_basic_block(name="entry")
builder = ir.IRBuilder(block) builder = ir.IRBuilder(block)
process_func_body(module, builder, func_node, func, process_func_body(
ret_type, map_sym_tab, structs_sym_tab) module, builder, func_node, func, ret_type, map_sym_tab, structs_sym_tab
)
return func return func
@ -474,7 +587,11 @@ def func_proc(tree, module, chunks, map_sym_tab, structs_sym_tab):
for func_node in chunks: for func_node in chunks:
is_global = False is_global = False
for decorator in func_node.decorator_list: for decorator in func_node.decorator_list:
if isinstance(decorator, ast.Name) and decorator.id in ("map", "bpfglobal", "struct"): if isinstance(decorator, ast.Name) and decorator.id in (
"map",
"bpfglobal",
"struct",
):
is_global = True is_global = True
break break
if is_global: if is_global:
@ -482,8 +599,13 @@ def func_proc(tree, module, chunks, map_sym_tab, structs_sym_tab):
func_type = get_probe_string(func_node) func_type = get_probe_string(func_node)
print(f"Found probe_string of {func_node.name}: {func_type}") print(f"Found probe_string of {func_node.name}: {func_type}")
process_bpf_chunk(func_node, module, ctypes_to_ir( process_bpf_chunk(
infer_return_type(func_node)), map_sym_tab, structs_sym_tab) func_node,
module,
ctypes_to_ir(infer_return_type(func_node)),
map_sym_tab,
structs_sym_tab,
)
def infer_return_type(func_node: ast.FunctionDef): def infer_return_type(func_node: ast.FunctionDef):
@ -533,16 +655,17 @@ def infer_return_type(func_node: ast.FunctionDef):
return ast.unparse(e) return ast.unparse(e)
except Exception: except Exception:
return type(e).__name__ return type(e).__name__
for node in ast.walk(func_node): for node in ast.walk(func_node):
if isinstance(node, ast.Return): if isinstance(node, ast.Return):
t = _expr_type(node.value) t = _expr_type(node.value)
if found_type is None: if found_type is None:
found_type = t found_type = t
elif found_type != t: elif found_type != t:
raise ValueError("Conflicting return types:" raise ValueError("Conflicting return types:" f"{found_type} vs {t}")
f"{found_type} vs {t}")
return found_type or "None" return found_type or "None"
# For string assignment to fixed-size arrays # For string assignment to fixed-size arrays
@ -566,7 +689,8 @@ def assign_string_to_array(builder, target_array_ptr, source_string_ptr, array_l
builder.position_at_end(copy_block) builder.position_at_end(copy_block)
idx = builder.load(i) idx = builder.load(i)
in_bounds = builder.icmp_unsigned( in_bounds = builder.icmp_unsigned(
'<', idx, ir.Constant(ir.IntType(32), array_length)) "<", idx, ir.Constant(ir.IntType(32), array_length)
)
builder.cbranch(in_bounds, copy_block, end_block) builder.cbranch(in_bounds, copy_block, end_block)
with builder.if_then(in_bounds): with builder.if_then(in_bounds):
@ -575,8 +699,7 @@ def assign_string_to_array(builder, target_array_ptr, source_string_ptr, array_l
char = builder.load(src_ptr) char = builder.load(src_ptr)
# Store character in target # Store character in target
dst_ptr = builder.gep( dst_ptr = builder.gep(target_array_ptr, [ir.Constant(ir.IntType(32), 0), idx])
target_array_ptr, [ir.Constant(ir.IntType(32), 0), idx])
builder.store(char, dst_ptr) builder.store(char, dst_ptr)
# Increment counter # Increment counter
@ -587,6 +710,5 @@ def assign_string_to_array(builder, target_array_ptr, source_string_ptr, array_l
# Ensure null termination # Ensure null termination
last_idx = ir.Constant(ir.IntType(32), array_length - 1) last_idx = ir.Constant(ir.IntType(32), array_length - 1)
null_ptr = builder.gep( null_ptr = builder.gep(target_array_ptr, [ir.Constant(ir.IntType(32), 0), last_idx])
target_array_ptr, [ir.Constant(ir.IntType(32), 0), last_idx])
builder.store(ir.Constant(ir.IntType(8), 0), null_ptr) builder.store(ir.Constant(ir.IntType(8), 0), null_ptr)

View File

@ -1,15 +1,19 @@
import ctypes import ctypes
def ktime(): def ktime():
return ctypes.c_int64(0) return ctypes.c_int64(0)
def pid(): def pid():
return ctypes.c_int32(0) return ctypes.c_int32(0)
def deref(ptr): def deref(ptr):
"dereference a pointer" "dereference a pointer"
result = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_void_p)).contents.value result = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_void_p)).contents.value
return result if result is not None else 0 return result if result is not None else 0
XDP_DROP = ctypes.c_int64(1) XDP_DROP = ctypes.c_int64(1)
XDP_PASS = ctypes.c_int64(2) XDP_PASS = ctypes.c_int64(2)

View File

@ -11,10 +11,10 @@ def emit_license(module: ir.Module, license_str: str):
gvar.initializer = ir.Constant(ty, elems) # type: ignore gvar.initializer = ir.Constant(ty, elems) # type: ignore
gvar.align = 1 # type: ignore gvar.align = 1 # type: ignore
gvar.linkage = "dso_local" # type: ignore gvar.linkage = "dso_local" # type: ignore
gvar.global_constant = False gvar.global_constant = False
gvar.section = "license" # type: ignore gvar.section = "license" # type: ignore
return gvar return gvar
@ -26,7 +26,8 @@ def license_processing(tree, module):
if isinstance(node, ast.FunctionDef) and node.name == "LICENSE": if isinstance(node, ast.FunctionDef) and node.name == "LICENSE":
# check decorators # check decorators
decorators = [ decorators = [
dec.id for dec in node.decorator_list if isinstance(dec, ast.Name)] dec.id for dec in node.decorator_list if isinstance(dec, ast.Name)
]
if "bpf" in decorators and "bpfglobal" in decorators: if "bpf" in decorators and "bpfglobal" in decorators:
if count == 0: if count == 0:
count += 1 count += 1

View File

@ -2,14 +2,14 @@ import ast
from llvmlite import ir from llvmlite import ir
from enum import Enum from enum import Enum
from .maps_utils import MapProcessorRegistry from .maps_utils import MapProcessorRegistry
from ..debuginfo import dwarf_constants as dc, DebugInfoGenerator from ..debuginfo import DebugInfoGenerator
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def maps_proc(tree, module, chunks): def maps_proc(tree, module, chunks):
""" Process all functions decorated with @map to find BPF maps """ """Process all functions decorated with @map to find BPF maps"""
map_sym_tab = {} map_sym_tab = {}
for func_node in chunks: for func_node in chunks:
if is_map(func_node): if is_map(func_node):
@ -35,14 +35,14 @@ def create_bpf_map(module, map_name, map_params):
# Create the anonymous struct type for BPF map # Create the anonymous struct type for BPF map
map_struct_type = ir.LiteralStructType( map_struct_type = ir.LiteralStructType(
[ir.PointerType() for _ in range(len(map_params))]) [ir.PointerType() for _ in range(len(map_params))]
)
# Create the global variable # Create the global variable
map_global = ir.GlobalVariable(module, map_struct_type, name=map_name) map_global = ir.GlobalVariable(module, map_struct_type, name=map_name)
map_global.linkage = 'dso_local' map_global.linkage = "dso_local"
map_global.global_constant = False map_global.global_constant = False
map_global.initializer = ir.Constant( map_global.initializer = ir.Constant(map_struct_type, None)
map_struct_type, None)
map_global.section = ".maps" map_global.section = ".maps"
map_global.align = 8 map_global.align = 8
@ -56,11 +56,16 @@ def create_map_debug_info(module, map_global, map_name, map_params):
uint_type = generator.get_uint32_type() uint_type = generator.get_uint32_type()
ulong_type = generator.get_uint64_type() ulong_type = generator.get_uint64_type()
array_type = generator.create_array_type(uint_type, map_params.get("type", BPFMapType.HASH).value) array_type = generator.create_array_type(
uint_type, map_params.get("type", BPFMapType.HASH).value
)
type_ptr = generator.create_pointer_type(array_type, 64) type_ptr = generator.create_pointer_type(array_type, 64)
key_ptr = generator.create_pointer_type(array_type if "key_size" in map_params else ulong_type, 64) key_ptr = generator.create_pointer_type(
value_ptr = generator.create_pointer_type(array_type if "value_size" in map_params else ulong_type, 64) array_type if "key_size" in map_params else ulong_type, 64
)
value_ptr = generator.create_pointer_type(
array_type if "value_size" in map_params else ulong_type, 64
)
elements_arr = [] elements_arr = []
@ -82,16 +87,24 @@ def create_map_debug_info(module, map_global, map_name, map_params):
cnt += 1 cnt += 1
if "max_entries" in map_params: if "max_entries" in map_params:
max_entries_array = generator.create_array_type(uint_type, map_params["max_entries"]) max_entries_array = generator.create_array_type(
uint_type, map_params["max_entries"]
)
max_entries_ptr = generator.create_pointer_type(max_entries_array, 64) max_entries_ptr = generator.create_pointer_type(max_entries_array, 64)
max_entries_member = generator.create_struct_member("max_entries", max_entries_ptr, cnt * 64) max_entries_member = generator.create_struct_member(
"max_entries", max_entries_ptr, cnt * 64
)
elements_arr.append(max_entries_member) elements_arr.append(max_entries_member)
# Create the struct type # Create the struct type
struct_type = generator.create_struct_type(elements_arr, 64 * len(elements_arr), is_distinct=True) struct_type = generator.create_struct_type(
elements_arr, 64 * len(elements_arr), is_distinct=True
)
# Create global variable debug info # Create global variable debug info
global_var = generator.create_global_var_debug_info(map_name, struct_type, is_local=False) global_var = generator.create_global_var_debug_info(
map_name, struct_type, is_local=False
)
# Attach debug info to the global variable # Attach debug info to the global variable
map_global.set_metadata("dbg", global_var) map_global.set_metadata("dbg", global_var)
@ -120,8 +133,7 @@ def process_hash_map(map_name, rval, module):
map_params["key"] = keyword.value.id map_params["key"] = keyword.value.id
elif keyword.arg == "value" and isinstance(keyword.value, ast.Name): elif keyword.arg == "value" and isinstance(keyword.value, ast.Name):
map_params["value"] = keyword.value.id map_params["value"] = keyword.value.id
elif (keyword.arg == "max_entries" and elif keyword.arg == "max_entries" and isinstance(keyword.value, ast.Constant):
isinstance(keyword.value, ast.Constant)):
const_val = keyword.value.value const_val = keyword.value.value
if isinstance(const_val, (int, str)): if isinstance(const_val, (int, str)):
map_params["max_entries"] = const_val map_params["max_entries"] = const_val
@ -147,8 +159,7 @@ def process_perf_event_map(map_name, rval, module):
for keyword in rval.keywords: for keyword in rval.keywords:
if keyword.arg == "key_size" and isinstance(keyword.value, ast.Name): if keyword.arg == "key_size" and isinstance(keyword.value, ast.Name):
map_params["key_size"] = keyword.value.id map_params["key_size"] = keyword.value.id
elif (keyword.arg == "value_size" and elif keyword.arg == "value_size" and isinstance(keyword.value, ast.Name):
isinstance(keyword.value, ast.Name)):
map_params["value_size"] = keyword.value.id map_params["value_size"] = keyword.value.id
logger.info(f"Map parameters: {map_params}") logger.info(f"Map parameters: {map_params}")
@ -179,8 +190,9 @@ def process_bpf_map(func_node, module):
if handler: if handler:
return handler(map_name, rval, module) return handler(map_name, rval, module)
else: else:
logger.warning(f"Unknown map type " logger.warning(
f"{rval.func.id}, defaulting to HashMap") f"Unknown map type " f"{rval.func.id}, defaulting to HashMap"
)
return process_hash_map(map_name, rval, module) return process_hash_map(map_name, rval, module)
else: else:
raise ValueError("Function under @map must return a map") raise ValueError("Function under @map must return a map")

View File

@ -1,13 +1,16 @@
class MapProcessorRegistry: class MapProcessorRegistry:
"""Registry for map processor functions""" """Registry for map processor functions"""
_processors = {} _processors = {}
@classmethod @classmethod
def register(cls, map_type_name): def register(cls, map_type_name):
"""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):
cls._processors[map_type_name] = func cls._processors[map_type_name] = func
return func return func
return decorator return decorator
@classmethod @classmethod

View File

@ -15,9 +15,11 @@ class StructType:
def gep(self, builder, ptr, field_name): def gep(self, builder, ptr, field_name):
idx = self.field_idx(field_name) idx = self.field_idx(field_name)
return builder.gep(ptr, [ir.Constant(ir.IntType(32), 0), return builder.gep(
ir.Constant(ir.IntType(32), idx)], ptr,
inbounds=True) [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), idx)],
inbounds=True,
)
def field_size(self, field_name): def field_size(self, field_name):
fld = self.fields[field_name] fld = self.fields[field_name]

View File

@ -15,7 +15,7 @@ logger = logging.getLogger(__name__)
def structs_proc(tree, module, chunks): def structs_proc(tree, module, chunks):
""" Process all class definitions to find BPF structs """ """Process all class definitions to find BPF structs"""
structs_sym_tab = {} structs_sym_tab = {}
for cls_node in chunks: for cls_node in chunks:
if is_bpf_struct(cls_node): if is_bpf_struct(cls_node):
@ -33,7 +33,7 @@ def is_bpf_struct(cls_node):
def process_bpf_struct(cls_node, module): def process_bpf_struct(cls_node, module):
""" Process a single BPF struct definition """ """Process a single BPF struct definition"""
fields = parse_struct_fields(cls_node) fields = parse_struct_fields(cls_node)
field_types = list(fields.values()) field_types = list(fields.values())
@ -44,12 +44,11 @@ def process_bpf_struct(cls_node, module):
def parse_struct_fields(cls_node): def parse_struct_fields(cls_node):
""" Parse fields of a struct class node """ """Parse fields of a struct class node"""
fields = {} fields = {}
for item in cls_node.body: for item in cls_node.body:
if isinstance(item, ast.AnnAssign) and \ if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
isinstance(item.target, ast.Name):
fields[item.target.id] = get_type_from_ann(item.annotation) fields[item.target.id] = get_type_from_ann(item.annotation)
else: else:
logger.error(f"Unsupported struct field: {ast.dump(item)}") logger.error(f"Unsupported struct field: {ast.dump(item)}")
@ -58,9 +57,8 @@ def parse_struct_fields(cls_node):
def get_type_from_ann(annotation): def get_type_from_ann(annotation):
""" Convert an AST annotation node to an LLVM IR type for struct fields""" """Convert an AST annotation node to an LLVM IR type for struct fields"""
if isinstance(annotation, ast.Call) and \ if isinstance(annotation, ast.Call) and isinstance(annotation.func, ast.Name):
isinstance(annotation.func, ast.Name):
if annotation.func.id == "str": if annotation.func.id == "str":
# Char array # Char array
# Assumes constant integer argument # Assumes constant integer argument
@ -74,7 +72,7 @@ def get_type_from_ann(annotation):
def calc_struct_size(field_types): def calc_struct_size(field_types):
""" Calculate total size of the struct with alignment and padding """ """Calculate total size of the struct with alignment and padding"""
curr_offset = 0 curr_offset = 0
for ftype in field_types: for ftype in field_types:
if isinstance(ftype, ir.IntType): if isinstance(ftype, ir.IntType):

View File

@ -17,7 +17,7 @@ def ctypes_to_ir(ctype: str):
"c_double": ir.DoubleType(), "c_double": ir.DoubleType(),
"c_void_p": ir.IntType(64), "c_void_p": ir.IntType(64),
# Not so sure about this one # Not so sure about this one
"str": ir.PointerType(ir.IntType(8)) "str": ir.PointerType(ir.IntType(8)),
} }
if ctype in mapping: if ctype in mapping:
return mapping[ctype] return mapping[ctype]

View File

@ -23,20 +23,20 @@ SEC("tracepoint/syscalls/sys_enter_clone")
int hello(struct pt_regs *ctx) int hello(struct pt_regs *ctx)
{ {
struct data_t data = {}; struct data_t data = {};
// Get PID (lower 32 bits of the 64-bit value returned) // Get PID (lower 32 bits of the 64-bit value returned)
data.pid = bpf_get_current_pid_tgid() & 0xFFFFFFFF; data.pid = bpf_get_current_pid_tgid() & 0xFFFFFFFF;
// Get timestamp // Get timestamp
data.ts = bpf_ktime_get_ns(); data.ts = bpf_ktime_get_ns();
// Get current process name // Get current process name
// bpf_get_current_comm(&data.comm, sizeof(data.comm)); // bpf_get_current_comm(&data.comm, sizeof(data.comm));
// Submit data to userspace via perf event // Submit data to userspace via perf event
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
&data, sizeof(data)); &data, sizeof(data));
return 0; return 0;
} }

View File

@ -3,7 +3,7 @@
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> #include <bpf/bpf_tracing.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#define __TARGET_ARCH_aarch64 #define __TARGET_ARCH_aarch64
#define u64 unsigned long long #define u64 unsigned long long
struct { struct {
@ -33,11 +33,11 @@ SEC("kprobe/blk_account_io_completion")
int BPF_KPROBE(trace_completion, struct request *req) int BPF_KPROBE(trace_completion, struct request *req)
{ {
u64 *tsp, delta; u64 *tsp, delta;
tsp = bpf_map_lookup_elem(&start, &req); tsp = bpf_map_lookup_elem(&start, &req);
if (tsp) { if (tsp) {
delta = bpf_ktime_get_ns() - *tsp; delta = bpf_ktime_get_ns() - *tsp;
bpf_printk("%d %x %d\n", req->__data_len, bpf_printk("%d %x %d\n", req->__data_len,
req->cmd_flags, delta / 1000); req->cmd_flags, delta / 1000);
bpf_map_delete_elem(&start, &req); bpf_map_delete_elem(&start, &req);
} }

164152
tests/c-form/vmlinux.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,18 @@
from pythonbpf import compile, bpf, section, bpfglobal from pythonbpf import compile, bpf, section, bpfglobal
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
@bpf @bpf
@section("sometag1") @section("sometag1")
def sometag(ctx: c_void_p) -> c_int64: def sometag(ctx: c_void_p) -> c_int64:
a = 1 + 2 + 1 a = 1 + 2 + 1
return c_int64(0) return c_int64(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -1,6 +1,7 @@
from pythonbpf import compile, bpf, section, bpfglobal from pythonbpf import compile, bpf, section, bpfglobal
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
@bpf @bpf
@section("sometag1") @section("sometag1")
def sometag(ctx: c_void_p) -> c_int64: def sometag(ctx: c_void_p) -> c_int64:
@ -8,9 +9,11 @@ def sometag(ctx: c_void_p) -> c_int64:
a = 1 + b a = 1 + b
return c_int64(a) return c_int64(a)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -4,6 +4,7 @@ from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
@bpf @bpf
@map @map
def count() -> HashMap: def count() -> HashMap:
@ -22,9 +23,11 @@ def hello_world(ctx: c_void_p) -> c_int64:
return XDP_PASS return XDP_PASS
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -1,6 +1,7 @@
from pythonbpf import compile, bpf, section, bpfglobal from pythonbpf import compile, bpf, section, bpfglobal
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
@bpf @bpf
@section("sometag1") @section("sometag1")
def sometag(ctx: c_void_p) -> c_int64: def sometag(ctx: c_void_p) -> c_int64:
@ -8,9 +9,11 @@ def sometag(ctx: c_void_p) -> c_int64:
return c_int64(5) return c_int64(5)
return c_int64(0) return c_int64(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -1,6 +1,7 @@
from pythonbpf import compile, bpf, section, bpfglobal from pythonbpf import compile, bpf, section
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
# FAILS WHEN THERE IS NO LICENSE. which is wrong. # FAILS WHEN THERE IS NO LICENSE. which is wrong.
@bpf @bpf
@section("sometag1") @section("sometag1")
@ -8,4 +9,5 @@ def sometag(ctx: c_void_p) -> c_int64:
a = 1 + 2 a = 1 + 2
return c_int64(0) return c_int64(0)
compile() compile()

View File

@ -1,14 +1,17 @@
from pythonbpf import compile, bpf, section, bpfglobal from pythonbpf import compile, bpf, section, bpfglobal
from ctypes import c_void_p, c_int64 from ctypes import c_void_p, c_int64
@bpf @bpf
@section("sometag1") @section("sometag1")
def sometag(ctx: c_void_p) -> c_int64: def sometag(ctx: c_void_p) -> c_int64:
return c_int64(1 - 1) return c_int64(1 - 1)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
compile() compile()

View File

@ -10,16 +10,19 @@ from ctypes import c_int32, c_uint64, c_void_p
def mymap() -> HashMap: def mymap() -> HashMap:
return HashMap(key=c_int32, value=c_uint64, max_entries=16) return HashMap(key=c_int32, value=c_uint64, max_entries=16)
@bpf @bpf
@section("tracepoint/syscalls/sys_enter_clone") @section("tracepoint/syscalls/sys_enter_clone")
def testing(ctx: c_void_p) -> c_int32: def testing(ctx: c_void_p) -> c_int32:
return c_int32(0) return c_int32(0)
@bpf @bpf
@bpfglobal @bpfglobal
def LICENSE() -> str: def LICENSE() -> str:
return "GPL" return "GPL"
# Load program (no sections -> nothing attached, just map exists) # Load program (no sections -> nothing attached, just map exists)
b = BPF() b = BPF()
b.load_and_attach() b.load_and_attach()