Skip to content

Commit fa0eaec

Browse files
[lldb comparator] ability to execute in parallel (#36)
`LLDBDebugger` handles only 1 lldb instance (similar to `IDDGdbController`) `LLDBParallelDebugger` handles 2 instance of `LLDBDebugger` and is responsible for parallel execution
1 parent f5c2cd5 commit fa0eaec

File tree

4 files changed

+145
-199
lines changed

4 files changed

+145
-199
lines changed

debuggers/gdb/idd_gdb_controller.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import subprocess
33

4+
from driver import IDDParallelTerminate
45
from pygdbmi.gdbcontroller import GdbController
56
from pygdbmi.IoManager import IoManager
67
from pygdbmi.constants import (
@@ -55,9 +56,6 @@ def spawn_new_gdb_subprocess(self) -> int:
5556
return self.gdb_process.pid
5657

5758

58-
class IDDParallelTerminate:
59-
pass
60-
6159

6260
class IDDParallelGdbController:
6361
def __init__(self, *args, **kwargs):

debuggers/lldb/lldb_driver.py

Lines changed: 135 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -1,227 +1,168 @@
11
import os
22
import lldb
33

4-
from driver import Driver
4+
from driver import Driver, IDDParallelTerminate
55
from debuggers.lldb.lldb_extensions import *
6+
from multiprocessing import Process, Pipe
67

7-
base_response = None
8-
regressed_response = None
98

10-
class LLDBDebugger(Driver):
11-
is_initted = False
9+
processes = []
1210

13-
base_lldb_instance = None
14-
regression_lldb_instance = None
1511

16-
base_command_interpreter = None
17-
regression_command_interpreter = None
12+
class LLDBGetState:
13+
pass
1814

19-
lldb_instances = None
15+
class LLDBDebugger:
16+
is_initted = False
2017

21-
def __init__(self, base_args, regression_args):
22-
self.base_lldb_instance = lldb.SBDebugger.Create()
23-
self.base_lldb_instance.SetAsync(False)
24-
self.base_lldb_instance.SetUseColor(False)
25-
26-
self.regression_lldb_instance = lldb.SBDebugger.Create()
27-
self.regression_lldb_instance.SetAsync(False)
28-
self.regression_lldb_instance.SetUseColor(False)
18+
lldb_instance = None
2919

30-
base_error = lldb.SBError()
31-
base_target = self.base_lldb_instance.CreateTarget(base_args, "x86_64", "host", True, base_error)
32-
if not base_error.Success():
33-
raise Exception(base_error.GetCString())
20+
command_interpreter = None
3421

35-
regression_error = lldb.SBError()
36-
regression_target = self.regression_lldb_instance.CreateTarget(regression_args, "x86_64", "host", True, regression_error)
37-
if not regression_error.Success():
38-
raise Exception(regression_error.GetCString())
22+
lldb_instances = None
3923

40-
self.base_command_interpreter = self.base_lldb_instance.GetCommandInterpreter()
41-
self.regression_command_interpreter = self.regression_lldb_instance.GetCommandInterpreter()
24+
def __init__(self, args):
25+
self.lldb_instance = lldb.SBDebugger.Create()
26+
self.lldb_instance.SetAsync(False)
27+
self.lldb_instance.SetUseColor(False)
28+
29+
error = lldb.SBError()
30+
target = self.lldb_instance.CreateTarget(args, "x86_64", "host", True, error)
31+
if not error.Success():
32+
raise Exception(error.GetCString())
4233

43-
base_launch_info = lldb.SBLaunchInfo(None)
44-
base_launch_info.SetExecutableFile (base_target.GetExecutable(), True)
34+
self.command_interpreter = self.lldb_instance.GetCommandInterpreter()
4535

46-
regression_launch_info = lldb.SBLaunchInfo(None)
47-
regression_launch_info.SetExecutableFile (regression_target.GetExecutable(), True)
36+
launch_info = lldb.SBLaunchInfo(None)
37+
launch_info.SetExecutableFile (target.GetExecutable(), True)
4838

4939
dirname = os.path.dirname(__file__)
50-
self.run_parallel_raw_command("command script import " + os.path.join(dirname, "lldb_commands.py"))
40+
self.run_single_command("command script import " + os.path.join(dirname, "lldb_commands.py"))
5141

5242
self.is_initted = True
5343

54-
def run_parallel_command(self, command):
55-
raw_base_response = self.run_single_command(command, "base")
56-
base_response = raw_base_response[0].split("\n")
57-
58-
raw_regression_response = self.run_single_command(command, "regressed")
59-
regression_response = raw_regression_response[0].split("\n")
60-
61-
return { "base": base_response, "regressed": regression_response }
62-
63-
def run_parallel_raw_command(self, command):
64-
base_response = self.run_single_command(command, "base")
65-
regression_response = self.run_single_command(command, "regressed")
66-
67-
return { "base": base_response, "regressed": regression_response }
68-
69-
70-
def run_single_command(self, command, version):
44+
def run_single_command(self, command):
7145
command_result = lldb.SBCommandReturnObject()
72-
if version == "base":
73-
self.base_command_interpreter.HandleCommand(command, command_result)
74-
elif version == "regressed":
75-
self.regression_command_interpreter.HandleCommand(command, command_result)
76-
46+
self.command_interpreter.HandleCommand(command, command_result)
47+
7748
if command_result.Succeeded():
78-
return [command_result.GetOutput()]
49+
return command_result.GetOutput()
7950
else:
80-
return [command_result.GetError()]
81-
82-
return ""
83-
84-
def get_state(self, version=None):
85-
result = {}
86-
base_state = {}
87-
regression_state = {}
88-
89-
result['stack_frames'] = self.get_current_stack_frames(version)
90-
result['locals'] = self.get_current_local_vars(None, version)
91-
result['args'] = self.get_current_args(version)
92-
result['instructions'] = self.get_current_instructions(version)
93-
result['registers'] = self.get_current_registers(version)
51+
return command_result.GetError()
52+
53+
def get_state(self):
54+
return {
55+
'stack_frames': self.get_current_stack_frames(),
56+
'locals': self.get_current_local_vars(None),
57+
'args': self.get_current_args(),
58+
'instructions': self.get_current_instructions(),
59+
'registers': self.get_current_registers(),
60+
}
61+
62+
def get_current_stack_frames(self):
63+
target = self.lldb_instance.GetTargetAtIndex(0)
64+
stack_frame = get_current_stack_frame_from_target(target)
65+
return stack_frame
66+
67+
def get_current_args(self):
68+
target = self.lldb_instance.GetTargetAtIndex(0)
69+
args = get_args_as_list(target)
70+
return args
71+
72+
def get_current_local_vars(self, filters):
73+
target = self.lldb_instance.GetTargetAtIndex(0)
74+
target_locals = get_local_vars_as_list(target)
75+
if filters == 'ignore-order-declaration':
76+
target_locals.sort()
77+
return target_locals
78+
79+
def get_current_instructions(self):
80+
target = self.lldb_instance.GetTargetAtIndex(0)
81+
args = get_instructions_as_list(target)
82+
return args
83+
84+
def get_current_registers(self):
85+
target = self.lldb_instance.GetTargetAtIndex(0)
86+
args = get_registers_as_list(target)
87+
return args
88+
89+
def get_current_calls(self):
90+
target = self.lldb_instance.GetTargetAtIndex(0)
91+
calls = get_call_instructions(target)
92+
return calls
93+
94+
def terminate(self):
95+
pass
9496

95-
if version is not None:
96-
return result
97+
@staticmethod
98+
def run(lldb_args, pipe):
99+
lldb = LLDBDebugger(lldb_args)
100+
while True:
101+
args, kwargs = pipe.recv()
102+
if isinstance(args, IDDParallelTerminate) or isinstance(kwargs, IDDParallelTerminate):
103+
return
104+
if isinstance(args, LLDBGetState) or isinstance(kwargs, LLDBGetState):
105+
res = lldb.get_state()
106+
pipe.send(res)
107+
else:
108+
res = lldb.run_single_command(*args, **kwargs)
109+
pipe.send(res)
97110

98-
base_state['stack_frames'] = result['stack_frames']['base']
99-
regression_state['stack_frames'] = result['stack_frames']['regressed']
100111

101-
base_state['locals'] = result['locals']['base']
102-
regression_state['locals'] = result['locals']['regressed']
103112

104-
base_state['args'] = result['args']['base']
105-
regression_state['args'] = result['args']['regressed']
113+
class LLDBParallelDebugger(Driver):
114+
def __init__(self, base_args, regression_args):
115+
self.base_pipe = create_LLDBDebugger_for_parallel(base_args)
116+
self.regressed_pipe = create_LLDBDebugger_for_parallel(regression_args)
117+
118+
def get_state(self, target=None):
119+
if target == "base":
120+
self.base_pipe.send((LLDBGetState(), LLDBGetState()))
121+
return self.base_pipe.recv()
122+
if target == "regressed":
123+
self.regressed_pipe.send((LLDBGetState(), LLDBGetState()))
124+
return self.regressed_pipe.recv()
125+
126+
self.base_pipe.send((LLDBGetState(), LLDBGetState()))
127+
self.regressed_pipe.send((LLDBGetState(), LLDBGetState()))
128+
129+
return {
130+
"base": self.base_pipe.recv(),
131+
"regressed": self.regressed_pipe.recv(),
132+
}
133+
134+
def run_single_command(self, command, target):
135+
if target == "base":
136+
self.base_pipe.send(((command,), {}))
137+
return self.base_pipe.recv().split("\n")
138+
if target == "regressed":
139+
self.regressed_pipe.send(((command,), {}))
140+
return self.regressed_pipe.recv().split("\n")
106141

107-
base_state['instructions'] = result['instructions']['base']
108-
regression_state['instructions'] = result['instructions']['regressed']
142+
def run_parallel_command(self, command):
143+
self.base_pipe.send(((command,), {}))
144+
self.regressed_pipe.send(((command,), {}))
109145

110-
base_state['registers'] = result['registers']['base']
111-
regression_state['registers'] = result['registers']['regressed']
146+
return {
147+
"base": self.base_pipe.recv().split("\n"),
148+
"regressed": self.regressed_pipe.recv().split("\n"),
149+
}
150+
151+
def terminate(self):
152+
terminate_all_IDDGdbController()
112153

113-
return { "base" : base_state, "regressed" : regression_state }
114154

115-
def get_current_stack_frames(self, version=None):
116-
if version == "base":
117-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
118-
base_stack_frame = get_current_stack_frame_from_target(base_target)
119-
return base_stack_frame
120-
121-
if version == "regressed":
122-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
123-
regression_stack_frame = get_current_stack_frame_from_target(regression_target)
124-
return regression_stack_frame
125-
126-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
127-
base_stack_frame = get_current_stack_frame_from_target(base_target)
128-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
129-
regression_stack_frame = get_current_stack_frame_from_target(regression_target)
130-
131-
return { "base" : base_stack_frame, "regressed" : regression_stack_frame }
132-
133-
def get_current_args(self, version=None):
134-
if version == "base":
135-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
136-
base_args = get_args_as_list(base_target)
137-
return base_args
138-
139-
if version == "regressed":
140-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
141-
regression_args = get_args_as_list(regression_target)
142-
return regression_args
143-
144-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
145-
base_args = get_args_as_list(base_target)
146-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
147-
regression_args = get_args_as_list(regression_target)
148-
return { "base" : base_args, "regressed" : regression_args }
149-
150-
def get_current_local_vars(self, filters, version=None):
151-
if version == "base":
152-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
153-
base_locals = get_local_vars_as_list(base_target)
154-
if filters == 'ignore-order-declaration':
155-
base_locals.sort()
156-
return base_locals
157-
158-
if version == "regressed":
159-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
160-
regression_locals = get_local_vars_as_list(regression_target)
161-
if filters == 'ignore-order-declaration':
162-
regression_locals.sort()
163-
return regression_locals
164-
165-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
166-
base_locals = get_local_vars_as_list(base_target)
167-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
168-
regression_locals = get_local_vars_as_list(regression_target)
169-
if filters == 'ignore-order-declaration':
170-
base_locals.sort()
171-
regression_locals.sort()
155+
def terminate_all_IDDGdbController():
156+
for _, pipe in processes:
157+
pipe.send((IDDParallelTerminate(), IDDParallelTerminate()))
158+
for process, _ in processes:
159+
process.join()
172160

173-
return { "base" : base_locals, "regressed" : regression_locals }
161+
def create_LLDBDebugger_for_parallel(args):
162+
global processes
174163

175-
def get_current_instructions(self, version=None):
176-
if version == "base":
177-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
178-
base_args = get_instructions_as_list(base_target)
179-
return base_args
180-
181-
if version == "regressed":
182-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
183-
regression_args = get_instructions_as_list(regression_target)
184-
return regression_args
185-
186-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
187-
base_args = get_instructions_as_list(base_target)
188-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
189-
regression_args = get_instructions_as_list(regression_target)
190-
return { "base" : base_args, "regressed" : regression_args }
191-
192-
def get_current_registers(self, version=None):
193-
if version == "base":
194-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
195-
base_args = get_registers_as_list(base_target)
196-
return base_args
197-
198-
if version == "regressed":
199-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
200-
regression_args = get_registers_as_list(regression_target)
201-
return regression_args
202-
203-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
204-
base_args = get_registers_as_list(base_target)
205-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
206-
regression_args = get_registers_as_list(regression_target)
207-
return { "base" : base_args, "regressed" : regression_args }
208-
209-
def get_current_calls(self, version=None):
210-
if version == "base":
211-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
212-
base_calls = get_call_instructions(base_target)
213-
return base_calls
214-
215-
if version == "regressed":
216-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
217-
regression_calls = get_call_instructions(regression_target)
218-
return regression_calls
219-
220-
base_target = self.base_lldb_instance.GetTargetAtIndex(0)
221-
base_calls = get_call_instructions(base_target)
222-
regression_target = self.regression_lldb_instance.GetTargetAtIndex(0)
223-
regression_calls = get_call_instructions(regression_target)
224-
return { "base" : base_calls, "regressed" : regression_calls }
225-
226-
def terminate(self):
227-
pass
164+
parent_conn, child_conn = Pipe()
165+
process = Process(target=LLDBDebugger.run, args=(args, child_conn))
166+
processes.append((process, parent_conn))
167+
process.start()
168+
return parent_conn

driver.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from abc import ABCMeta, abstractmethod
33

44
class Driver(metaclass=abc.ABCMeta):
5+
@abstractmethod
6+
def get_state(self, target): raise NotImplementedError
7+
58
@abstractmethod
69
def run_single_command(self, command, target): raise NotImplementedError
710

@@ -10,3 +13,7 @@ def run_parallel_command(self, command): raise NotImplementedError
1013

1114
@abstractmethod
1215
def terminate(self): raise NotImplementedError
16+
17+
18+
class IDDParallelTerminate:
19+
pass

0 commit comments

Comments
 (0)