From 75b316929a8fbdbe50f5fbd7e517d534c87795f0 Mon Sep 17 00:00:00 2001 From: Stephen Tozer Date: Fri, 8 Oct 2021 17:39:51 +0100 Subject: [PATCH] [Dexter] Add option to pass a Visual Studio solution instead of a binary This patch allows a visual studio solution file to be passed directly into Dexter, instead of using a pre-built binary and a small internal solution file with template arguments. This is primarily to allow launching an application that has specific launch configuration requirements, without needing all the details of this configuration to be built directly into Dexter or adding a config file that simply duplicates existing settings in the VS solution. Reviewed By: Orlando Differential Revision: https://reviews.llvm.org/D110167 --- .../dexter/dex/builder/ParserOptions.py | 2 ++ .../dexter/dex/debugger/DebuggerBase.py | 4 +-- .../DebuggerControllerBase.py | 4 ++- .../dex/debugger/visualstudio/VisualStudio.py | 29 ++++++++++++++----- .../dexter/dex/tools/TestToolBase.py | 7 ++++- .../dex/tools/run_debugger_internal_/Tool.py | 20 ++++++++----- .../dexter/dex/tools/test/Tool.py | 6 +++- 7 files changed, 51 insertions(+), 21 deletions(-) diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/builder/ParserOptions.py b/cross-project-tests/debuginfo-tests/dexter/dex/builder/ParserOptions.py index e35063bde41a..27683f4c418b 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/builder/ParserOptions.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/builder/ParserOptions.py @@ -48,6 +48,8 @@ def add_builder_tool_arguments(parser): type=str, choices=sorted(_find_build_scripts().keys()), help='test builder to use') + build_group.add_argument('--vs-solution', metavar="", + help='provide a path to an already existing visual studio solution.') parser.add_argument( '--cflags', type=str, default='', help='compiler flags') parser.add_argument('--ldflags', type=str, default='', help='linker flags') diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py index a795b3b0a28e..f329a7e6f7dc 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py @@ -16,7 +16,6 @@ from types import SimpleNamespace from dex.command.CommandBase import StepExpectInfo from dex.dextIR import DebuggerIR, FrameIR, LocIR, StepIR, ValueIR from dex.utils.Exceptions import DebuggerException -from dex.utils.Exceptions import NotYetLoadedDebuggerException from dex.utils.ReturnCode import ReturnCode def watch_is_active(watch_info: StepExpectInfo, path, frame_idx, line_no): @@ -44,11 +43,10 @@ class DebuggerBase(object, metaclass=abc.ABCMeta): self._interface = None self.has_loaded = False - self._loading_error = NotYetLoadedDebuggerException() + self._loading_error = None try: self._interface = self._load_interface() self.has_loaded = True - self._loading_error = None except DebuggerException: self._loading_error = sys.exc_info() diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py index 87b13fc7f3a8..cd1a9b3c2f60 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/DebuggerControllerBase.py @@ -21,7 +21,9 @@ class DebuggerControllerBase(object, metaclass=abc.ABCMeta): """ self.debugger = debugger with self.debugger: - self._run_debugger_custom() + if not self.debugger.loading_error: + 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/cross-project-tests/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py index e36b353cef6f..4669fc3486ea 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/visualstudio/VisualStudio.py @@ -67,6 +67,23 @@ class VisualStudio(DebuggerBase, metaclass=abc.ABCMeta): # pylint: disable=abst super(VisualStudio, self).__init__(*args) + def _create_solution(self): + self._solution.Create(self.context.working_directory.path, + 'DexterSolution') + try: + self._solution.AddFromFile(self._project_file) + except OSError: + raise LoadDebuggerException( + 'could not debug the specified executable', sys.exc_info()) + + def _load_solution(self): + try: + self._solution.Open(self.context.options.vs_solution) + except: + raise LoadDebuggerException( + 'could not load specified vs solution at {}'. + format(self.context.options.vs_solution), sys.exc_info()) + def _custom_init(self): try: self._debugger = self._interface.Debugger @@ -76,14 +93,10 @@ class VisualStudio(DebuggerBase, metaclass=abc.ABCMeta): # pylint: disable=abst self.context.options.show_debugger) self._solution = self._interface.Solution - self._solution.Create(self.context.working_directory.path, - 'DexterSolution') - - try: - self._solution.AddFromFile(self._project_file) - except OSError: - raise LoadDebuggerException( - 'could not debug the specified executable', sys.exc_info()) + if self.context.options.vs_solution is None: + self._create_solution() + else: + self._load_solution() self._fn_step = self._debugger.StepInto self._fn_go = self._debugger.Go diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/tools/TestToolBase.py b/cross-project-tests/debuginfo-tests/dexter/dex/tools/TestToolBase.py index 922e58cee57e..197803b969c7 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/tools/TestToolBase.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/tools/TestToolBase.py @@ -58,7 +58,12 @@ class TestToolBase(ToolBase): warn(self.context, '--cflags and --ldflags will be ignored when not' ' using --builder') - if options.binary: + if options.vs_solution: + options.vs_solution = os.path.abspath(options.vs_solution) + if not os.path.isfile(options.vs_solution): + raise Error('could not find VS solution file "{}"' + .format(options.vs_solution)) + elif options.binary: options.binary = os.path.abspath(options.binary) if not os.path.isfile(options.binary): raise Error('could not find binary file "{}"' diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py b/cross-project-tests/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py index c4536c4a211f..5091e607b6c6 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py @@ -42,20 +42,26 @@ class Tool(ToolBase): self.options = self.context.options Timer.display = self.options.time_report + def raise_debugger_error(self, action, debugger): + msg = 'could not {} {} ({})\n'.format( + action, debugger.name, debugger.loading_error) + if self.options.verbose: + msg = '{}\n {}'.format( + msg, ' '.join(debugger.loading_error_trace)) + raise Error(msg) + def go(self) -> ReturnCode: with Timer('loading debugger'): debugger = Debuggers(self.context).load(self.options.debugger) with Timer('running debugger'): if not debugger.is_available: - msg = 'could not load {} ({})\n'.format( - debugger.name, debugger.loading_error) - if self.options.verbose: - msg = '{}\n {}'.format( - msg, ' '.join(debugger.loading_error_trace)) - raise Error(msg) + self.raise_debugger_error('load', debugger) - self.debugger_controller.run_debugger(debugger) + self.debugger_controller.run_debugger(debugger) + + if debugger.loading_error: + self.raise_debugger_error('run', debugger) with open(self.controller_path, 'wb') as fp: pickle.dump(self.debugger_controller, fp) diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/tools/test/Tool.py b/cross-project-tests/debuginfo-tests/dexter/dex/tools/test/Tool.py index 1456d6e66db9..6e0ef56c9f74 100644 --- a/cross-project-tests/debuginfo-tests/dexter/dex/tools/test/Tool.py +++ b/cross-project-tests/debuginfo-tests/dexter/dex/tools/test/Tool.py @@ -108,9 +108,13 @@ class Tool(TestToolBase): """Build an executable from the test source with the given --builder script and flags (--cflags, --ldflags) in the working directory. Or, if the --binary option has been given, copy the executable provided - into the working directory and rename it to match the --builder output. + into the working directory and rename it to match the --builder output + or skip if --vs-solution was passed on the command line. """ + if self.context.options.vs_solution: + return + options = self.context.options if options.binary: # Copy user's binary into the tmp working directory