Repository navigation
Add kernel selftest equivalent roadmap tests #105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0c5a9b3
a64f01d
7911436
0459b3a
507f075
708b5af
3ffba47
0bdea85
5e70b8f
e0d4d1e
298c140
598e3b4
cf80aad
057b68c
efe58fc
3de9832
49e7485
d649327
55fb6d6
3a984dd
ad6adb1
49ed2cf
d3fa7d7
4e8f767
20a1e2f
a5eeaaf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| from llvmlite import ir | ||
| from pythonbpf.expr import eval_expr, convert | ||
| from pythonbpf.helper import emit_probe_read_kernel_str_call | ||
| from pythonbpf.type_deducer import ctypes_to_ir | ||
| from pythonbpf.type_deducer import field_int_type | ||
| from pythonbpf.vmlinux_parser.dependency_node import Field | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
@@ -40,6 +40,10 @@ def handle_struct_field_assignment( | |
| return | ||
|
|
||
| val, val_type = val_result | ||
| if isinstance(val_type, Field): | ||
| field_ty = field_int_type(val_type) | ||
| if field_ty is not None: | ||
| val_type = field_ty | ||
|
|
||
| # Special case: i8* string to [N x i8] char array | ||
| if _is_char_array(field_type) and _is_i8_ptr(val_type): | ||
|
|
@@ -150,6 +154,13 @@ def handle_variable_assignment( | |
| logger.info( | ||
| f"Evaluated value for {var_name}: {val} of type {val_type}, expected {var_type}" | ||
| ) | ||
| # An integer vmlinux field is, for conversion purposes, its declared IntTy | ||
| # (width and sign from the ctype), so it takes the same convert() path as | ||
| # every other integer below instead of a special case. | ||
| if isinstance(val_type, Field): | ||
| field_ty = field_int_type(val_type) | ||
| if field_ty is not None: | ||
| val_type = field_ty | ||
|
|
||
| if isinstance(val_type, ir.IntType) and isinstance(var_type, ir.IntType): | ||
| # The descriptor may be narrower than the constant carrying the value | ||
|
|
@@ -194,33 +205,13 @@ def handle_variable_assignment( | |
| ) | ||
| return False | ||
| if isinstance(val_type, Field): | ||
| logger.info("Handling assignment to struct field") | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure this change is fine? Can you comprehensively test this?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks fine though |
||
| field_ir_type = ctypes_to_ir(val_type.type.__name__) | ||
| # Sub-register-width context fields are zero-extended to i64 by | ||
| # load_ctx_field, so val is already i64 even though the field type | ||
| # says otherwise (c_uint for xdp_md, c_ushort for pt_regs.cs/ss). | ||
| if ( | ||
| isinstance(field_ir_type, ir.IntType) | ||
| and field_ir_type.width < 64 | ||
| and isinstance(var_type, ir.IntType) | ||
| and var_type.width == 64 | ||
| ): | ||
| builder.store(val, var_ptr) | ||
| logger.info( | ||
| f"Assigned zero-extended i{field_ir_type.width} context field " | ||
| f"to {var_name} (i64)" | ||
| ) | ||
| return True | ||
| # TODO: handling only ctype struct fields for now. Handle other stuff too later. | ||
| elif var_type == field_ir_type: | ||
| builder.store(val, var_ptr) | ||
| logger.info(f"Assigned ctype struct field to {var_name}") | ||
| return True | ||
| else: | ||
| logger.error( | ||
| f"Failed to assign ctype struct field to {var_name}: {val_type} != {var_type}" | ||
| ) | ||
| return False | ||
| # Integer fields were normalised to their IntTy above; what is | ||
| # left is a pointer, array or struct field, which has no path | ||
| # into this slot. | ||
| logger.error( | ||
| f"Failed to assign ctype struct field to {var_name}: {val_type} != {var_type}" | ||
| ) | ||
| return False | ||
| elif isinstance(val_type, ir.IntType) and isinstance(var_type, ir.PointerType): | ||
| # NOTE: This is assignment to a PTR_TO_MAP_VALUE_OR_NULL | ||
| logger.info( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,12 @@ | ||
| import logging | ||
| import ast | ||
|
|
||
| from llvmlite import ir | ||
|
|
||
| logger: logging.Logger = logging.getLogger(__name__) | ||
|
|
||
| XDP_ACTIONS = { | ||
| "XDP_ABORTED": 0, | ||
| "XDP_DROP": 1, | ||
| "XDP_PASS": 2, | ||
| "XDP_TX": 3, | ||
| "XDP_REDIRECT": 4, | ||
| } | ||
|
|
||
|
|
||
| def handle_none_return(builder) -> bool: | ||
| """Handle return or return None -> returns 0.""" | ||
| builder.ret(ir.Constant(ir.IntType(64), 0)) | ||
| logger.debug("Generated default return: 0") | ||
| return True | ||
|
|
||
|
|
||
| def is_xdp_name(name: str) -> bool: | ||
| """Check if a name is an XDP action""" | ||
| return name in XDP_ACTIONS | ||
|
|
||
|
|
||
| def handle_xdp_return(stmt: ast.Return, builder, ret_type) -> bool: | ||
| """Handle XDP returns""" | ||
| if not isinstance(stmt.value, ast.Name): | ||
| return False | ||
|
|
||
| action_name = stmt.value.id | ||
|
|
||
| if action_name not in XDP_ACTIONS: | ||
| raise ValueError( | ||
| f"Unknown XDP action: {action_name}. Available: {XDP_ACTIONS.keys()}" | ||
| ) | ||
|
|
||
| value = XDP_ACTIONS[action_name] | ||
| builder.ret(ir.Constant(ret_type, value)) | ||
| logger.debug(f"Generated XDP action return: {action_name} = {value}") | ||
| return True |
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait what is this? XDP_TX, XDP_ABORTED and XDP_PASS (everything XDP_..) is from the vmlinux.py. Why is this being included from helpers? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,12 @@ | ||
| from .maps import HashMap, PerfEventArray, RingBuffer | ||
| from .maps import ArrayMap, HashMap, PerfEventArray, RingBuffer | ||
| from .maps_pass import maps_proc | ||
| from .map_types import BPFMapType | ||
|
|
||
| __all__ = ["HashMap", "PerfEventArray", "maps_proc", "RingBuffer", "BPFMapType"] | ||
| __all__ = [ | ||
| "ArrayMap", | ||
| "HashMap", | ||
| "PerfEventArray", | ||
| "maps_proc", | ||
| "RingBuffer", | ||
| "BPFMapType", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is bool also accepted here?