import sys
import os
import platform
from dex.debugger.DebuggerBase import DebuggerBase, watch_is_active
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":
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 = res
self.running = True
except Exception as e:
raise Exception("Failed to start debuggee: {}".format(e))
def _custom_exit(self):
setup.cleanup(self.client)
def _load_interface(self):
arch = platform.architecture()[0]
machine = platform.machine()
if arch == "32bit" and machine == "AMD64":
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")
@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):
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):
pass
def _add_conditional_breakpoint(self, file_, line, condition):
raise NotImplementedError(
"add_conditional_breakpoint is not yet implemented by dbgeng"
)
def get_triggered_breakpoint_ids(self):
raise NotImplementedError(
"get_triggered_breakpoint_ids is not yet implemented by dbgeng"
)
def delete_breakpoints(self, ids):
raise NotImplementedError(
"delete_conditional_breakpoint is not yet implemented by dbgeng"
)
def launch(self, cmdline):
assert (
len(cmdline) == 0 and not self.context.options.target_run_args
), "Command lines unimplemented for dbgeng right now"
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):
self.step()
def _get_step_info(self, watches, step_index):
frames = self.step_info
state_frames = []
dex_frames = []
for i, x in enumerate(frames):
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_info, idx=i: self.evaluate_expression(
watch_info.expression, idx
),
filter(
lambda watch_info, idx=i, line_no=loc.lineno, path=loc.path: watch_is_active(
watch_info, path, idx, line_no
),
watches,
),
):
state_frame.watches[expr.expression] = expr
state_frames.append(state_frame)
return StepIR(
step_index=step_index,
frames=dex_frames,
stop_reason=StopReason.STEP,
program_state=ProgramState(state_frames),
)
@property
def is_running(self):
return False
@property
def is_finished(self):
return self.finished
def evaluate_expression(self, expression, frame_idx=0):
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,
)