Skip to content

Commit c5bef26

Browse files
add multi imports to single import line.
1 parent a9d82d4 commit c5bef26

File tree

2 files changed

+50
-41
lines changed

2 files changed

+50
-41
lines changed

pythonbpf/vmlinux_parser/import_detector.py

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def detect_import_statement(tree: ast.AST) -> list[tuple[str, ast.ImportFrom]]:
2525
List of tuples containing (module_name, imported_item) for each vmlinux import
2626
2727
Raises:
28-
SyntaxError: If multiple imports from vmlinux are attempted or import * is used
28+
SyntaxError: If import * is used
2929
"""
3030
vmlinux_imports = []
3131

@@ -40,28 +40,19 @@ def detect_import_statement(tree: ast.AST) -> list[tuple[str, ast.ImportFrom]]:
4040
"Please import specific types explicitly."
4141
)
4242

43-
# Check for multiple imports: from vmlinux import A, B, C
44-
if len(node.names) > 1:
45-
imported_names = [alias.name for alias in node.names]
46-
raise SyntaxError(
47-
f"Multiple imports from vmlinux are not supported. "
48-
f"Found: {', '.join(imported_names)}. "
49-
f"Please use separate import statements for each type."
50-
)
51-
5243
# Check if no specific import is specified (should not happen with valid Python)
5344
if len(node.names) == 0:
5445
raise SyntaxError(
5546
"Import from vmlinux must specify at least one type."
5647
)
5748

58-
# Valid single import
49+
# Support multiple imports: from vmlinux import A, B, C
5950
for alias in node.names:
6051
import_name = alias.name
61-
# Use alias if provided, otherwise use the original name (commented)
62-
# as_name = alias.asname if alias.asname else alias.name
63-
vmlinux_imports.append(("vmlinux", node))
64-
logger.info(f"Found vmlinux import: {import_name}")
52+
# Use alias if provided, otherwise use the original name
53+
as_name = alias.asname if alias.asname else alias.name
54+
vmlinux_imports.append(("vmlinux", node, import_name, as_name))
55+
logger.info(f"Found vmlinux import: {import_name} as {as_name}")
6556

6657
# Handle "import vmlinux" statements (not typical but should be rejected)
6758
elif isinstance(node, ast.Import):
@@ -103,40 +94,37 @@ def vmlinux_proc(tree: ast.AST, module):
10394
with open(source_file, "r") as f:
10495
mod_ast = ast.parse(f.read(), filename=source_file)
10596

106-
for import_mod, import_node in import_statements:
107-
for alias in import_node.names:
108-
imported_name = alias.name
109-
found = False
110-
for mod_node in mod_ast.body:
111-
if (
112-
isinstance(mod_node, ast.ClassDef)
113-
and mod_node.name == imported_name
114-
):
115-
process_vmlinux_class(mod_node, module, handler)
116-
found = True
117-
break
118-
if isinstance(mod_node, ast.Assign):
119-
for target in mod_node.targets:
120-
if isinstance(target, ast.Name) and target.id == imported_name:
121-
process_vmlinux_assign(mod_node, module, assignments)
122-
found = True
123-
break
124-
if found:
125-
break
126-
if not found:
127-
logger.info(
128-
f"{imported_name} not found as ClassDef or Assign in vmlinux"
129-
)
97+
for import_mod, import_node, imported_name, as_name in import_statements:
98+
found = False
99+
for mod_node in mod_ast.body:
100+
if isinstance(mod_node, ast.ClassDef) and mod_node.name == imported_name:
101+
process_vmlinux_class(mod_node, module, handler)
102+
found = True
103+
break
104+
if isinstance(mod_node, ast.Assign):
105+
for target in mod_node.targets:
106+
if isinstance(target, ast.Name) and target.id == imported_name:
107+
process_vmlinux_assign(mod_node, module, assignments, as_name)
108+
found = True
109+
break
110+
if found:
111+
break
112+
if not found:
113+
logger.info(f"{imported_name} not found as ClassDef or Assign in vmlinux")
130114

131115
IRGenerator(module, handler, assignments)
132116
return assignments
133117

134118

135-
def process_vmlinux_assign(node, module, assignments: dict[str, AssignmentInfo]):
119+
def process_vmlinux_assign(
120+
node, module, assignments: dict[str, AssignmentInfo], target_name=None
121+
):
136122
"""Process assignments from vmlinux module."""
137123
# Only handle single-target assignments
138124
if len(node.targets) == 1 and isinstance(node.targets[0], ast.Name):
139-
target_name = node.targets[0].id
125+
# Use provided target_name (for aliased imports) or fall back to original name
126+
if target_name is None:
127+
target_name = node.targets[0].id
140128

141129
# Handle constant value assignments
142130
if isinstance(node.value, ast.Constant):
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from vmlinux import struct_request, struct_pt_regs, XDP_PASS
2+
from pythonbpf import bpf, section, bpfglobal, compile_to_ir
3+
import logging
4+
5+
6+
@bpf
7+
@section("kprobe/blk_mq_start_request")
8+
def example(ctx: struct_pt_regs):
9+
req = struct_request(ctx.di)
10+
c = req.__data_len
11+
d = XDP_PASS
12+
print(f"data length {c} and test {d}")
13+
14+
15+
@bpf
16+
@bpfglobal
17+
def LICENSE() -> str:
18+
return "GPL"
19+
20+
21+
compile_to_ir("requests.py", "requests.ll", loglevel=logging.INFO)

0 commit comments

Comments
 (0)