[debuginfo-tests] 9cf9710 - [Dexter][NFC] Add Debugger Controller To Dexter
Tom Weaver via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 20 07:47:35 PDT 2020
Author: Tom Weaver
Date: 2020-04-20T15:46:55+01:00
New Revision: 9cf9710bb0d61cb5c27c6e780af6a182cb162bfb
URL: https://github.com/llvm/llvm-project/commit/9cf9710bb0d61cb5c27c6e780af6a182cb162bfb
DIFF: https://github.com/llvm/llvm-project/commit/9cf9710bb0d61cb5c27c6e780af6a182cb162bfb.diff
LOG: [Dexter][NFC] Add Debugger Controller To Dexter
Add DebuggerControllerBase and DefaultController to Dexter
implements a new architecture that supports new and novel ways of running
a debugger under dexter.
Current implementation adds the original default behaviour via the new
architecture via the DefaultController, this should have NFC.
Reviewers: Orlando
Differential Revision: https://reviews.llvm.org/D76926
Added:
debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py
debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DefaultController.py
Modified:
debuginfo-tests/dexter/dex/command/ParseCommand.py
debuginfo-tests/dexter/dex/command/__init__.py
debuginfo-tests/dexter/dex/command/commands/DexExpectStepOrder.py
debuginfo-tests/dexter/dex/command/commands/DexUnreachable.py
debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
debuginfo-tests/dexter/dex/debugger/Debuggers.py
debuginfo-tests/dexter/dex/debugger/__init__.py
debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py
debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py
debuginfo-tests/dexter/dex/tools/clang_opt_bisect/Tool.py
debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py
debuginfo-tests/dexter/dex/tools/test/Tool.py
Removed:
################################################################################
diff --git a/debuginfo-tests/dexter/dex/command/ParseCommand.py b/debuginfo-tests/dexter/dex/command/ParseCommand.py
index 3b9a2d5766bf..4cc9ae125920 100644
--- a/debuginfo-tests/dexter/dex/command/ParseCommand.py
+++ b/debuginfo-tests/dexter/dex/command/ParseCommand.py
@@ -13,7 +13,7 @@
import unittest
from copy import copy
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
from dex.utils.Exceptions import CommandParseError
@@ -26,7 +26,8 @@
from dex.command.commands.DexLabel import DexLabel
from dex.command.commands.DexUnreachable import DexUnreachable
from dex.command.commands.DexWatch import DexWatch
-
+from dex.utils import Timer
+from dex.utils.Exceptions import CommandParseError, DebuggerException
def _get_valid_commands():
"""Return all top level DExTer test commands.
@@ -262,9 +263,7 @@ def _find_all_commands_in_file(path, file_lines, valid_commands):
raise format_parse_err(msg, path, file_lines, err_point)
return dict(commands)
-
-
-def find_all_commands(source_files):
+def _find_all_commands(source_files):
commands = defaultdict(dict)
valid_commands = _get_valid_commands()
for source_file in source_files:
@@ -277,6 +276,21 @@ def find_all_commands(source_files):
return dict(commands)
+def get_command_infos(source_files):
+ with Timer('parsing commands'):
+ try:
+ commands = _find_all_commands(source_files)
+ command_infos = OrderedDict()
+ for command_type in commands:
+ for command in commands[command_type].values():
+ if command_type not in command_infos:
+ command_infos[command_type] = []
+ command_infos[command_type].append(command)
+ return OrderedDict(command_infos)
+ except CommandParseError as e:
+ msg = 'parser error: <d>{}({}):</> {}\n{}\n{}\n'.format(
+ e.filename, e.lineno, e.info, e.src, e.caret)
+ raise DebuggerException(msg)
class TestParseCommand(unittest.TestCase):
class MockCmd(CommandBase):
diff --git a/debuginfo-tests/dexter/dex/command/__init__.py b/debuginfo-tests/dexter/dex/command/__init__.py
index 70da546fe5ef..3b1c448f70dd 100644
--- a/debuginfo-tests/dexter/dex/command/__init__.py
+++ b/debuginfo-tests/dexter/dex/command/__init__.py
@@ -5,5 +5,5 @@
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-from dex.command.ParseCommand import find_all_commands
+from dex.command.ParseCommand import get_command_infos
from dex.command.StepValueInfo import StepValueInfo
diff --git a/debuginfo-tests/dexter/dex/command/commands/DexExpectStepOrder.py b/debuginfo-tests/dexter/dex/command/commands/DexExpectStepOrder.py
index 4342bc5e80b0..700dc5420431 100644
--- a/debuginfo-tests/dexter/dex/command/commands/DexExpectStepOrder.py
+++ b/debuginfo-tests/dexter/dex/command/commands/DexExpectStepOrder.py
@@ -6,6 +6,7 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from dex.command.CommandBase import CommandBase
+from dex.dextIR import LocIR
from dex.dextIR import ValueIR
class DexExpectStepOrder(CommandBase):
@@ -28,11 +29,9 @@ def __init__(self, *args):
def get_name():
return __class__.__name__
- def eval(self, debugger):
- step_info = debugger.get_step_info()
- loc = step_info.current_location
- return {'DexExpectStepOrder': ValueIR(expression=str(loc.lineno),
- value=str(debugger.step_index), type_name=None,
+ def eval(self, step_info):
+ return {'DexExpectStepOrder': ValueIR(expression=str(step_info.current_location.lineno),
+ value=str(step_info.step_index), type_name=None,
error_string=None,
could_evaluate=True,
is_optimized_away=True,
diff --git a/debuginfo-tests/dexter/dex/command/commands/DexUnreachable.py b/debuginfo-tests/dexter/dex/command/commands/DexUnreachable.py
index 188a5d8180de..152ce02a7be0 100644
--- a/debuginfo-tests/dexter/dex/command/commands/DexUnreachable.py
+++ b/debuginfo-tests/dexter/dex/command/commands/DexUnreachable.py
@@ -26,7 +26,7 @@ def __init(self):
def get_name():
return __class__.__name__
- def eval(self, debugger):
+ def eval(self, step_info):
# If we're ever called, at all, then we're evaluating a line that has
# been marked as unreachable. Which means a failure.
vir = ValueIR(expression="Unreachable",
diff --git a/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py b/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
index 57fcad0de42f..2261396b94b4 100644
--- a/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
+++ b/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
@@ -7,10 +7,7 @@
"""Base class for all debugger interface implementations."""
import abc
-from itertools import chain
-import os
import sys
-import time
import traceback
from dex.dextIR import DebuggerIR, ValueIR
@@ -20,14 +17,11 @@
class DebuggerBase(object, metaclass=abc.ABCMeta):
- def __init__(self, context, step_collection):
+ def __init__(self, context):
self.context = context
- self.steps = step_collection
self._interface = None
self.has_loaded = False
self._loading_error = NotYetLoadedDebuggerException()
- self.watches = set()
-
try:
self._interface = self._load_interface()
self.has_loaded = True
@@ -35,13 +29,10 @@ def __init__(self, context, step_collection):
except DebuggerException:
self._loading_error = sys.exc_info()
- self.step_index = 0
-
def __enter__(self):
try:
self._custom_init()
self.clear_breakpoints()
- self.add_breakpoints()
except DebuggerException:
self._loading_error = sys.exc_info()
return self
@@ -86,31 +77,6 @@ def loading_error_trace(self):
tb = ''.join(tb).splitlines(True)
return tb
- def add_breakpoints(self):
- for s in self.context.options.source_files:
- with open(s, 'r') as fp:
- num_lines = len(fp.readlines())
- for line in range(1, num_lines + 1):
- self.add_breakpoint(s, line)
-
- def _update_step_watches(self, step_info):
- loc = step_info.current_location
- watch_cmds = ['DexUnreachable', 'DexExpectStepOrder']
- towatch = chain.from_iterable(self.steps.commands[x]
- for x in watch_cmds
- if x in self.steps.commands)
- try:
- # Iterate over all watches of the types named in watch_cmds
- for watch in towatch:
- if (os.path.exists(loc.path)
- and os.path.samefile(watch.path, loc.path)
- and watch.lineno == loc.lineno):
- result = watch.eval(self)
- step_info.watches.update(result)
- break
- except KeyError:
- pass
-
def _sanitize_function_name(self, name): # pylint: disable=no-self-use
"""If the function name returned by the debugger needs any post-
processing to make it fit (for example, if it includes a byte offset),
@@ -118,48 +84,6 @@ def _sanitize_function_name(self, name): # pylint: disable=no-self-use
"""
return name
- def start(self):
- self.steps.clear_steps()
- self.launch()
-
- for command_obj in chain.from_iterable(self.steps.commands.values()):
- self.watches.update(command_obj.get_watches())
-
- max_steps = self.context.options.max_steps
- for _ in range(max_steps):
- while self.is_running:
- pass
-
- if self.is_finished:
- break
-
- self.step_index += 1
- step_info = self.get_step_info()
-
- if step_info.current_frame:
- self._update_step_watches(step_info)
- self.steps.new_step(self.context, step_info)
-
- if self.in_source_file(step_info):
- self.step()
- else:
- self.go()
-
- time.sleep(self.context.options.pause_between_steps)
- else:
- raise DebuggerException(
- 'maximum number of steps reached ({})'.format(max_steps))
-
- def in_source_file(self, step_info):
- if not step_info.current_frame:
- return False
- if not step_info.current_location.path:
- return False
- if not os.path.exists(step_info.current_location.path):
- return False
- return any(os.path.samefile(step_info.current_location.path, f) \
- for f in self.context.options.source_files)
-
@abc.abstractmethod
def _load_interface(self):
pass
@@ -209,7 +133,7 @@ def go(self) -> ReturnCode:
pass
@abc.abstractmethod
- def get_step_info(self):
+ def get_step_info(self, watches, step_index):
pass
@abc.abstractproperty
diff --git a/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py b/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py
new file mode 100644
index 000000000000..ff98baa2d0e2
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py
@@ -0,0 +1,27 @@
+# DExTer : Debugging Experience Tester
+# ~~~~~~ ~ ~~ ~ ~~
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+"""Default class for controlling debuggers."""
+
+import abc
+
+class DebuggerControllerBase(object, metaclass=abc.ABCMeta):
+ @abc.abstractclassmethod
+ def _run_debugger_custom(self):
+ """Specify your own implementation of run_debugger_custom in your own
+ controller.
+ """
+ pass
+
+ def run_debugger(self, debugger):
+ """Responsible for correctly launching and tearing down the debugger.
+ """
+ self.debugger = debugger
+ with self.debugger:
+ self._run_debugger_custom()
+ # We may need to pickle this debugger controller after running the
+ # debugger. Debuggers are not picklable objects, so set to None.
+ self.debugger = None
diff --git a/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DefaultController.py b/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DefaultController.py
new file mode 100644
index 000000000000..0077a19e601a
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DefaultController.py
@@ -0,0 +1,90 @@
+# DExTer : Debugging Experience Tester
+# ~~~~~~ ~ ~~ ~ ~~
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+"""Base class for controlling debuggers."""
+
+from itertools import chain
+import os
+import time
+
+from dex.debugger.DebuggerControllers.DebuggerControllerBase import DebuggerControllerBase
+from dex.utils.Exceptions import DebuggerException
+
+class DefaultController(DebuggerControllerBase):
+ def __init__(self, context, step_collection):
+ self.context = context
+ self.step_collection = step_collection
+ self.watches = set()
+ self.step_index = 0
+
+ def _update_step_watches(self, step_info):
+ watch_cmds = ['DexUnreachable', 'DexExpectStepOrder']
+ towatch = chain.from_iterable(self.step_collection.commands[x]
+ for x in watch_cmds
+ if x in self.step_collection.commands)
+ try:
+ # Iterate over all watches of the types named in watch_cmds
+ for watch in towatch:
+ loc = step_info.current_location
+ if (os.path.exists(loc.path)
+ and os.path.samefile(watch.path, loc.path)
+ and watch.lineno == loc.lineno):
+ result = watch.eval(step_info)
+ step_info.watches.update(result)
+ break
+ except KeyError:
+ pass
+
+ def _break_point_all_lines(self):
+ for s in self.context.options.source_files:
+ with open(s, 'r') as fp:
+ num_lines = len(fp.readlines())
+ for line in range(1, num_lines + 1):
+ self.debugger.add_breakpoint(s, line)
+
+ def _in_source_file(self, step_info):
+ if not step_info.current_frame:
+ return False
+ if not step_info.current_location.path:
+ return False
+ if not os.path.exists(step_info.current_location.path):
+ return False
+ return any(os.path.samefile(step_info.current_location.path, f) \
+ for f in self.context.options.source_files)
+
+ def _run_debugger_custom(self):
+ self.step_collection.debugger = self.debugger.debugger_info
+ self._break_point_all_lines()
+
+ self.debugger.launch()
+
+ for command_obj in chain.from_iterable(self.step_collection.commands.values()):
+ self.watches.update(command_obj.get_watches())
+
+ max_steps = self.context.options.max_steps
+ for _ in range(max_steps):
+ while self.debugger.is_running:
+ pass
+
+ if self.debugger.is_finished:
+ break
+
+ self.step_index += 1
+ step_info = self.debugger.get_step_info(self.watches, self.step_index)
+
+ if step_info.current_frame:
+ self._update_step_watches(step_info)
+ self.step_collection.new_step(self.context, step_info)
+
+ if self._in_source_file(step_info):
+ self.debugger.step()
+ else:
+ self.debugger.go()
+
+ time.sleep(self.context.options.pause_between_steps)
+ else:
+ raise DebuggerException(
+ 'maximum number of steps reached ({})'.format(max_steps))
diff --git a/debuginfo-tests/dexter/dex/debugger/Debuggers.py b/debuginfo-tests/dexter/dex/debugger/Debuggers.py
index bc9355a0381c..f69169f27980 100644
--- a/debuginfo-tests/dexter/dex/debugger/Debuggers.py
+++ b/debuginfo-tests/dexter/dex/debugger/Debuggers.py
@@ -13,13 +13,15 @@
import sys
from tempfile import NamedTemporaryFile
-from dex.command import find_all_commands
+from dex.command import get_command_infos
from dex.dextIR import DextIR
from dex.utils import get_root_directory, Timer
from dex.utils.Environment import is_native_windows
-from dex.utils.Exceptions import CommandParseError, DebuggerException
from dex.utils.Exceptions import ToolArgumentError
from dex.utils.Warning import warn
+from dex.utils.Exceptions import DebuggerException
+
+from dex.debugger.DebuggerControllers.DefaultController import DefaultController
from dex.debugger.dbgeng.dbgeng import DbgEng
from dex.debugger.lldb.LLDB import LLDB
@@ -133,55 +135,26 @@ def handle_debugger_tool_options(context, defaults): # noqa
_warn_meaningless_option(context, '--show-debugger')
-def _get_command_infos(context):
- commands = find_all_commands(context.options.source_files)
- command_infos = OrderedDict()
- for command_type in commands:
- for command in commands[command_type].values():
- if command_type not in command_infos:
- command_infos[command_type] = []
- command_infos[command_type].append(command)
- return OrderedDict(command_infos)
-
-
-def empty_debugger_steps(context):
- return DextIR(
- executable_path=context.options.executable,
- source_paths=context.options.source_files,
- dexter_version=context.version)
-
-
-def get_debugger_steps(context):
- step_collection = empty_debugger_steps(context)
-
- with Timer('parsing commands'):
- try:
- step_collection.commands = _get_command_infos(context)
- except CommandParseError as e:
- msg = 'parser error: <d>{}({}):</> {}\n{}\n{}\n'.format(
- e.filename, e.lineno, e.info, e.src, e.caret)
- raise DebuggerException(msg)
-
- with NamedTemporaryFile(
- dir=context.working_directory.path, delete=False) as fp:
- pickle.dump(step_collection, fp, protocol=pickle.HIGHEST_PROTOCOL)
- steps_path = fp.name
-
+def run_debugger_subprocess(debugger_controller, working_dir_path):
with NamedTemporaryFile(
- dir=context.working_directory.path, delete=False, mode='wb') as fp:
- pickle.dump(context.options, fp, protocol=pickle.HIGHEST_PROTOCOL)
- options_path = fp.name
+ dir=working_dir_path, delete=False, mode='wb') as fp:
+ pickle.dump(debugger_controller, fp, protocol=pickle.HIGHEST_PROTOCOL)
+ controller_path = fp.name
dexter_py = os.path.basename(sys.argv[0])
if not os.path.isfile(dexter_py):
dexter_py = os.path.join(get_root_directory(), '..', dexter_py)
assert os.path.isfile(dexter_py)
- with NamedTemporaryFile(dir=context.working_directory.path) as fp:
+ with NamedTemporaryFile(dir=working_dir_path) as fp:
args = [
- sys.executable, dexter_py, 'run-debugger-internal-', steps_path,
- options_path, '--working-directory', context.working_directory.path,
- '--unittest=off', '--indent-timer-level={}'.format(Timer.indent + 2)
+ sys.executable,
+ dexter_py,
+ 'run-debugger-internal-',
+ controller_path,
+ '--working-directory={}'.format(working_dir_path),
+ '--unittest=off',
+ '--indent-timer-level={}'.format(Timer.indent + 2)
]
try:
with Timer('running external debugger process'):
@@ -189,10 +162,10 @@ def get_debugger_steps(context):
except subprocess.CalledProcessError as e:
raise DebuggerException(e)
- with open(steps_path, 'rb') as fp:
- step_collection = pickle.load(fp)
+ with open(controller_path, 'rb') as fp:
+ debugger_controller = pickle.load(fp)
- return step_collection
+ return debugger_controller
class Debuggers(object):
@@ -207,10 +180,9 @@ def potential_debuggers(cls):
def __init__(self, context):
self.context = context
- def load(self, key, step_collection=None):
+ def load(self, key):
with Timer('load {}'.format(key)):
- return Debuggers.potential_debuggers()[key](self.context,
- step_collection)
+ return Debuggers.potential_debuggers()[key](self.context)
def _populate_debugger_cache(self):
debuggers = []
diff --git a/debuginfo-tests/dexter/dex/debugger/__init__.py b/debuginfo-tests/dexter/dex/debugger/__init__.py
index 3c4fdece4794..394f9f0eca8d 100644
--- a/debuginfo-tests/dexter/dex/debugger/__init__.py
+++ b/debuginfo-tests/dexter/dex/debugger/__init__.py
@@ -6,3 +6,5 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from dex.debugger.Debuggers import Debuggers
+from dex.debugger.DebuggerControllers.DebuggerControllerBase import DebuggerControllerBase
+from dex.debugger.DebuggerControllers.DefaultController import DefaultController
diff --git a/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py b/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py
index db7ea9161400..0afc748aecb1 100644
--- a/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py
+++ b/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py
@@ -96,7 +96,7 @@ def go(self):
# We never go -- we always single step.
pass
- def get_step_info(self):
+ def get_step_info(self, watches, step_index):
frames = self.step_info
state_frames = []
@@ -118,12 +118,12 @@ def get_step_info(self):
watches={})
for expr in map(
lambda watch, idx=i: self.evaluate_expression(watch, idx),
- self.watches):
+ watches):
state_frame.watches[expr.expression] = expr
state_frames.append(state_frame)
return StepIR(
- step_index=self.step_index, frames=dex_frames,
+ step_index=step_index, frames=dex_frames,
stop_reason=StopReason.STEP,
program_state=ProgramState(state_frames))
diff --git a/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py b/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
index 425d3c2adb12..a943431c8887 100644
--- a/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
+++ b/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
@@ -124,7 +124,7 @@ def go(self) -> ReturnCode:
self._process.Continue()
return ReturnCode.OK
- def get_step_info(self):
+ def get_step_info(self, watches, step_index):
frames = []
state_frames = []
@@ -164,7 +164,7 @@ def get_step_info(self):
watches={})
for expr in map(
lambda watch, idx=i: self.evaluate_expression(watch, idx),
- self.watches):
+ watches):
state_frame.watches[expr.expression] = expr
state_frames.append(state_frame)
@@ -175,7 +175,7 @@ def get_step_info(self):
reason = self._translate_stop_reason(self._thread.GetStopReason())
return StepIR(
- step_index=self.step_index, frames=frames, stop_reason=reason,
+ step_index=step_index, frames=frames, stop_reason=reason,
program_state=ProgramState(state_frames))
@property
diff --git a/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py b/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py
index 596dc31ab4a7..b9816f84f723 100644
--- a/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py
+++ b/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py
@@ -131,7 +131,7 @@ def set_current_stack_frame(self, idx: int = 0):
raise Error('attempted to access stack frame {} out of {}'
.format(idx, len(stack_frames)))
- def get_step_info(self):
+ def get_step_info(self, watches, step_index):
thread = self._debugger.CurrentThread
stackframes = thread.StackFrames
@@ -154,7 +154,7 @@ def get_step_info(self):
is_inlined=frame.is_inlined,
watches={})
- for watch in self.watches:
+ for watch in watches:
state_frame.watches[watch] = self.evaluate_expression(
watch, idx)
@@ -174,7 +174,7 @@ def get_step_info(self):
program_state = ProgramState(frames=state_frames)
return StepIR(
- step_index=self.step_index, frames=frames, stop_reason=reason,
+ step_index=step_index, frames=frames, stop_reason=reason,
program_state=program_state)
@property
diff --git a/debuginfo-tests/dexter/dex/tools/clang_opt_bisect/Tool.py b/debuginfo-tests/dexter/dex/tools/clang_opt_bisect/Tool.py
index a8bdd027d164..1bec2c78dd28 100644
--- a/debuginfo-tests/dexter/dex/tools/clang_opt_bisect/Tool.py
+++ b/debuginfo-tests/dexter/dex/tools/clang_opt_bisect/Tool.py
@@ -13,7 +13,10 @@
import pickle
from dex.builder import run_external_build_script
-from dex.debugger.Debuggers import empty_debugger_steps, get_debugger_steps
+from dex.command.ParseCommand import get_command_infos
+from dex.debugger.Debuggers import run_debugger_subprocess
+from dex.debugger.DebuggerControllers.DefaultController import DefaultController
+from dex.dextIR.DextIR import DextIR
from dex.heuristic import Heuristic
from dex.tools import TestToolBase
from dex.utils.Exceptions import DebuggerException, Error
@@ -84,6 +87,16 @@ def handle_options(self, defaults):
"supported " % options.builder)
super(Tool, self).handle_options(defaults)
+ def _init_debugger_controller(self):
+ step_collection = DextIR(
+ executable_path=self.context.options.executable,
+ source_paths=self.context.options.source_files,
+ dexter_version=self.context.version)
+ step_collection.commands = get_command_infos(
+ self.context.options.source_files)
+ debugger_controller = DefaultController(self.context, step_collection)
+ return debugger_controller
+
def _run_test(self, test_name): # noqa
options = self.context.options
@@ -123,9 +136,15 @@ def _run_test(self, test_name): # noqa
pass_info = (0, None, None)
try:
- steps = get_debugger_steps(self.context)
+ debugger_controller =self._init_debugger_controller()
+ debugger_controller = run_debugger_subprocess(
+ self.context, debugger_controller)
+ steps = debugger_controller.step_collection
except DebuggerException:
- steps = empty_debugger_steps(self.context)
+ steps = DextIR(
+ executable_path=self.context.options.executable,
+ source_paths=self.context.options.source_files,
+ dexter_version=self.context.version)
steps.builder = builderIR
diff --git a/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py b/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py
index 494b4e1d0a99..c4536c4a211f 100644
--- a/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py
+++ b/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py
@@ -17,58 +17,46 @@
from dex.utils.Exceptions import DebuggerException, Error
from dex.utils.ReturnCode import ReturnCode
-
class Tool(ToolBase):
def __init__(self, *args, **kwargs):
+ self.controller_path = None
+ self.debugger_controller = None
+ self.options = None
super(Tool, self).__init__(*args, **kwargs)
- self.dextIR = None
@property
def name(self):
return 'DExTer run debugger internal'
def add_tool_arguments(self, parser, defaults):
- parser.add_argument('dextIR_path', type=str, help='dextIR file')
parser.add_argument(
- 'pickled_options', type=str, help='pickled options file')
+ 'controller_path',
+ type=str,
+ help='pickled debugger controller file')
def handle_options(self, defaults):
- with open(self.context.options.dextIR_path, 'rb') as fp:
- self.dextIR = pickle.load(fp)
-
- with open(self.context.options.pickled_options, 'rb') as fp:
- poptions = pickle.load(fp)
- poptions.working_directory = (
- self.context.options.working_directory[:])
- poptions.unittest = self.context.options.unittest
- poptions.dextIR_path = self.context.options.dextIR_path
- self.context.options = poptions
-
- Timer.display = self.context.options.time_report
+ with open(self.context.options.controller_path, 'rb') as fp:
+ self.debugger_controller = pickle.load(fp)
+ self.controller_path = self.context.options.controller_path
+ self.context = self.debugger_controller.context
+ self.options = self.context.options
+ Timer.display = self.options.time_report
def go(self) -> ReturnCode:
- options = self.context.options
-
with Timer('loading debugger'):
- debugger = Debuggers(self.context).load(options.debugger,
- self.dextIR)
- self.dextIR.debugger = debugger.debugger_info
+ debugger = Debuggers(self.context).load(self.options.debugger)
with Timer('running debugger'):
if not debugger.is_available:
msg = '<d>could not load {}</> ({})\n'.format(
debugger.name, debugger.loading_error)
- if options.verbose:
+ if self.options.verbose:
msg = '{}\n {}'.format(
msg, ' '.join(debugger.loading_error_trace))
raise Error(msg)
- with debugger:
- try:
- debugger.start()
- except DebuggerException as e:
- raise Error(e)
+ self.debugger_controller.run_debugger(debugger)
- with open(self.context.options.dextIR_path, 'wb') as fp:
- pickle.dump(self.dextIR, fp)
+ with open(self.controller_path, 'wb') as fp:
+ pickle.dump(self.debugger_controller, fp)
return ReturnCode.OK
diff --git a/debuginfo-tests/dexter/dex/tools/test/Tool.py b/debuginfo-tests/dexter/dex/tools/test/Tool.py
index 91c9dd48bb63..a615c8cad90c 100644
--- a/debuginfo-tests/dexter/dex/tools/test/Tool.py
+++ b/debuginfo-tests/dexter/dex/tools/test/Tool.py
@@ -13,7 +13,10 @@
import shutil
from dex.builder import run_external_build_script
-from dex.debugger.Debuggers import get_debugger_steps
+from dex.command.ParseCommand import get_command_infos
+from dex.debugger.Debuggers import run_debugger_subprocess
+from dex.debugger.DebuggerControllers.DefaultController import DefaultController
+from dex.dextIR.DextIR import DextIR
from dex.heuristic import Heuristic
from dex.tools import TestToolBase
from dex.utils.Exceptions import DebuggerException
@@ -128,10 +131,23 @@ def _build_test_case(self):
executable_file=options.executable)
return builderIR
+ def _init_debugger_controller(self):
+ step_collection = DextIR(
+ executable_path=self.context.options.executable,
+ source_paths=self.context.options.source_files,
+ dexter_version=self.context.version)
+ step_collection.commands = get_command_infos(
+ self.context.options.source_files)
+ debugger_controller = DefaultController(self.context, step_collection)
+ return debugger_controller
+
def _get_steps(self, builderIR):
"""Generate a list of debugger steps from a test case.
"""
- steps = get_debugger_steps(self.context)
+ debugger_controller = self._init_debugger_controller()
+ debugger_controller = run_debugger_subprocess(
+ debugger_controller, self.context.working_directory.path)
+ steps = debugger_controller.step_collection
steps.builder = builderIR
return steps
More information about the llvm-commits
mailing list