16cf66801SMed Ismail Bennani"""
26cf66801SMed Ismail BennaniTest the functionality of interactive scripted processes
36cf66801SMed Ismail Bennani"""
46cf66801SMed Ismail Bennani
56cf66801SMed Ismail Bennaniimport lldb
66cf66801SMed Ismail Bennaniimport lldbsuite.test.lldbutil as lldbutil
7f8d6542eSMed Ismail Bennanifrom lldbsuite.test.decorators import *
86cf66801SMed Ismail Bennanifrom lldbsuite.test.lldbtest import *
96cf66801SMed Ismail Bennaniimport json, os
106cf66801SMed Ismail Bennani
116cf66801SMed Ismail Bennani
126cf66801SMed Ismail Bennaniclass TestInteractiveScriptedProcess(TestBase):
136cf66801SMed Ismail Bennani    NO_DEBUG_INFO_TESTCASE = True
146cf66801SMed Ismail Bennani
15d3a6b931SMed Ismail Bennani    def setUp(self):
16d3a6b931SMed Ismail Bennani        # Call super's setUp().
17d3a6b931SMed Ismail Bennani        TestBase.setUp(self)
18d3a6b931SMed Ismail Bennani        # Build and load test program
196cf66801SMed Ismail Bennani        self.build()
206cf66801SMed Ismail Bennani        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
216cf66801SMed Ismail Bennani        self.main_source_file = lldb.SBFileSpec("main.cpp")
226cf66801SMed Ismail Bennani        self.script_module = "interactive_scripted_process"
236cf66801SMed Ismail Bennani        self.script_file = self.script_module + ".py"
24d3a6b931SMed Ismail Bennani
25*2e7aa2eeSJim Ingham    # These tests are flakey and sometimes timeout.  They work most of the time
26*2e7aa2eeSJim Ingham    # so the basic event flow is right, but somehow the handling is off.
27d0d902dfSMed Ismail Bennani    @skipUnlessDarwin
28c0d1128fSJonas Devlieghere    @skipIfDarwin
29d3a6b931SMed Ismail Bennani    def test_passthrough_launch(self):
30d3a6b931SMed Ismail Bennani        """Test a simple pass-through process launch"""
316cf66801SMed Ismail Bennani        self.passthrough_launch()
326cf66801SMed Ismail Bennani
33d3a6b931SMed Ismail Bennani        lldbutil.run_break_set_by_source_regexp(self, "also break here")
34d3a6b931SMed Ismail Bennani        self.assertEqual(self.mux_target.GetNumBreakpoints(), 2)
35d3a6b931SMed Ismail Bennani        error = self.mux_process.Continue()
36d3a6b931SMed Ismail Bennani        self.assertSuccess(error, "Resuming multiplexer scripted process")
37d3a6b931SMed Ismail Bennani        self.assertTrue(self.mux_process.IsValid(), "Got a valid process")
38d3a6b931SMed Ismail Bennani
39d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
40*2e7aa2eeSJim Ingham            self, self.dbg.GetListener(), self.mux_process.GetBroadcaster(), timeout=20
41*2e7aa2eeSJim Ingham        )
42*2e7aa2eeSJim Ingham        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
43*2e7aa2eeSJim Ingham        event = lldbutil.fetch_next_event(
44*2e7aa2eeSJim Ingham            self, self.dbg.GetListener(), self.mux_process.GetBroadcaster()
45*2e7aa2eeSJim Ingham        )
46*2e7aa2eeSJim Ingham        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
47*2e7aa2eeSJim Ingham
48*2e7aa2eeSJim Ingham        event = lldbutil.fetch_next_event(
49d3a6b931SMed Ismail Bennani            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
50d3a6b931SMed Ismail Bennani        )
51d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
52d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
53d3a6b931SMed Ismail Bennani            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
54d3a6b931SMed Ismail Bennani        )
55d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
56d3a6b931SMed Ismail Bennani
57d0d902dfSMed Ismail Bennani    @skipUnlessDarwin
58c0d1128fSJonas Devlieghere    @skipIfDarwin
59d3a6b931SMed Ismail Bennani    def test_multiplexed_launch(self):
60d3a6b931SMed Ismail Bennani        """Test a multiple interactive scripted process debugging"""
61d3a6b931SMed Ismail Bennani        self.passthrough_launch()
62d3a6b931SMed Ismail Bennani        self.assertEqual(self.dbg.GetNumTargets(), 2)
63d3a6b931SMed Ismail Bennani
64d3a6b931SMed Ismail Bennani        driving_target = self.mux_process.GetScriptedImplementation().driving_target
65d3a6b931SMed Ismail Bennani        self.assertTrue(driving_target.IsValid(), "Driving target is invalid")
66d3a6b931SMed Ismail Bennani
67d3a6b931SMed Ismail Bennani        # Create a target for the multiplexed even scripted process
68d3a6b931SMed Ismail Bennani        even_target = self.duplicate_target(driving_target)
69d3a6b931SMed Ismail Bennani        self.assertTrue(
70d3a6b931SMed Ismail Bennani            even_target.IsValid(),
71d3a6b931SMed Ismail Bennani            "Couldn't duplicate driving target to launch multiplexed even scripted process",
72d3a6b931SMed Ismail Bennani        )
73d3a6b931SMed Ismail Bennani
74d3a6b931SMed Ismail Bennani        class_name = f"{self.script_module}.MultiplexedScriptedProcess"
75d3a6b931SMed Ismail Bennani        dictionary = {"driving_target_idx": self.dbg.GetIndexOfTarget(self.mux_target)}
76d3a6b931SMed Ismail Bennani
77d3a6b931SMed Ismail Bennani        dictionary["parity"] = 0
78d3a6b931SMed Ismail Bennani        muxed_launch_info = self.get_launch_info(class_name, dictionary)
79d3a6b931SMed Ismail Bennani
80d3a6b931SMed Ismail Bennani        # Launch Even Child Scripted Process
81d3a6b931SMed Ismail Bennani        error = lldb.SBError()
82d3a6b931SMed Ismail Bennani        even_process = even_target.Launch(muxed_launch_info, error)
83d3a6b931SMed Ismail Bennani        self.assertTrue(
84d3a6b931SMed Ismail Bennani            even_process, "Couldn't launch multiplexed even scripted process"
85d3a6b931SMed Ismail Bennani        )
86d3a6b931SMed Ismail Bennani        self.multiplex(even_process)
87d3a6b931SMed Ismail Bennani
88d3a6b931SMed Ismail Bennani        # Check that the even process started running
89d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
90d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), even_process.GetBroadcaster()
91d3a6b931SMed Ismail Bennani        )
92d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
93d3a6b931SMed Ismail Bennani        # Check that the even process stopped
94d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
95d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), even_process.GetBroadcaster()
96d3a6b931SMed Ismail Bennani        )
97d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
98d3a6b931SMed Ismail Bennani
99d3a6b931SMed Ismail Bennani        self.assertTrue(even_process.IsValid(), "Got a valid process")
100d3a6b931SMed Ismail Bennani        self.assertState(
101d3a6b931SMed Ismail Bennani            even_process.GetState(), lldb.eStateStopped, "Process is stopped"
102d3a6b931SMed Ismail Bennani        )
103d3a6b931SMed Ismail Bennani
104d3a6b931SMed Ismail Bennani        # Create a target for the multiplexed odd scripted process
105d3a6b931SMed Ismail Bennani        odd_target = self.duplicate_target(driving_target)
106d3a6b931SMed Ismail Bennani        self.assertTrue(
107d3a6b931SMed Ismail Bennani            odd_target.IsValid(),
108d3a6b931SMed Ismail Bennani            "Couldn't duplicate driving target to launch multiplexed odd scripted process",
109d3a6b931SMed Ismail Bennani        )
110d3a6b931SMed Ismail Bennani
111d3a6b931SMed Ismail Bennani        dictionary["parity"] = 1
112d3a6b931SMed Ismail Bennani        muxed_launch_info = self.get_launch_info(class_name, dictionary)
113d3a6b931SMed Ismail Bennani
114d3a6b931SMed Ismail Bennani        # Launch Odd Child Scripted Process
115d3a6b931SMed Ismail Bennani        error = lldb.SBError()
116d3a6b931SMed Ismail Bennani        odd_process = odd_target.Launch(muxed_launch_info, error)
117d3a6b931SMed Ismail Bennani        self.assertTrue(odd_process, "Couldn't launch multiplexed odd scripted process")
118d3a6b931SMed Ismail Bennani        self.multiplex(odd_process)
119d3a6b931SMed Ismail Bennani
120d3a6b931SMed Ismail Bennani        # Check that the odd process started running
121d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
122d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), odd_process.GetBroadcaster()
123d3a6b931SMed Ismail Bennani        )
124d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
125d3a6b931SMed Ismail Bennani        # Check that the odd process stopped
126d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
127d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), odd_process.GetBroadcaster()
128d3a6b931SMed Ismail Bennani        )
129d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
130d3a6b931SMed Ismail Bennani
131d3a6b931SMed Ismail Bennani        self.assertTrue(odd_process.IsValid(), "Got a valid process")
132d3a6b931SMed Ismail Bennani        self.assertState(
133d3a6b931SMed Ismail Bennani            odd_process.GetState(), lldb.eStateStopped, "Process is stopped"
134d3a6b931SMed Ismail Bennani        )
135d3a6b931SMed Ismail Bennani
136d3a6b931SMed Ismail Bennani        # Set a breakpoint on the odd child process
137d3a6b931SMed Ismail Bennani        bkpt = odd_target.BreakpointCreateBySourceRegex(
138d3a6b931SMed Ismail Bennani            "also break here", self.main_source_file
139d3a6b931SMed Ismail Bennani        )
140d3a6b931SMed Ismail Bennani        self.assertEqual(odd_target.GetNumBreakpoints(), 1)
141d3a6b931SMed Ismail Bennani        self.assertTrue(bkpt, "Second breakpoint set on child scripted process")
142d3a6b931SMed Ismail Bennani        self.assertEqual(bkpt.GetNumLocations(), 1, "Second breakpoint has 1 location")
143d3a6b931SMed Ismail Bennani
144d3a6b931SMed Ismail Bennani        # Verify that the breakpoint was also set on the multiplexer & real target
145d3a6b931SMed Ismail Bennani        self.assertEqual(self.mux_target.GetNumBreakpoints(), 2)
146d3a6b931SMed Ismail Bennani        bkpt = self.mux_target.GetBreakpointAtIndex(1)
147d3a6b931SMed Ismail Bennani        self.assertEqual(
148d3a6b931SMed Ismail Bennani            bkpt.GetNumLocations(), 1, "Second breakpoint set on mux scripted process"
149d3a6b931SMed Ismail Bennani        )
150d3a6b931SMed Ismail Bennani        self.assertTrue(bkpt.MatchesName("multiplexed_scripted_process_421"))
151d3a6b931SMed Ismail Bennani
152d3a6b931SMed Ismail Bennani        self.assertGreater(driving_target.GetNumBreakpoints(), 1)
153d3a6b931SMed Ismail Bennani
154d3a6b931SMed Ismail Bennani        # Resume execution on child process
155d3a6b931SMed Ismail Bennani        error = odd_process.Continue()
156d3a6b931SMed Ismail Bennani        self.assertSuccess(error, "Resuming odd child scripted process")
157d3a6b931SMed Ismail Bennani        self.assertTrue(odd_process.IsValid(), "Got a valid process")
158d3a6b931SMed Ismail Bennani
159d3a6b931SMed Ismail Bennani        # Since all the execution is asynchronous, the order in which events
160d3a6b931SMed Ismail Bennani        # arrive is non-deterministic, so we need a data structure to make sure
161d3a6b931SMed Ismail Bennani        # we received both the running and stopped event for each target.
162d3a6b931SMed Ismail Bennani
163d3a6b931SMed Ismail Bennani        # Initialize the execution event "bingo book", that maps a process index
164d3a6b931SMed Ismail Bennani        # to a dictionary that contains flags that are not set for the process
165d3a6b931SMed Ismail Bennani        # events that we care about (running & stopped)
166d3a6b931SMed Ismail Bennani
167d3a6b931SMed Ismail Bennani        execution_events = {
168d3a6b931SMed Ismail Bennani            1: {lldb.eStateRunning: False, lldb.eStateStopped: False},
169d3a6b931SMed Ismail Bennani            2: {lldb.eStateRunning: False, lldb.eStateStopped: False},
170d3a6b931SMed Ismail Bennani            3: {lldb.eStateRunning: False, lldb.eStateStopped: False},
171d3a6b931SMed Ismail Bennani        }
172d3a6b931SMed Ismail Bennani
173d3a6b931SMed Ismail Bennani        def fetch_process_event(self, execution_events):
174d3a6b931SMed Ismail Bennani            event = lldbutil.fetch_next_event(
175d3a6b931SMed Ismail Bennani                self,
176d3a6b931SMed Ismail Bennani                self.dbg.GetListener(),
177d3a6b931SMed Ismail Bennani                lldb.SBProcess.GetBroadcasterClass(),
178d3a6b931SMed Ismail Bennani                match_class=True,
179d3a6b931SMed Ismail Bennani            )
180d3a6b931SMed Ismail Bennani            state = lldb.SBProcess.GetStateFromEvent(event)
181d3a6b931SMed Ismail Bennani            self.assertIn(state, [lldb.eStateRunning, lldb.eStateStopped])
182d3a6b931SMed Ismail Bennani            event_process = lldb.SBProcess.GetProcessFromEvent(event)
183d3a6b931SMed Ismail Bennani            self.assertTrue(event_process.IsValid())
184d3a6b931SMed Ismail Bennani            event_target = event_process.GetTarget()
185d3a6b931SMed Ismail Bennani            event_target_idx = self.dbg.GetIndexOfTarget(event_target)
186d3a6b931SMed Ismail Bennani            self.assertFalse(
187d3a6b931SMed Ismail Bennani                execution_events[event_target_idx][state],
188d3a6b931SMed Ismail Bennani                "Event already received for this process",
189d3a6b931SMed Ismail Bennani            )
190d3a6b931SMed Ismail Bennani            execution_events[event_target_idx][state] = True
191d3a6b931SMed Ismail Bennani
192*2e7aa2eeSJim Ingham        for _ in range((self.dbg.GetNumTargets() - 1) * 2):
193*2e7aa2eeSJim Ingham            fetch_process_event(self, execution_events)
194*2e7aa2eeSJim Ingham
195*2e7aa2eeSJim Ingham        for target_index, event_states in execution_events.items():
196*2e7aa2eeSJim Ingham            for state, is_set in event_states.items():
197*2e7aa2eeSJim Ingham                self.assertTrue(is_set, f"Target {target_index} has state {state} set")
198*2e7aa2eeSJim Ingham
199d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
200d3a6b931SMed Ismail Bennani            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
201d3a6b931SMed Ismail Bennani        )
202d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
203d3a6b931SMed Ismail Bennani
204d3a6b931SMed Ismail Bennani        event = lldbutil.fetch_next_event(
205d3a6b931SMed Ismail Bennani            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
206d3a6b931SMed Ismail Bennani        )
207d3a6b931SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
208d3a6b931SMed Ismail Bennani
2096cf66801SMed Ismail Bennani    def duplicate_target(self, driving_target):
2106cf66801SMed Ismail Bennani        exe = driving_target.executable.fullpath
2116cf66801SMed Ismail Bennani        triple = driving_target.triple
2126cf66801SMed Ismail Bennani        return self.dbg.CreateTargetWithFileAndTargetTriple(exe, triple)
2136cf66801SMed Ismail Bennani
2146cf66801SMed Ismail Bennani    def get_launch_info(self, class_name, script_dict):
2156cf66801SMed Ismail Bennani        structured_data = lldb.SBStructuredData()
2166cf66801SMed Ismail Bennani        structured_data.SetFromJSON(json.dumps(script_dict))
2176cf66801SMed Ismail Bennani
2186cf66801SMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
2196cf66801SMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
2206cf66801SMed Ismail Bennani        launch_info.SetScriptedProcessClassName(class_name)
2216cf66801SMed Ismail Bennani        launch_info.SetScriptedProcessDictionary(structured_data)
2226cf66801SMed Ismail Bennani        return launch_info
2236cf66801SMed Ismail Bennani
224d3a6b931SMed Ismail Bennani    def multiplex(self, muxed_process):
225d3a6b931SMed Ismail Bennani        muxed_process.GetScriptedImplementation().multiplexer = (
226d3a6b931SMed Ismail Bennani            self.mux_process.GetScriptedImplementation()
227d3a6b931SMed Ismail Bennani        )
228d3a6b931SMed Ismail Bennani        self.mux_process.GetScriptedImplementation().multiplexed_processes[
229d3a6b931SMed Ismail Bennani            muxed_process.GetProcessID()
230d3a6b931SMed Ismail Bennani        ] = muxed_process
231d3a6b931SMed Ismail Bennani
2326cf66801SMed Ismail Bennani    def passthrough_launch(self):
2336cf66801SMed Ismail Bennani        """Test that a simple passthrough wrapper functions correctly"""
2346cf66801SMed Ismail Bennani        # First build the real target:
2356cf66801SMed Ismail Bennani        self.assertEqual(self.dbg.GetNumTargets(), 1)
2366cf66801SMed Ismail Bennani        real_target_id = 0
2376cf66801SMed Ismail Bennani        real_target = self.dbg.GetTargetAtIndex(real_target_id)
2386cf66801SMed Ismail Bennani        lldbutil.run_break_set_by_source_regexp(self, "Break here")
2396cf66801SMed Ismail Bennani        self.assertEqual(real_target.GetNumBreakpoints(), 1)
2406cf66801SMed Ismail Bennani
2416cf66801SMed Ismail Bennani        # Now source in the scripted module:
2426cf66801SMed Ismail Bennani        script_path = os.path.join(self.getSourceDir(), self.script_file)
2436cf66801SMed Ismail Bennani        self.runCmd(f"command script import '{script_path}'")
2446cf66801SMed Ismail Bennani
245d3a6b931SMed Ismail Bennani        self.mux_target = self.duplicate_target(real_target)
246d3a6b931SMed Ismail Bennani        self.assertTrue(self.mux_target.IsValid(), "duplicate target succeeded")
2476cf66801SMed Ismail Bennani
2486cf66801SMed Ismail Bennani        mux_class = f"{self.script_module}.MultiplexerScriptedProcess"
2496cf66801SMed Ismail Bennani        script_dict = {"driving_target_idx": real_target_id}
2506cf66801SMed Ismail Bennani        mux_launch_info = self.get_launch_info(mux_class, script_dict)
251d3a6b931SMed Ismail Bennani        self.mux_process_listener = lldb.SBListener(
2526cf66801SMed Ismail Bennani            "lldb.test.interactive-scripted-process.listener"
2536cf66801SMed Ismail Bennani        )
254d3a6b931SMed Ismail Bennani        mux_launch_info.SetShadowListener(self.mux_process_listener)
2556cf66801SMed Ismail Bennani
2566cf66801SMed Ismail Bennani        self.dbg.SetAsync(True)
2576cf66801SMed Ismail Bennani        error = lldb.SBError()
258d3a6b931SMed Ismail Bennani        self.mux_process = self.mux_target.Launch(mux_launch_info, error)
2596cf66801SMed Ismail Bennani        self.assertSuccess(error, "Launched multiplexer scripted process")
260d3a6b931SMed Ismail Bennani        self.assertTrue(self.mux_process.IsValid(), "Got a valid process")
2616cf66801SMed Ismail Bennani
2626cf66801SMed Ismail Bennani        # Check that the real process started running
2636cf66801SMed Ismail Bennani        event = lldbutil.fetch_next_event(
264d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), self.mux_process.GetBroadcaster()
2656cf66801SMed Ismail Bennani        )
2666cf66801SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
267*2e7aa2eeSJim Ingham        # Check that the mux process started running
268*2e7aa2eeSJim Ingham        event = lldbutil.fetch_next_event(
269*2e7aa2eeSJim Ingham            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
270*2e7aa2eeSJim Ingham        )
271*2e7aa2eeSJim Ingham        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning)
2726cf66801SMed Ismail Bennani
2736cf66801SMed Ismail Bennani        # Check that the real process stopped
2746cf66801SMed Ismail Bennani        event = lldbutil.fetch_next_event(
275d3a6b931SMed Ismail Bennani            self, self.dbg.GetListener(), self.mux_process.GetBroadcaster()
2766cf66801SMed Ismail Bennani        )
2776cf66801SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
2786cf66801SMed Ismail Bennani        # Check that the mux process stopped
2796cf66801SMed Ismail Bennani        event = lldbutil.fetch_next_event(
280d3a6b931SMed Ismail Bennani            self, self.mux_process_listener, self.mux_process.GetBroadcaster()
2816cf66801SMed Ismail Bennani        )
2826cf66801SMed Ismail Bennani        self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
2836cf66801SMed Ismail Bennani
2846cf66801SMed Ismail Bennani        real_process = real_target.GetProcess()
2856cf66801SMed Ismail Bennani        self.assertTrue(real_process.IsValid(), "Got a valid process")
2866cf66801SMed Ismail Bennani        self.assertState(
2876cf66801SMed Ismail Bennani            real_process.GetState(), lldb.eStateStopped, "Process is stopped"
2886cf66801SMed Ismail Bennani        )
2896cf66801SMed Ismail Bennani
2906cf66801SMed Ismail Bennani        # This is a passthrough, so the two processes should have the same state:
2916cf66801SMed Ismail Bennani        # Check that we got the right threads:
2926cf66801SMed Ismail Bennani        self.assertEqual(
2936cf66801SMed Ismail Bennani            len(real_process.threads),
294d3a6b931SMed Ismail Bennani            len(self.mux_process.threads),
2956cf66801SMed Ismail Bennani            "Same number of threads",
2966cf66801SMed Ismail Bennani        )
2976cf66801SMed Ismail Bennani        for id in range(len(real_process.threads)):
2986cf66801SMed Ismail Bennani            real_pc = real_process.threads[id].frame[0].pc
299d3a6b931SMed Ismail Bennani            mux_pc = self.mux_process.threads[id].frame[0].pc
3006cf66801SMed Ismail Bennani            self.assertEqual(real_pc, mux_pc, f"PC's equal for {id}")
301