@@ -15,7 +15,20 @@ def get_module_symbols(module_name: str):
1515
1616
1717# Recursive function that gets all the dependent classes and adds them to handler
18- def process_vmlinux_class (node , llvm_module , handler : DependencyHandler ):
18+ def process_vmlinux_class (node , llvm_module , handler : DependencyHandler , processing_stack = None ):
19+ """
20+ Recursively process vmlinux classes and their dependencies.
21+
22+ Args:
23+ node: The class/type to process
24+ llvm_module: The LLVM module context
25+ handler: DependencyHandler to track all nodes
26+ processing_stack: Set of currently processing nodes to detect cycles
27+ """
28+ # Initialize processing stack on first call
29+ if processing_stack is None :
30+ processing_stack = set ()
31+
1932 symbols_in_module , imported_module = get_module_symbols ("vmlinux" )
2033
2134 # Handle both node objects and type objects
@@ -28,80 +41,120 @@ def process_vmlinux_class(node, llvm_module, handler: DependencyHandler):
2841
2942 if current_symbol_name not in symbols_in_module :
3043 raise ImportError (f"{ current_symbol_name } not present in module vmlinux" )
44+
45+ # Check if we're already processing this node (circular dependency)
46+ if current_symbol_name in processing_stack :
47+ logger .debug (f"Circular dependency detected for { current_symbol_name } , skipping" )
48+ return True
49+
50+ # Check if already processed
51+ if handler .has_node (current_symbol_name ):
52+ existing_node = handler .get_node (current_symbol_name )
53+ # If the node exists and is ready, we're done
54+ if existing_node and existing_node .is_ready :
55+ logger .info (f"Node { current_symbol_name } already processed and ready" )
56+ return True
57+
3158 logger .info (f"Resolving vmlinux class { current_symbol_name } " )
3259 logger .debug (
3360 f"Current handler state: { handler .is_ready } readiness and { handler .get_all_nodes ()} all nodes"
3461 )
35- field_table = {} # should contain the field and it's type.
3662
37- # Get the class object from the module
38- class_obj = getattr ( imported_module , current_symbol_name )
63+ # Add to processing stack to detect cycles
64+ processing_stack . add ( current_symbol_name )
3965
40- # Below, I've written a general structure that gets class-info
41- # everytime, no matter the format in which it is present
66+ try :
67+ field_table = {} # should contain the field and it's type.
4268
43- # Inspect the class fields
44- # Assuming class_obj has fields stored in some standard way
45- # If it's a ctypes-like structure with _fields_
46- if hasattr (class_obj , "_fields_" ):
47- for field_name , field_type in class_obj ._fields_ :
48- field_table [field_name ] = field_type
69+ # Get the class object from the module
70+ class_obj = getattr (imported_module , current_symbol_name )
4971
50- # If it's using __annotations__
51- elif hasattr (class_obj , "__annotations__" ):
52- for field_name , field_type in class_obj .__annotations__ .items ():
53- field_table [field_name ] = field_type
72+ # Inspect the class fields
73+ if hasattr (class_obj , "_fields_" ):
74+ for field_name , field_type in class_obj ._fields_ :
75+ field_table [field_name ] = field_type
76+ elif hasattr (class_obj , "__annotations__" ):
77+ for field_name , field_type in class_obj .__annotations__ .items ():
78+ field_table [field_name ] = field_type
79+ else :
80+ raise TypeError ("Could not get required class and definition" )
5481
55- else :
56- raise TypeError ("Could not get required class and definition" )
82+ logger .debug (f"Extracted fields for { current_symbol_name } : { field_table } " )
5783
58- logger .debug (f"Extracted fields for { current_symbol_name } : { field_table } " )
59- if handler .has_node (current_symbol_name ):
60- logger .info ("Extraction pruned due to already available field" )
61- return True
62- else :
63- new_dep_node = DependencyNode (name = current_symbol_name )
64- handler .add_node (new_dep_node )
84+ # Create or get the node
85+ if handler .has_node (current_symbol_name ):
86+ new_dep_node = handler .get_node (current_symbol_name )
87+ else :
88+ new_dep_node = DependencyNode (name = current_symbol_name )
89+ handler .add_node (new_dep_node )
90+
91+ # Process each field
6592 for elem_name , elem_type in field_table .items ():
6693 module_name = getattr (elem_type , "__module__" , None )
94+
6795 if module_name == ctypes .__name__ :
96+ # Simple ctypes - mark as ready immediately
6897 new_dep_node .add_field (elem_name , elem_type , ready = True )
98+
6999 elif module_name == "vmlinux" :
100+ # Complex vmlinux type - needs recursive processing
70101 new_dep_node .add_field (elem_name , elem_type , ready = False )
71- print ( "elem_name:" , elem_name , "elem_type:" , elem_type )
72- # currently fails when a non-normal type appears which is basically everytime
102+ logger . debug ( f"Processing vmlinux field: { elem_name } , type: { elem_type } " )
103+
73104 identify_ctypes_type (elem_name , elem_type , new_dep_node )
105+
106+ # Determine the actual symbol to process
74107 symbol_name = (
75108 elem_type .__name__
76109 if hasattr (elem_type , "__name__" )
77110 else str (elem_type )
78111 )
79112 vmlinux_symbol = None
113+
114+ # Handle pointers/arrays to other types
80115 if hasattr (elem_type , "_type_" ):
81116 containing_module_name = getattr (
82117 (elem_type ._type_ ), "__module__" , None
83118 )
84119 if containing_module_name == ctypes .__name__ :
120+ # Pointer/Array to ctypes - mark as ready
85121 new_dep_node .set_field_ready (elem_name , True )
86122 continue
87123 elif containing_module_name == "vmlinux" :
124+ # Pointer/Array to vmlinux type
88125 symbol_name = (
89126 (elem_type ._type_ ).__name__
90127 if hasattr ((elem_type ._type_ ), "__name__" )
91128 else str (elem_type ._type_ )
92129 )
130+
131+ # Self-referential check
132+ if symbol_name == current_symbol_name :
133+ logger .debug (f"Self-referential field { elem_name } in { current_symbol_name } " )
134+ # For pointers to self, we can mark as ready since the type is being defined
135+ new_dep_node .set_field_ready (elem_name , True )
136+ continue
137+
93138 vmlinux_symbol = getattr (imported_module , symbol_name )
94139 else :
140+ # Direct vmlinux type (not pointer/array)
95141 vmlinux_symbol = getattr (imported_module , symbol_name )
96- if process_vmlinux_class (vmlinux_symbol , llvm_module , handler ):
97- new_dep_node .set_field_ready (elem_name , True )
142+
143+ # Recursively process the dependency
144+ if vmlinux_symbol is not None :
145+ if process_vmlinux_class (vmlinux_symbol , llvm_module , handler , processing_stack ):
146+ new_dep_node .set_field_ready (elem_name , True )
98147 else :
99148 raise ValueError (
100149 f"{ elem_name } with type { elem_type } not supported in recursive resolver"
101150 )
102- logger .info (f"added node: { current_symbol_name } " )
103151
104- return True
152+ logger .info (f"Successfully processed node: { current_symbol_name } " )
153+ return True
154+
155+ finally :
156+ # Remove from processing stack when done
157+ processing_stack .discard (current_symbol_name )
105158
106159
107160def identify_ctypes_type (elem_name , elem_type , new_dep_node : DependencyNode ):
0 commit comments