Skip to content

Commit b2a57ed

Browse files
committed
Simplify maps_pass
1 parent 6345fcd commit b2a57ed

File tree

3 files changed

+161
-172
lines changed

3 files changed

+161
-172
lines changed

pythonbpf/maps/map_debug_info.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
from pythonbpf.debuginfo import DebugInfoGenerator
2+
from .map_types import BPFMapType
3+
4+
5+
def create_map_debug_info(module, map_global, map_name, map_params):
6+
"""Generate debug info metadata for BPF maps HASH and PERF_EVENT_ARRAY"""
7+
generator = DebugInfoGenerator(module)
8+
9+
uint_type = generator.get_uint32_type()
10+
ulong_type = generator.get_uint64_type()
11+
array_type = generator.create_array_type(
12+
uint_type, map_params.get("type", BPFMapType.UNSPEC).value
13+
)
14+
type_ptr = generator.create_pointer_type(array_type, 64)
15+
key_ptr = generator.create_pointer_type(
16+
array_type if "key_size" in map_params else ulong_type, 64
17+
)
18+
value_ptr = generator.create_pointer_type(
19+
array_type if "value_size" in map_params else ulong_type, 64
20+
)
21+
22+
elements_arr = []
23+
24+
# Create struct members
25+
# scope field does not appear for some reason
26+
cnt = 0
27+
for elem in map_params:
28+
if elem == "max_entries":
29+
continue
30+
if elem == "type":
31+
ptr = type_ptr
32+
elif "key" in elem:
33+
ptr = key_ptr
34+
else:
35+
ptr = value_ptr
36+
# TODO: the best way to do this is not 64, but get the size each time. this will not work for structs.
37+
member = generator.create_struct_member(elem, ptr, cnt * 64)
38+
elements_arr.append(member)
39+
cnt += 1
40+
41+
if "max_entries" in map_params:
42+
max_entries_array = generator.create_array_type(
43+
uint_type, map_params["max_entries"]
44+
)
45+
max_entries_ptr = generator.create_pointer_type(max_entries_array, 64)
46+
max_entries_member = generator.create_struct_member(
47+
"max_entries", max_entries_ptr, cnt * 64
48+
)
49+
elements_arr.append(max_entries_member)
50+
51+
# Create the struct type
52+
struct_type = generator.create_struct_type(
53+
elements_arr, 64 * len(elements_arr), is_distinct=True
54+
)
55+
56+
# Create global variable debug info
57+
global_var = generator.create_global_var_debug_info(
58+
map_name, struct_type, is_local=False
59+
)
60+
61+
# Attach debug info to the global variable
62+
map_global.set_metadata("dbg", global_var)
63+
64+
return global_var
65+
66+
67+
def create_ringbuf_debug_info(module, map_global, map_name, map_params):
68+
"""Generate debug information metadata for BPF RINGBUF map"""
69+
generator = DebugInfoGenerator(module)
70+
71+
int_type = generator.get_int32_type()
72+
73+
type_array = generator.create_array_type(
74+
int_type, map_params.get("type", BPFMapType.RINGBUF).value
75+
)
76+
type_ptr = generator.create_pointer_type(type_array, 64)
77+
type_member = generator.create_struct_member("type", type_ptr, 0)
78+
79+
max_entries_array = generator.create_array_type(int_type, map_params["max_entries"])
80+
max_entries_ptr = generator.create_pointer_type(max_entries_array, 64)
81+
max_entries_member = generator.create_struct_member(
82+
"max_entries", max_entries_ptr, 64
83+
)
84+
85+
elements_arr = [type_member, max_entries_member]
86+
87+
struct_type = generator.create_struct_type(elements_arr, 128, is_distinct=True)
88+
89+
global_var = generator.create_global_var_debug_info(
90+
map_name, struct_type, is_local=False
91+
)
92+
map_global.set_metadata("dbg", global_var)
93+
return global_var

