xref: /llvm-project/cross-project-tests/debuginfo-tests/dexter/dex/tools/run_debugger_internal_/Tool.py (revision f98ee40f4b5d7474fc67e82824bf6abbaedb7b1c)
1# DExTer : Debugging Experience Tester
2# ~~~~~~   ~         ~~         ~   ~~
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7"""This is an internal subtool used to sandbox the communication with a
8debugger into a separate process so that any crashes inside the debugger will
9not bring down the entire DExTer tool.
10"""
11
12import pickle
13
14from dex.debugger import Debuggers
15from dex.tools import ToolBase
16from dex.utils import Timer
17from dex.utils.Exceptions import DebuggerException, Error
18from dex.utils.ReturnCode import ReturnCode
19
20
21class Tool(ToolBase):
22    def __init__(self, *args, **kwargs):
23        self.controller_path = None
24        self.debugger_controller = None
25        self.options = None
26        super(Tool, self).__init__(*args, **kwargs)
27
28    @property
29    def name(self):
30        return "DExTer run debugger internal"
31
32    def add_tool_arguments(self, parser, defaults):
33        parser.add_argument(
34            "controller_path", type=str, help="pickled debugger controller file"
35        )
36
37    def handle_options(self, defaults):
38        with open(self.context.options.controller_path, "rb") as fp:
39            self.debugger_controller = pickle.load(fp)
40        self.controller_path = self.context.options.controller_path
41        self.context = self.debugger_controller.context
42        self.options = self.context.options
43        Timer.display = self.options.time_report
44
45    def raise_debugger_error(self, action, debugger):
46        msg = "<d>could not {} {}</> ({})\n".format(
47            action, debugger.name, debugger.loading_error
48        )
49        if self.options.verbose:
50            msg = "{}\n    {}".format(msg, "    ".join(debugger.loading_error_trace))
51        raise Error(msg)
52
53    def go(self) -> ReturnCode:
54        with Timer("loading debugger"):
55            debugger = Debuggers(self.context).load(self.options.debugger)
56
57        with Timer("running debugger"):
58            if not debugger.is_available:
59                self.raise_debugger_error("load", debugger)
60
61            self.debugger_controller.run_debugger(debugger)
62
63            if debugger.loading_error:
64                self.raise_debugger_error("run", debugger)
65
66        with open(self.controller_path, "wb") as fp:
67            pickle.dump(self.debugger_controller, fp)
68        return ReturnCode.OK
69