diff options
Diffstat (limited to 'debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py')
-rw-r--r-- | debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py b/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py new file mode 100644 index 00000000000..66d01f03e8f --- /dev/null +++ b/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py @@ -0,0 +1,163 @@ +# 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 + +import sys +import os +import platform + +from dex.debugger.DebuggerBase import DebuggerBase +from dex.dextIR import FrameIR, LocIR, StepIR, StopReason, ValueIR +from dex.dextIR import ProgramState, StackFrame, SourceLocation +from dex.utils.Exceptions import DebuggerException, LoadDebuggerException +from dex.utils.ReturnCode import ReturnCode + +if platform.system() == "Windows": + # Don't load on linux; _load_interface will croak before any names are used. + from . import setup + from . import probe_process + from . import breakpoint + +class DbgEng(DebuggerBase): + def __init__(self, context, *args): + self.breakpoints = [] + self.running = False + self.finished = False + self.step_info = None + super(DbgEng, self).__init__(context, *args) + + def _custom_init(self): + try: + res = setup.setup_everything(self.context.options.executable) + self.client, self.hProcess = res + self.running = True + except Exception as e: + raise Exception('Failed to start debuggee: {}'.format(e)) + + def _custom_exit(self): + setup.cleanup(self.client, self.hProcess) + + def _load_interface(self): + arch = platform.architecture()[0] + machine = platform.machine() + if arch == '32bit' and machine == 'AMD64': + # This python process is 32 bits, but is sitting on a 64 bit machine. + # Bad things may happen, don't support it. + raise LoadDebuggerException('Can\'t run Dexter dbgeng on 32 bit python in a 64 bit environment') + + if platform.system() != 'Windows': + raise LoadDebuggerException('DbgEng supports Windows only') + + # Otherwise, everything was imported earlier + + @classmethod + def get_name(cls): + return 'dbgeng' + + @classmethod + def get_option_name(cls): + return 'dbgeng' + + @property + def frames_below_main(self): + return [] + + @property + def version(self): + # I don't believe there's a well defined DbgEng version, outside of the + # version of Windows being used. + return "1" + + def clear_breakpoints(self): + for x in self.breakpoints: + x.RemoveFlags(breakpoint.BreakpointFlags.DEBUG_BREAKPOINT_ENABLED) + self.client.Control.RemoveBreakpoint(x) + + def add_breakpoint(self, file_, line): + # This is something to implement in the future -- as it stands, Dexter + # doesn't test for such things as "I can set a breakpoint on this line". + # This is only called AFAICT right now to ensure we break on every step. + pass + + def launch(self): + # We are, by this point, already launched. + self.step_info = probe_process.probe_state(self.client) + + def step(self): + res = setup.step_once(self.client) + if not res: + self.finished = True + self.step_info = res + + def go(self): + # We never go -- we always single step. + pass + + def get_step_info(self): + frames = self.step_info + state_frames = [] + + # For now assume the base function is the... function, ignoring + # inlining. + dex_frames = [] + for i, x in enumerate(frames): + # XXX Might be able to get columns out through + # GetSourceEntriesByOffset, not a priority now + loc = LocIR(path=x.source_file, lineno=x.line_no, column=0) + new_frame = FrameIR(function=x.function_name, is_inlined=False, loc=loc) + dex_frames.append(new_frame) + + state_frame = StackFrame(function=new_frame.function, + is_inlined=new_frame.is_inlined, + location=SourceLocation(path=x.source_file, + lineno=x.line_no, + column=0), + watches={}) + for expr in map( + lambda watch, idx=i: self.evaluate_expression(watch, idx), + self.watches): + state_frame.watches[expr.expression] = expr + state_frames.append(state_frame) + + return StepIR( + step_index=self.step_index, frames=dex_frames, + stop_reason=StopReason.STEP, + program_state=ProgramState(state_frames)) + + @property + def is_running(self): + return False # We're never free-running + + @property + def is_finished(self): + return self.finished + + def evaluate_expression(self, expression, frame_idx=0): + # XXX: cdb insists on using '->' to examine fields of structures, + # as it appears to reserve '.' for other purposes. + fixed_expr = expression.replace('.', '->') + + orig_scope_idx = self.client.Symbols.GetCurrentScopeFrameIndex() + self.client.Symbols.SetScopeFrameByIndex(frame_idx) + + res = self.client.Control.Evaluate(fixed_expr) + if res is not None: + result, typename = self.client.Control.Evaluate(fixed_expr) + could_eval = True + else: + result, typename = (None, None) + could_eval = False + + self.client.Symbols.SetScopeFrameByIndex(orig_scope_idx) + + return ValueIR( + expression=expression, + value=str(result), + type_name=typename, + error_string="", + could_evaluate=could_eval, + is_optimized_away=False, + is_irretrievable=not could_eval) |