1+ import ctypes
12import logging
2- from pythonbpf .vmlinux_parser .dependency_handler import DependencyHandler
3+ from ..dependency_handler import DependencyHandler
4+ from .debug_info_gen import debug_info_generation
5+ from ..dependency_node import DependencyNode
6+ import llvmlite .ir as ir
37
48logger = logging .getLogger (__name__ )
59
610
711class IRGenerator :
8- def __init__ (self , module , handler : DependencyHandler ):
9- self .module = module
12+ # get the assignments dict and add this stuff to it.
13+ def __init__ (self , llvm_module , handler : DependencyHandler , assignment = None ):
14+ self .llvm_module = llvm_module
1015 self .handler : DependencyHandler = handler
1116 self .generated : list [str ] = []
1217 if not handler .is_ready :
@@ -15,22 +20,142 @@ def __init__(self, module, handler: DependencyHandler):
1520 )
1621 for struct in handler :
1722 self .struct_processor (struct )
18- print ()
19-
20- def struct_processor (self , struct ):
21- if struct .name not in self .generated :
22- print (f"IR generating for { struct .name } " )
23- print (f"Struct is { struct } " )
24- for dependency in struct .depends_on :
25- if dependency not in self .generated :
26- dep_node_from_dependency = self .handler [dependency ]
27- self .struct_processor (dep_node_from_dependency )
28- self .generated .append (dependency )
29- # write actual processor logic here after assuming all dependencies are resolved
30- # this part cannot yet resolve circular dependencies. Gets stuck on an infinite loop during that.
23+
24+ def struct_processor (self , struct , processing_stack = None ):
25+ # Initialize processing stack on first call
26+ if processing_stack is None :
27+ processing_stack = set ()
28+
29+ # If already generated, skip
30+ if struct .name in self .generated :
31+ return
32+
33+ # Detect circular dependency
34+ if struct .name in processing_stack :
35+ logger .info (
36+ f"Circular dependency detected for { struct .name } , skipping recursive processing"
37+ )
38+ # For circular dependencies, we can either:
39+ # 1. Use forward declarations (opaque pointers)
40+ # 2. Mark as incomplete and process later
41+ # 3. Generate a placeholder type
42+ # Here we'll just skip and let it be processed in its own call
43+ return
44+
45+ logger .info (f"IR generating for { struct .name } " )
46+
47+ # Add to processing stack before processing dependencies
48+ processing_stack .add (struct .name )
49+
50+ try :
51+ # Process all dependencies first
52+ if struct .depends_on is None :
53+ pass
54+ else :
55+ for dependency in struct .depends_on :
56+ if dependency not in self .generated :
57+ # Check if dependency exists in handler
58+ if dependency in self .handler .nodes :
59+ dep_node_from_dependency = self .handler [dependency ]
60+ # Pass the processing_stack down to track circular refs
61+ self .struct_processor (
62+ dep_node_from_dependency , processing_stack
63+ )
64+ else :
65+ raise RuntimeError (
66+ f"Warning: Dependency { dependency } not found in handler"
67+ )
68+
69+ # Actual processor logic here after dependencies are resolved
70+ self .gen_ir (struct )
3171 self .generated .append (struct .name )
3272
33- def struct_name_generator (
73+ finally :
74+ # Remove from processing stack after we're done
75+ processing_stack .discard (struct .name )
76+
77+ def gen_ir (self , struct ):
78+ # TODO: we add the btf_ama attribute by monkey patching in the end of compilation, but once llvmlite
79+ # accepts our issue, we will resort to normal accessed attribute based attribute addition
80+ # currently we generate all possible field accesses for CO-RE and put into the assignment table
81+ debug_info = debug_info_generation (struct , self .llvm_module )
82+ field_index = 0
83+ for field_name , field in struct .fields .items ():
84+ # does not take arrays and similar types into consideration yet.
85+ if field .ctype_complex_type is not None and issubclass (
86+ field .ctype_complex_type , ctypes .Array
87+ ):
88+ array_size = field .type_size
89+ containing_type = field .containing_type
90+ if containing_type .__module__ == ctypes .__name__ :
91+ containing_type_size = ctypes .sizeof (containing_type )
92+ for i in range (0 , array_size ):
93+ field_co_re_name = self ._struct_name_generator (
94+ struct , field , field_index , True , i , containing_type_size
95+ )
96+ globvar = ir .GlobalVariable (
97+ self .llvm_module , ir .IntType (64 ), name = field_co_re_name
98+ )
99+ globvar .linkage = "external"
100+ globvar .set_metadata ("llvm.preserve.access.index" , debug_info )
101+ field_index += 1
102+ elif field .type_size is not None :
103+ array_size = field .type_size
104+ containing_type = field .containing_type
105+ if containing_type .__module__ == "vmlinux" :
106+ containing_type_size = self .handler [
107+ containing_type .__name__
108+ ].current_offset
109+ for i in range (0 , array_size ):
110+ field_co_re_name = self ._struct_name_generator (
111+ struct , field , field_index , True , i , containing_type_size
112+ )
113+ globvar = ir .GlobalVariable (
114+ self .llvm_module , ir .IntType (64 ), name = field_co_re_name
115+ )
116+ globvar .linkage = "external"
117+ globvar .set_metadata ("llvm.preserve.access.index" , debug_info )
118+ field_index += 1
119+ else :
120+ field_co_re_name = self ._struct_name_generator (
121+ struct , field , field_index
122+ )
123+ field_index += 1
124+ globvar = ir .GlobalVariable (
125+ self .llvm_module , ir .IntType (64 ), name = field_co_re_name
126+ )
127+ globvar .linkage = "external"
128+ globvar .set_metadata ("llvm.preserve.access.index" , debug_info )
129+
130+ def _struct_name_generator (
34131 self ,
35- ) -> None :
36- pass
132+ struct : DependencyNode ,
133+ field ,
134+ field_index : int ,
135+ is_indexed : bool = False ,
136+ index : int = 0 ,
137+ containing_type_size : int = 0 ,
138+ ) -> str :
139+ if is_indexed :
140+ name = (
141+ "llvm."
142+ + struct .name .removeprefix ("struct_" )
143+ + f":0:{ field .offset + index * containing_type_size } "
144+ + "$"
145+ + f"0:{ field_index } :{ index } "
146+ )
147+ return name
148+ elif struct .name .startswith ("struct_" ):
149+ name = (
150+ "llvm."
151+ + struct .name .removeprefix ("struct_" )
152+ + f":0:{ field .offset } "
153+ + "$"
154+ + f"0:{ field_index } "
155+ )
156+ return name
157+ else :
158+ print (self .handler [struct .name ])
159+ raise TypeError (
160+ "Name generation cannot occur due to type name not starting with struct"
161+ )
0 commit comments