Skip to content

Commit 26ee4d4

Browse files
r41k0uclaude
andcommitted
Core: Emit debug info for globals so llc produces BTF VAR and DATASEC
Each integer global gets a DIGlobalVariableExpression with a C-named basic type (matching signedness and width), attached via !dbg -- the same mechanism map_debug_info.py already uses. llc's BPF backend manufactures the BTF VAR and DATASEC '.bss'/'.data' entries from it: [2] VAR 'expected_pid' type_id=1, linkage=global [3] VAR 'cg_id' type_id=1, linkage=global [4] DATASEC '.bss' size=0 vlen=2 Verified against clang's output for the same shapes: the in-object DATASEC var offsets read 0 in both (libbpf patches them from the ELF symbol table at load), and the ELF symbols carry the real layout, identical to the reference (expected_pid at .bss+0, cg_id at .bss+8). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L1PX8EuP9C3o3veWGA84RF
1 parent 4ee96e7 commit 26ee4d4

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

pythonbpf/globals_pass.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,25 @@
55
from logging import Logger
66
import logging
77
from .type_deducer import ctypes_to_ir
8+
from .debuginfo import DebugInfoGenerator
9+
from .debuginfo import dwarf_constants as dc
810

911
logger: Logger = logging.getLogger(__name__)
1012

13+
_SIGNED_CTYPES = {
14+
"c_int8",
15+
"c_int16",
16+
"c_int32",
17+
"c_int64",
18+
"c_int",
19+
"c_short",
20+
"c_long",
21+
"c_longlong",
22+
"c_byte",
23+
}
24+
25+
_C_NAME_BY_WIDTH = {8: "char", 16: "short", 32: "int", 64: "long long"}
26+
1127

1228
@dataclass
1329
class BpfGlobalSymbol:
@@ -93,6 +109,28 @@ def _emit_global(module: ir.Module, node, name):
93109
return gvar
94110

95111

112+
def _emit_global_debug_info(compilation_context, gvar, name, ctype_name):
113+
"""Attach DIGlobalVariableExpression metadata to a BPF global.
114+
115+
llc's BPF backend manufactures the BTF VAR and DATASEC ('.bss'/'.data')
116+
entries from exactly this metadata (see tests/c-form/global_vars.bpf.c);
117+
without it, libbpf still creates the section maps but neither bpftool nor a
118+
future skeleton can tell which variable lives at which offset.
119+
"""
120+
generator = DebugInfoGenerator(compilation_context.module)
121+
width = gvar.value_type.width
122+
signed = ctype_name in _SIGNED_CTYPES
123+
base = _C_NAME_BY_WIDTH[width]
124+
if width == 8:
125+
encoding = dc.DW_ATE_signed_char if signed else dc.DW_ATE_unsigned_char
126+
else:
127+
encoding = dc.DW_ATE_signed if signed else dc.DW_ATE_unsigned
128+
cname = base if signed else f"unsigned {base}"
129+
di_type = generator.get_basic_type(cname, width, encoding)
130+
dv = generator.create_global_var_debug_info(name, di_type, is_local=False)
131+
gvar.set_metadata("dbg", dv)
132+
133+
96134
def globals_processing(tree, compilation_context):
97135
"""Process stuff decorated with @bpf and @bpfglobal except license and return the section name"""
98136
# Local tracking for duplicate checking if needed, or we can iterate context
@@ -137,6 +175,9 @@ def globals_processing(tree, compilation_context):
137175
ir_type=gvar.value_type,
138176
ctype_name=node.returns.id,
139177
)
178+
_emit_global_debug_info(
179+
compilation_context, gvar, name, node.returns.id
180+
)
140181
else:
141182
raise NotImplementedError(
142183
f"Global '{name}': only integer scalar globals are "

0 commit comments

Comments
 (0)