summaryrefslogtreecommitdiffstats
path: root/debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py
diff options
context:
space:
mode:
Diffstat (limited to 'debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py')
-rw-r--r--debuginfo-tests/dexter/dex/debugger/dbgeng/dbgeng.py163
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)
OpenPOWER on IntegriCloud