@@ -12,15 +12,185 @@ class TestInteractiveScriptedProcess(TestBase):
12
12
13
13
NO_DEBUG_INFO_TESTCASE = True
14
14
15
- def test_passthrough_launch (self ):
16
- """Test a simple pass-through process launch"""
15
+ def setUp (self ):
16
+ # Call super's setUp().
17
+ TestBase .setUp (self )
18
+ # Build and load test program
17
19
self .build ()
18
20
self .runCmd ("file " + self .getBuildArtifact ("a.out" ), CURRENT_EXECUTABLE_SET )
19
21
self .main_source_file = lldb .SBFileSpec ("main.cpp" )
20
22
self .script_module = "interactive_scripted_process"
21
23
self .script_file = self .script_module + ".py"
24
+
25
+ def test_passthrough_launch (self ):
26
+ """Test a simple pass-through process launch"""
22
27
self .passthrough_launch ()
23
28
29
+ lldbutil .run_break_set_by_source_regexp (self , "also break here" )
30
+ self .assertEqual (self .mux_target .GetNumBreakpoints (), 2 )
31
+ error = self .mux_process .Continue ()
32
+ self .assertSuccess (error , "Resuming multiplexer scripted process" )
33
+ self .assertTrue (self .mux_process .IsValid (), "Got a valid process" )
34
+
35
+ event = lldbutil .fetch_next_event (
36
+ self , self .mux_process_listener , self .mux_process .GetBroadcaster ()
37
+ )
38
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
39
+ event = lldbutil .fetch_next_event (
40
+ self , self .mux_process_listener , self .mux_process .GetBroadcaster ()
41
+ )
42
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
43
+
44
+ def test_multiplexed_launch (self ):
45
+ """Test a multiple interactive scripted process debugging"""
46
+ self .passthrough_launch ()
47
+ self .assertEqual (self .dbg .GetNumTargets (), 2 )
48
+
49
+ driving_target = self .mux_process .GetScriptedImplementation ().driving_target
50
+ self .assertTrue (driving_target .IsValid (), "Driving target is invalid" )
51
+
52
+ # Create a target for the multiplexed even scripted process
53
+ even_target = self .duplicate_target (driving_target )
54
+ self .assertTrue (
55
+ even_target .IsValid (),
56
+ "Couldn't duplicate driving target to launch multiplexed even scripted process" ,
57
+ )
58
+
59
+ class_name = f"{ self .script_module } .MultiplexedScriptedProcess"
60
+ dictionary = {"driving_target_idx" : self .dbg .GetIndexOfTarget (self .mux_target )}
61
+
62
+ dictionary ["parity" ] = 0
63
+ muxed_launch_info = self .get_launch_info (class_name , dictionary )
64
+
65
+ # Launch Even Child Scripted Process
66
+ error = lldb .SBError ()
67
+ even_process = even_target .Launch (muxed_launch_info , error )
68
+ self .assertTrue (
69
+ even_process , "Couldn't launch multiplexed even scripted process"
70
+ )
71
+ self .multiplex (even_process )
72
+
73
+ # Check that the even process started running
74
+ event = lldbutil .fetch_next_event (
75
+ self , self .dbg .GetListener (), even_process .GetBroadcaster ()
76
+ )
77
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
78
+ # Check that the even process stopped
79
+ event = lldbutil .fetch_next_event (
80
+ self , self .dbg .GetListener (), even_process .GetBroadcaster ()
81
+ )
82
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
83
+
84
+ self .assertTrue (even_process .IsValid (), "Got a valid process" )
85
+ self .assertState (
86
+ even_process .GetState (), lldb .eStateStopped , "Process is stopped"
87
+ )
88
+
89
+ # Create a target for the multiplexed odd scripted process
90
+ odd_target = self .duplicate_target (driving_target )
91
+ self .assertTrue (
92
+ odd_target .IsValid (),
93
+ "Couldn't duplicate driving target to launch multiplexed odd scripted process" ,
94
+ )
95
+
96
+ dictionary ["parity" ] = 1
97
+ muxed_launch_info = self .get_launch_info (class_name , dictionary )
98
+
99
+ # Launch Odd Child Scripted Process
100
+ error = lldb .SBError ()
101
+ odd_process = odd_target .Launch (muxed_launch_info , error )
102
+ self .assertTrue (odd_process , "Couldn't launch multiplexed odd scripted process" )
103
+ self .multiplex (odd_process )
104
+
105
+ # Check that the odd process started running
106
+ event = lldbutil .fetch_next_event (
107
+ self , self .dbg .GetListener (), odd_process .GetBroadcaster ()
108
+ )
109
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
110
+ # Check that the odd process stopped
111
+ event = lldbutil .fetch_next_event (
112
+ self , self .dbg .GetListener (), odd_process .GetBroadcaster ()
113
+ )
114
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
115
+
116
+ self .assertTrue (odd_process .IsValid (), "Got a valid process" )
117
+ self .assertState (
118
+ odd_process .GetState (), lldb .eStateStopped , "Process is stopped"
119
+ )
120
+
121
+ # Set a breakpoint on the odd child process
122
+ bkpt = odd_target .BreakpointCreateBySourceRegex (
123
+ "also break here" , self .main_source_file
124
+ )
125
+ self .assertEqual (odd_target .GetNumBreakpoints (), 1 )
126
+ self .assertTrue (bkpt , "Second breakpoint set on child scripted process" )
127
+ self .assertEqual (bkpt .GetNumLocations (), 1 , "Second breakpoint has 1 location" )
128
+
129
+ # Verify that the breakpoint was also set on the multiplexer & real target
130
+ self .assertEqual (self .mux_target .GetNumBreakpoints (), 2 )
131
+ bkpt = self .mux_target .GetBreakpointAtIndex (1 )
132
+ self .assertEqual (
133
+ bkpt .GetNumLocations (), 1 , "Second breakpoint set on mux scripted process"
134
+ )
135
+ self .assertTrue (bkpt .MatchesName ("multiplexed_scripted_process_421" ))
136
+
137
+ self .assertGreater (driving_target .GetNumBreakpoints (), 1 )
138
+
139
+ # Resume execution on child process
140
+ error = odd_process .Continue ()
141
+ self .assertSuccess (error , "Resuming odd child scripted process" )
142
+ self .assertTrue (odd_process .IsValid (), "Got a valid process" )
143
+
144
+ # Since all the execution is asynchronous, the order in which events
145
+ # arrive is non-deterministic, so we need a data structure to make sure
146
+ # we received both the running and stopped event for each target.
147
+
148
+ # Initialize the execution event "bingo book", that maps a process index
149
+ # to a dictionary that contains flags that are not set for the process
150
+ # events that we care about (running & stopped)
151
+
152
+ execution_events = {
153
+ 1 : {lldb .eStateRunning : False , lldb .eStateStopped : False },
154
+ 2 : {lldb .eStateRunning : False , lldb .eStateStopped : False },
155
+ 3 : {lldb .eStateRunning : False , lldb .eStateStopped : False },
156
+ }
157
+
158
+ def fetch_process_event (self , execution_events ):
159
+ event = lldbutil .fetch_next_event (
160
+ self ,
161
+ self .dbg .GetListener (),
162
+ lldb .SBProcess .GetBroadcasterClass (),
163
+ match_class = True ,
164
+ )
165
+ state = lldb .SBProcess .GetStateFromEvent (event )
166
+ self .assertIn (state , [lldb .eStateRunning , lldb .eStateStopped ])
167
+ event_process = lldb .SBProcess .GetProcessFromEvent (event )
168
+ self .assertTrue (event_process .IsValid ())
169
+ event_target = event_process .GetTarget ()
170
+ event_target_idx = self .dbg .GetIndexOfTarget (event_target )
171
+ self .assertFalse (
172
+ execution_events [event_target_idx ][state ],
173
+ "Event already received for this process" ,
174
+ )
175
+ execution_events [event_target_idx ][state ] = True
176
+
177
+ event = lldbutil .fetch_next_event (
178
+ self , self .mux_process_listener , self .mux_process .GetBroadcaster ()
179
+ )
180
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
181
+
182
+ event = lldbutil .fetch_next_event (
183
+ self , self .mux_process_listener , self .mux_process .GetBroadcaster ()
184
+ )
185
+ self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
186
+
187
+ for _ in range ((self .dbg .GetNumTargets () - 1 ) * 2 ):
188
+ fetch_process_event (self , execution_events )
189
+
190
+ for target_index , event_states in execution_events .items ():
191
+ for state , is_set in event_states .items ():
192
+ self .assertTrue (is_set , f"Target { target_index } has state { state } set" )
193
+
24
194
def duplicate_target (self , driving_target ):
25
195
exe = driving_target .executable .fullpath
26
196
triple = driving_target .triple
@@ -36,6 +206,14 @@ def get_launch_info(self, class_name, script_dict):
36
206
launch_info .SetScriptedProcessDictionary (structured_data )
37
207
return launch_info
38
208
209
+ def multiplex (self , muxed_process ):
210
+ muxed_process .GetScriptedImplementation ().multiplexer = (
211
+ self .mux_process .GetScriptedImplementation ()
212
+ )
213
+ self .mux_process .GetScriptedImplementation ().multiplexed_processes [
214
+ muxed_process .GetProcessID ()
215
+ ] = muxed_process
216
+
39
217
def passthrough_launch (self ):
40
218
"""Test that a simple passthrough wrapper functions correctly"""
41
219
# First build the real target:
@@ -49,42 +227,42 @@ def passthrough_launch(self):
49
227
script_path = os .path .join (self .getSourceDir (), self .script_file )
50
228
self .runCmd (f"command script import '{ script_path } '" )
51
229
52
- mux_target = self .duplicate_target (real_target )
53
- self .assertTrue (mux_target .IsValid (), "duplicate target succeeded" )
230
+ self . mux_target = self .duplicate_target (real_target )
231
+ self .assertTrue (self . mux_target .IsValid (), "duplicate target succeeded" )
54
232
55
233
mux_class = f"{ self .script_module } .MultiplexerScriptedProcess"
56
234
script_dict = {"driving_target_idx" : real_target_id }
57
235
mux_launch_info = self .get_launch_info (mux_class , script_dict )
58
- mux_process_listener = lldb .SBListener (
236
+ self . mux_process_listener = lldb .SBListener (
59
237
"lldb.test.interactive-scripted-process.listener"
60
238
)
61
- mux_launch_info .SetPassthroughListener ( mux_process_listener )
239
+ mux_launch_info .SetShadowListener ( self . mux_process_listener )
62
240
63
241
self .dbg .SetAsync (True )
64
242
error = lldb .SBError ()
65
- mux_process = mux_target .Launch (mux_launch_info , error )
243
+ self . mux_process = self . mux_target .Launch (mux_launch_info , error )
66
244
self .assertSuccess (error , "Launched multiplexer scripted process" )
67
- self .assertTrue (mux_process .IsValid (), "Got a valid process" )
245
+ self .assertTrue (self . mux_process .IsValid (), "Got a valid process" )
68
246
69
247
# Check that the mux process started running
70
248
event = lldbutil .fetch_next_event (
71
- self , mux_process_listener , mux_process .GetBroadcaster (), timeout = 60 * 5
249
+ self , self . mux_process_listener , self . mux_process .GetBroadcaster ()
72
250
)
73
251
self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
74
252
# Check that the real process started running
75
253
event = lldbutil .fetch_next_event (
76
- self , self .dbg .GetListener (), mux_process .GetBroadcaster ()
254
+ self , self .dbg .GetListener (), self . mux_process .GetBroadcaster ()
77
255
)
78
256
self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
79
257
80
258
# Check that the real process stopped
81
259
event = lldbutil .fetch_next_event (
82
- self , self .dbg .GetListener (), mux_process .GetBroadcaster (), timeout = 60 * 5
260
+ self , self .dbg .GetListener (), self . mux_process .GetBroadcaster ()
83
261
)
84
262
self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
85
263
# Check that the mux process stopped
86
264
event = lldbutil .fetch_next_event (
87
- self , mux_process_listener , mux_process .GetBroadcaster (), timeout = 60 * 5
265
+ self , self . mux_process_listener , self . mux_process .GetBroadcaster ()
88
266
)
89
267
self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
90
268
@@ -98,25 +276,10 @@ def passthrough_launch(self):
98
276
# Check that we got the right threads:
99
277
self .assertEqual (
100
278
len (real_process .threads ),
101
- len (mux_process .threads ),
279
+ len (self . mux_process .threads ),
102
280
"Same number of threads" ,
103
281
)
104
282
for id in range (len (real_process .threads )):
105
283
real_pc = real_process .threads [id ].frame [0 ].pc
106
- mux_pc = mux_process .threads [id ].frame [0 ].pc
284
+ mux_pc = self . mux_process .threads [id ].frame [0 ].pc
107
285
self .assertEqual (real_pc , mux_pc , f"PC's equal for { id } " )
108
-
109
- lldbutil .run_break_set_by_source_regexp (self , "also break here" )
110
- self .assertEqual (mux_target .GetNumBreakpoints (), 2 )
111
- error = mux_process .Continue ()
112
- self .assertSuccess (error , "Resuming multiplexer scripted process" )
113
- self .assertTrue (mux_process .IsValid (), "Got a valid process" )
114
-
115
- event = lldbutil .fetch_next_event (
116
- self , mux_process_listener , mux_process .GetBroadcaster ()
117
- )
118
- self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateRunning )
119
- event = lldbutil .fetch_next_event (
120
- self , mux_process_listener , mux_process .GetBroadcaster ()
121
- )
122
- self .assertState (lldb .SBProcess .GetStateFromEvent (event ), lldb .eStateStopped )
0 commit comments