brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · bf0a0f1 Raw
205 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~   ~         ~~         ~   ~~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-exception7 8import sys9import os10import platform11 12from dex.debugger.DebuggerBase import DebuggerBase, watch_is_active13from dex.dextIR import FrameIR, LocIR, StepIR, StopReason, ValueIR14from dex.dextIR import ProgramState, StackFrame, SourceLocation15from dex.utils.Exceptions import DebuggerException, LoadDebuggerException16from dex.utils.ReturnCode import ReturnCode17 18if platform.system() == "Windows":19    # Don't load on linux; _load_interface will croak before any names are used.20    from . import setup21    from . import probe_process22    from . import breakpoint23 24 25class DbgEng(DebuggerBase):26    def __init__(self, context, *args):27        self.breakpoints = []28        self.running = False29        self.finished = False30        self.step_info = None31        super(DbgEng, self).__init__(context, *args)32 33    def _custom_init(self):34        try:35            res = setup.setup_everything(self.context.options.executable)36            self.client = res37            self.running = True38        except Exception as e:39            raise Exception("Failed to start debuggee: {}".format(e))40 41    def _custom_exit(self):42        setup.cleanup(self.client)43 44    def _load_interface(self):45        arch = platform.architecture()[0]46        machine = platform.machine()47        if arch == "32bit" and machine == "AMD64":48            # This python process is 32 bits, but is sitting on a 64 bit machine.49            # Bad things may happen, don't support it.50            raise LoadDebuggerException(51                "Can't run Dexter dbgeng on 32 bit python in a 64 bit environment"52            )53 54        if platform.system() != "Windows":55            raise LoadDebuggerException("DbgEng supports Windows only")56 57        # Otherwise, everything was imported earlier58 59    @classmethod60    def get_name(cls):61        return "dbgeng"62 63    @classmethod64    def get_option_name(cls):65        return "dbgeng"66 67    @property68    def frames_below_main(self):69        return []70 71    @property72    def version(self):73        # I don't believe there's a well defined DbgEng version, outside of the74        # version of Windows being used.75        return "1"76 77    def clear_breakpoints(self):78        for x in self.breakpoints:79            x.RemoveFlags(breakpoint.BreakpointFlags.DEBUG_BREAKPOINT_ENABLED)80            self.client.Control.RemoveBreakpoint(x)81 82    def _add_breakpoint(self, file_, line):83        # Breakpoint setting/deleting is not supported by dbgeng at this moment84        # but is something that should be considered in the future.85        # TODO: this method is called in the DefaultController but has no effect.86        pass87 88    def _add_conditional_breakpoint(self, file_, line, condition):89        # breakpoint setting/deleting is not supported by dbgeng at this moment90        # but is something that should be considered in the future.91        raise NotImplementedError(92            "add_conditional_breakpoint is not yet implemented by dbgeng"93        )94 95    def get_triggered_breakpoint_ids(self):96        raise NotImplementedError(97            "get_triggered_breakpoint_ids is not yet implemented by dbgeng"98        )99 100    def delete_breakpoints(self, ids):101        # breakpoint setting/deleting is not supported by dbgeng at this moment102        # but is something that should be considered in the future.103        raise NotImplementedError(104            "delete_conditional_breakpoint is not yet implemented by dbgeng"105        )106 107    def launch(self, cmdline):108        assert (109            len(cmdline) == 0 and not self.context.options.target_run_args110        ), "Command lines unimplemented for dbgeng right now"111        # We are, by this point, already launched.112        self.step_info = probe_process.probe_state(self.client)113 114    def step_in(self):115        res = setup.step_once(self.client)116        if not res:117            self.finished = True118        self.step_info = res119 120    def go(self):121        # FIXME: running freely doesn't seem to reliably stop when back in a122        # relevant source file -- this is likely to be a problem when setting123        # breakpoints. Until that's fixed, single step instead of running124        # freely. This isn't very efficient, but at least makes progress.125        self.step_in()126 127    def _get_step_info(self, watches, step_index):128        frames = self.step_info129        state_frames = []130 131        # For now assume the base function is the... function, ignoring132        # inlining.133        dex_frames = []134        for i, x in enumerate(frames):135            # XXX Might be able to get columns out through136            # GetSourceEntriesByOffset, not a priority now137            loc = LocIR(path=x.source_file, lineno=x.line_no, column=0)138            new_frame = FrameIR(function=x.function_name, is_inlined=False, loc=loc)139            dex_frames.append(new_frame)140 141            state_frame = StackFrame(142                function=new_frame.function,143                is_inlined=new_frame.is_inlined,144                location=SourceLocation(path=x.source_file, lineno=x.line_no, column=0),145                watches={},146            )147            for expr in map(148                # Filter out watches that are not active in the current frame,149                # and then evaluate all the active watches.150                lambda watch_info, idx=i: self.evaluate_expression(151                    watch_info.expression, idx152                ),153                filter(154                    lambda watch_info, idx=i, line_no=loc.lineno, path=loc.path: watch_is_active(155                        watch_info, path, idx, line_no156                    ),157                    watches,158                ),159            ):160                state_frame.watches[expr.expression] = expr161            state_frames.append(state_frame)162 163        return StepIR(164            step_index=step_index,165            frames=dex_frames,166            stop_reason=StopReason.STEP,167            program_state=ProgramState(state_frames),168        )169 170    @property171    def is_running(self):172        return False  # We're never free-running173 174    @property175    def is_finished(self):176        return self.finished177 178    def evaluate_expression(self, expression, frame_idx=0):179        # XXX: cdb insists on using '->' to examine fields of structures,180        # as it appears to reserve '.' for other purposes.181        fixed_expr = expression.replace(".", "->")182 183        orig_scope_idx = self.client.Symbols.GetCurrentScopeFrameIndex()184        self.client.Symbols.SetScopeFrameByIndex(frame_idx)185 186        res = self.client.Control.Evaluate(fixed_expr)187        if res is not None:188            result, typename = self.client.Control.Evaluate(fixed_expr)189            could_eval = True190        else:191            result, typename = (None, None)192            could_eval = False193 194        self.client.Symbols.SetScopeFrameByIndex(orig_scope_idx)195 196        return ValueIR(197            expression=expression,198            value=str(result),199            type_name=typename,200            error_string="",201            could_evaluate=could_eval,202            is_optimized_away=False,203            is_irretrievable=not could_eval,204        )205