pythonbpf/maps/map_types.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from enum import Enum
2+
3+
4+
class BPFMapType(Enum):
5+
UNSPEC = 0
6+
HASH = 1
7+
ARRAY = 2
8+
PROG_ARRAY = 3
9+
PERF_EVENT_ARRAY = 4
10+
PERCPU_HASH = 5
11+
PERCPU_ARRAY = 6
12+
STACK_TRACE = 7
13+
CGROUP_ARRAY = 8
14+
LRU_HASH = 9
15+
LRU_PERCPU_HASH = 10
16+
LPM_TRIE = 11
17+
ARRAY_OF_MAPS = 12
18+
HASH_OF_MAPS = 13
19+
DEVMAP = 14
20+
SOCKMAP = 15
21+
CPUMAP = 16
22+
XSKMAP = 17
23+
SOCKHASH = 18
24+
CGROUP_STORAGE_DEPRECATED = 19
25+
CGROUP_STORAGE = 19
26+
REUSEPORT_SOCKARRAY = 20
27+
PERCPU_CGROUP_STORAGE_DEPRECATED = 21
28+
PERCPU_CGROUP_STORAGE = 21
29+
QUEUE = 22
30+
STACK = 23
31+
SK_STORAGE = 24
32+
DEVMAP_HASH = 25
33+
STRUCT_OPS = 26
34+
RINGBUF = 27
35+
INODE_STORAGE = 28
36+
TASK_STORAGE = 29
37+
BLOOM_FILTER = 30
38+
USER_RINGBUF = 31
39+
CGRP_STORAGE = 32

pythonbpf/maps/maps_pass.py

Lines changed: 29 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import ast
2+
import logging
23
from logging import Logger
34
from llvmlite import ir
4-
from enum import Enum
5+
56
from .maps_utils import MapProcessorRegistry
6-
from pythonbpf.debuginfo import DebugInfoGenerator
7-
import logging
7+
from .map_types import BPFMapType
8+
from .map_debug_info import create_map_debug_info, create_ringbuf_debug_info
89

910
logger: Logger = logging.getLogger(__name__)
1011

@@ -26,44 +27,6 @@ def is_map(func_node):
2627
)
2728

2829

29-
class BPFMapType(Enum):
30-
UNSPEC = 0
31-
HASH = 1
32-
ARRAY = 2
33-
PROG_ARRAY = 3
34-
PERF_EVENT_ARRAY = 4
35-
PERCPU_HASH = 5
36-
PERCPU_ARRAY = 6
37-
STACK_TRACE = 7
38-
CGROUP_ARRAY = 8
39-
LRU_HASH = 9
40-
LRU_PERCPU_HASH = 10
41-
LPM_TRIE = 11
42-
ARRAY_OF_MAPS = 12
43-
HASH_OF_MAPS = 13
44-
DEVMAP = 14
45-
SOCKMAP = 15
46-
CPUMAP = 16
47-
XSKMAP = 17
48-
SOCKHASH = 18
49-
CGROUP_STORAGE_DEPRECATED = 19
50-
CGROUP_STORAGE = 19
51-
REUSEPORT_SOCKARRAY = 20
52-
PERCPU_CGROUP_STORAGE_DEPRECATED = 21
53-
PERCPU_CGROUP_STORAGE = 21
54-
QUEUE = 22
55-
STACK = 23
56-
SK_STORAGE = 24
57-
DEVMAP_HASH = 25
58-
STRUCT_OPS = 26
59-
RINGBUF = 27
60-
INODE_STORAGE = 28
61-
TASK_STORAGE = 29
62-
BLOOM_FILTER = 30
63-
USER_RINGBUF = 31
64-
CGRP_STORAGE = 32
65-
66-
6730
def create_bpf_map(module, map_name, map_params):
6831
"""Create a BPF map in the module with given parameters and debug info"""
6932

@@ -84,114 +47,37 @@ def create_bpf_map(module, map_name, map_params):
8447
return map_global
8548

8649

