1 Commits

Author SHA1 Message Date
b84884162d Merge pull request #69 from pythonbpf/symex
Add support for userspace+kernelspace stack trace example using blazesym
2025-11-17 01:47:35 +05:30
3 changed files with 16 additions and 27 deletions

View File

@ -86,7 +86,7 @@ def processor(source_code, filename, module):
license_processing(tree, module) license_processing(tree, module)
globals_processing(tree, module) globals_processing(tree, module)
structs_sym_tab = structs_proc(tree, module, bpf_chunks) structs_sym_tab = structs_proc(tree, module, bpf_chunks)
map_sym_tab = maps_proc(tree, module, bpf_chunks, structs_sym_tab) map_sym_tab = maps_proc(tree, module, bpf_chunks)
func_proc(tree, module, bpf_chunks, map_sym_tab, structs_sym_tab) func_proc(tree, module, bpf_chunks, map_sym_tab, structs_sym_tab)
globals_list_creation(tree, module) globals_list_creation(tree, module)

View File

@ -2,7 +2,7 @@ from pythonbpf.debuginfo import DebugInfoGenerator
from .map_types import BPFMapType from .map_types import BPFMapType
def create_map_debug_info(module, map_global, map_name, map_params, structs_sym_tab): def create_map_debug_info(module, map_global, map_name, map_params):
"""Generate debug info metadata for BPF maps HASH and PERF_EVENT_ARRAY""" """Generate debug info metadata for BPF maps HASH and PERF_EVENT_ARRAY"""
generator = DebugInfoGenerator(module) generator = DebugInfoGenerator(module)
@ -64,13 +64,7 @@ def create_map_debug_info(module, map_global, map_name, map_params, structs_sym_
return global_var return global_var
# TODO: This should not be exposed outside of the module. def create_ringbuf_debug_info(module, map_global, map_name, map_params):
# Ideally we should expose a single create_map_debug_info function that handles all map types.
# We can probably use a registry pattern to register different map types and their debug info generators.
# map_params["type"] will be used to determine which generator to use.
def create_ringbuf_debug_info(
module, map_global, map_name, map_params, structs_sym_tab
):
"""Generate debug information metadata for BPF RINGBUF map""" """Generate debug information metadata for BPF RINGBUF map"""
generator = DebugInfoGenerator(module) generator = DebugInfoGenerator(module)

View File

@ -12,15 +12,13 @@ from pythonbpf.expr.vmlinux_registry import VmlinuxHandlerRegistry
logger: Logger = logging.getLogger(__name__) logger: Logger = logging.getLogger(__name__)
def maps_proc(tree, module, chunks, structs_sym_tab): 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):
logger.info(f"Found BPF map: {func_node.name}") logger.info(f"Found BPF map: {func_node.name}")
map_sym_tab[func_node.name] = process_bpf_map( map_sym_tab[func_node.name] = process_bpf_map(func_node, module)
func_node, module, structs_sym_tab
)
return map_sym_tab return map_sym_tab
@ -62,8 +60,7 @@ def _parse_map_params(rval, expected_args=None):
if i < len(rval.args): if i < len(rval.args):
arg = rval.args[i] arg = rval.args[i]
if isinstance(arg, ast.Name): if isinstance(arg, ast.Name):
result = _get_vmlinux_enum(handler, arg.id) params[arg_name] = arg.id
params[arg_name] = result if result is not None else arg.id
elif isinstance(arg, ast.Constant): elif isinstance(arg, ast.Constant):
params[arg_name] = arg.value params[arg_name] = arg.value
@ -71,21 +68,19 @@ def _parse_map_params(rval, expected_args=None):
for keyword in rval.keywords: for keyword in rval.keywords:
if isinstance(keyword.value, ast.Name): if isinstance(keyword.value, ast.Name):
name = keyword.value.id name = keyword.value.id
result = _get_vmlinux_enum(handler, name) if handler and handler.is_vmlinux_enum(name):
params[keyword.arg] = result if result is not None else name result = handler.get_vmlinux_enum_value(name)
params[keyword.arg] = result if result is not None else name
else:
params[keyword.arg] = name
elif isinstance(keyword.value, ast.Constant): elif isinstance(keyword.value, ast.Constant):
params[keyword.arg] = keyword.value.value params[keyword.arg] = keyword.value.value
return params return params
def _get_vmlinux_enum(handler, name):
if handler and handler.is_vmlinux_enum(name):
return handler.get_vmlinux_enum_value(name)
@MapProcessorRegistry.register("RingBuffer") @MapProcessorRegistry.register("RingBuffer")
def process_ringbuf_map(map_name, rval, module, structs_sym_tab): def process_ringbuf_map(map_name, rval, module):
"""Process a BPF_RINGBUF map declaration""" """Process a BPF_RINGBUF map declaration"""
logger.info(f"Processing Ringbuf: {map_name}") logger.info(f"Processing Ringbuf: {map_name}")
map_params = _parse_map_params(rval, expected_args=["max_entries"]) map_params = _parse_map_params(rval, expected_args=["max_entries"])
@ -110,7 +105,7 @@ def process_ringbuf_map(map_name, rval, module, structs_sym_tab):
@MapProcessorRegistry.register("HashMap") @MapProcessorRegistry.register("HashMap")
def process_hash_map(map_name, rval, module, structs_sym_tab): def process_hash_map(map_name, rval, module):
"""Process a BPF_HASH map declaration""" """Process a BPF_HASH map declaration"""
logger.info(f"Processing HashMap: {map_name}") logger.info(f"Processing HashMap: {map_name}")
map_params = _parse_map_params(rval, expected_args=["key", "value", "max_entries"]) map_params = _parse_map_params(rval, expected_args=["key", "value", "max_entries"])
@ -124,7 +119,7 @@ def process_hash_map(map_name, rval, module, structs_sym_tab):
@MapProcessorRegistry.register("PerfEventArray") @MapProcessorRegistry.register("PerfEventArray")
def process_perf_event_map(map_name, rval, module, structs_sym_tab): def process_perf_event_map(map_name, rval, module):
"""Process a BPF_PERF_EVENT_ARRAY map declaration""" """Process a BPF_PERF_EVENT_ARRAY map declaration"""
logger.info(f"Processing PerfEventArray: {map_name}") logger.info(f"Processing PerfEventArray: {map_name}")
map_params = _parse_map_params(rval, expected_args=["key_size", "value_size"]) map_params = _parse_map_params(rval, expected_args=["key_size", "value_size"])
@ -137,7 +132,7 @@ def process_perf_event_map(map_name, rval, module, structs_sym_tab):
return map_global return map_global
def process_bpf_map(func_node, module, structs_sym_tab): def process_bpf_map(func_node, module):
"""Process a BPF map (a function decorated with @map)""" """Process a BPF map (a function decorated with @map)"""
map_name = func_node.name map_name = func_node.name
logger.info(f"Processing BPF map: {map_name}") logger.info(f"Processing BPF map: {map_name}")
@ -156,7 +151,7 @@ def process_bpf_map(func_node, module, structs_sym_tab):
if isinstance(rval, ast.Call) and isinstance(rval.func, ast.Name): if isinstance(rval, ast.Call) and isinstance(rval.func, ast.Name):
handler = MapProcessorRegistry.get_processor(rval.func.id) handler = MapProcessorRegistry.get_processor(rval.func.id)
if handler: if handler:
return handler(map_name, rval, module, structs_sym_tab) return handler(map_name, rval, module)
else: else:
logger.warning(f"Unknown map type {rval.func.id}, defaulting to HashMap") logger.warning(f"Unknown map type {rval.func.id}, defaulting to HashMap")
return process_hash_map(map_name, rval, module) return process_hash_map(map_name, rval, module)