87-
def create_map_debug_info(module, map_global, map_name, map_params):
88-
"""Generate debug info metadata for BPF maps HASH and PERF_EVENT_ARRAY"""
89-
generator = DebugInfoGenerator(module)
90-
91-
uint_type = generator.get_uint32_type()
92-
ulong_type = generator.get_uint64_type()
93-
array_type = generator.create_array_type(
94-
uint_type, map_params.get("type", BPFMapType.UNSPEC).value
95-
)
96-
type_ptr = generator.create_pointer_type(array_type, 64)
97-
key_ptr = generator.create_pointer_type(
98-
array_type if "key_size" in map_params else ulong_type, 64
99-
)
100-
value_ptr = generator.create_pointer_type(
101-
array_type if "value_size" in map_params else ulong_type, 64
102-
)
103-
104-
elements_arr = []
105-
106-
# Create struct members
107-
# scope field does not appear for some reason
108-
cnt = 0
109-
for elem in map_params:
110-
if elem == "max_entries":
111-
continue
112-
if elem == "type":
113-
ptr = type_ptr
114-
elif "key" in elem:
115-
ptr = key_ptr
116-
else:
117-
ptr = value_ptr
118-
# TODO: the best way to do this is not 64, but get the size each time. this will not work for structs.
119-
member = generator.create_struct_member(elem, ptr, cnt * 64)
120-
elements_arr.append(member)
121-
cnt += 1
122-
123-
if "max_entries" in map_params:
124-
max_entries_array = generator.create_array_type(
125-
uint_type, map_params["max_entries"]
126-
)
127-
max_entries_ptr = generator.create_pointer_type(max_entries_array, 64)
128-
max_entries_member = generator.create_struct_member(
129-
"max_entries", max_entries_ptr, cnt * 64
130-
)
131-
elements_arr.append(max_entries_member)
132-
133-
# Create the struct type
134-
struct_type = generator.create_struct_type(
135-
elements_arr, 64 * len(elements_arr), is_distinct=True
136-
)
137-
138-
# Create global variable debug info
139-
global_var = generator.create_global_var_debug_info(
140-
map_name, struct_type, is_local=False
141-
)
142-
143-
# Attach debug info to the global variable
144-
map_global.set_metadata("dbg", global_var)
145-
146-
return global_var
50+
def _parse_map_params(rval, expected_args=None):
51+
"""Parse map parameters from call arguments and keywords."""
14752

53+
params = {}
14854

149-
def create_ringbuf_debug_info(module, map_global, map_name, map_params):
150-
"""Generate debug information metadata for BPF RINGBUF map"""
151-
generator = DebugInfoGenerator(module)
55+
# Parse positional arguments
56+
if expected_args:
57+
for i, arg_name in enumerate(expected_args):
58+
if i < len(rval.args):
59+
arg = rval.args[i]
60+
if isinstance(arg, ast.Name):
61+
params[arg_name] = arg.id
62+
elif isinstance(arg, ast.Constant):
63+
params[arg_name] = arg.value
15264

153-
int_type = generator.get_int32_type()
154-
155-
type_array = generator.create_array_type(
156-
int_type, map_params.get("type", BPFMapType.RINGBUF).value
157-
)
158-
type_ptr = generator.create_pointer_type(type_array, 64)
159-
type_member = generator.create_struct_member("type", type_ptr, 0)
160-
161-
max_entries_array = generator.create_array_type(int_type, map_params["max_entries"])
162-
max_entries_ptr = generator.create_pointer_type(max_entries_array, 64)
163-
max_entries_member = generator.create_struct_member(
164-
"max_entries", max_entries_ptr, 64
165-
)
166-
167-
elements_arr = [type_member, max_entries_member]
168-
169-
struct_type = generator.create_struct_type(elements_arr, 128, is_distinct=True)
65+
# Parse keyword arguments (override positional)
66+
for keyword in rval.keywords:
67+
if isinstance(keyword.value, ast.Name):
68+
params[keyword.arg] = keyword.value.id
69+
elif isinstance(keyword.value, ast.Constant):
70+
params[keyword.arg] = keyword.value.value
17071

171-
global_var = generator.create_global_var_debug_info(
172-
map_name, struct_type, is_local=False
173-
)
174-
map_global.set_metadata("dbg", global_var)
175-
return global_var
72+
return params
17673

17774

17875
@MapProcessorRegistry.register("RingBuf")
17976
def process_ringbuf_map(map_name, rval, module):
18077
"""Process a BPF_RINGBUF map declaration"""
18178
logger.info(f"Processing Ringbuf: {map_name}")
182-
map_params = {"type": BPFMapType.RINGBUF}
183-
184-
# Parse max_entries if present
185-
if len(rval.args) >= 1 and isinstance(rval.args[0], ast.Constant):
186-
const_val = rval.args[0].value
187-
if isinstance(const_val, int):
188-
map_params["max_entries"] = const_val
189-
190-
for keyword in rval.keywords:
191-
if keyword.arg == "max_entries" and isinstance(keyword.value, ast.Constant):
192-
const_val = keyword.value.value
193-
if isinstance(const_val, int):
194-
map_params["max_entries"] = const_val
79+
map_params = _parse_map_params(rval, expected_args=["max_entries"])
80+
map_params["type"] = BPFMapType.RINGBUF
19581

19682
logger.info(f"Ringbuf map parameters: {map_params}")
19783

@@ -204,27 +90,8 @@ def process_ringbuf_map(map_name, rval, module):
20490
def process_hash_map(map_name, rval, module):
20591
"""Process a BPF_HASH map declaration"""
20692
logger.info(f"Processing HashMap: {map_name}")
207-
map_params = {"type": BPFMapType.HASH}
208-
209-
# Assuming order: key_type, value_type, max_entries
210-
if len(rval.args) >= 1 and isinstance(rval.args[0], ast.Name):
211-
map_params["key"] = rval.args[0].id
212-
if len(rval.args) >= 2 and isinstance(rval.args[1], ast.Name):
213-
map_params["value"] = rval.args[1].id
214-
if len(rval.args) >= 3 and isinstance(rval.args[2], ast.Constant):
215-
const_val = rval.args[2].value
216-
if isinstance(const_val, (int, str)): # safe check
217-
map_params["max_entries"] = const_val
218-
219-
for keyword in rval.keywords:
220-
if keyword.arg == "key" and isinstance(keyword.value, ast.Name):
221-
map_params["key"] = keyword.value.id
222-
elif keyword.arg == "value" and isinstance(keyword.value, ast.Name):
223-
map_params["value"] = keyword.value.id
224-
elif keyword.arg == "max_entries" and isinstance(keyword.value, ast.Constant):
225-
const_val = keyword.value.value
226-
if isinstance(const_val, (int, str)):
227-
map_params["max_entries"] = const_val
93+
map_params = _parse_map_params(rval, expected_args=["key", "value", "max_entries"])
94+
map_params["type"] = BPFMapType.HASH
22895

22996
logger.info(f"Map parameters: {map_params}")
23097
map_global = create_bpf_map(module, map_name, map_params)
@@ -237,18 +104,8 @@ def process_hash_map(map_name, rval, module):
237104
def process_perf_event_map(map_name, rval, module):
238105
"""Process a BPF_PERF_EVENT_ARRAY map declaration"""
239106
logger.info(f"Processing PerfEventArray: {map_name}")
240-
map_params = {"type": BPFMapType.PERF_EVENT_ARRAY}
241-
242-
if len(rval.args) >= 1 and isinstance(rval.args[0], ast.Name):
243-
map_params["key_size"] = rval.args[0].id
244-
if len(rval.args) >= 2 and isinstance(rval.args[1], ast.Name):
245-
map_params["value_size"] = rval.args[1].id
246-
247-
for keyword in rval.keywords:
248-
if keyword.arg == "key_size" and isinstance(keyword.value, ast.Name):
249-
map_params["key_size"] = keyword.value.id
250-
elif keyword.arg == "value_size" and isinstance(keyword.value, ast.Name):
251-
map_params["value_size"] = keyword.value.id
107+
map_params = _parse_map_params(rval, expected_args=["key_size", "value_size"])
108+
map_params["type"] = BPFMapType.PERF_EVENT_ARRAY
252109

253110
logger.info(f"Map parameters: {map_params}")
254111
map_global = create_bpf_map(module, map_name, map_params)

0 commit comments

Comments
 (0)