diff options
Diffstat (limited to 'debuginfo-tests/dexter/dex/debugger/dbgeng/control.py')
-rw-r--r-- | debuginfo-tests/dexter/dex/debugger/dbgeng/control.py | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/debuginfo-tests/dexter/dex/debugger/dbgeng/control.py b/debuginfo-tests/dexter/dex/debugger/dbgeng/control.py new file mode 100644 index 00000000000..38585c83f70 --- /dev/null +++ b/debuginfo-tests/dexter/dex/debugger/dbgeng/control.py @@ -0,0 +1,405 @@ +# 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 + +from ctypes import * +from functools import partial + +from .utils import * +from .breakpoint import * + +class DEBUG_STACK_FRAME_EX(Structure): + _fields_ = [ + ("InstructionOffset", c_ulonglong), + ("ReturnOffset", c_ulonglong), + ("FrameOffset", c_ulonglong), + ("StackOffset", c_ulonglong), + ("FuncTableEntry", c_ulonglong), + ("Params", c_ulonglong * 4), + ("Reserved", c_ulonglong * 6), + ("Virtual", c_bool), + ("FrameNumber", c_ulong), + ("InlineFrameContext", c_ulong), + ("Reserved1", c_ulong) + ] +PDEBUG_STACK_FRAME_EX = POINTER(DEBUG_STACK_FRAME_EX) + +class DEBUG_VALUE_U(Union): + _fields_ = [ + ("I8", c_byte), + ("I16", c_short), + ("I32", c_int), + ("I64", c_long), + ("F32", c_float), + ("F64", c_double), + ("RawBytes", c_ubyte * 24) # Force length to 24b. + ] + +class DEBUG_VALUE(Structure): + _fields_ = [ + ("U", DEBUG_VALUE_U), + ("TailOfRawBytes", c_ulong), + ("Type", c_ulong) + ] +PDEBUG_VALUE = POINTER(DEBUG_VALUE) + +class DebugValueType(IntEnum): + DEBUG_VALUE_INVALID = 0 + DEBUG_VALUE_INT8 = 1 + DEBUG_VALUE_INT16 = 2 + DEBUG_VALUE_INT32 = 3 + DEBUG_VALUE_INT64 = 4 + DEBUG_VALUE_FLOAT32 = 5 + DEBUG_VALUE_FLOAT64 = 6 + DEBUG_VALUE_FLOAT80 = 7 + DEBUG_VALUE_FLOAT82 = 8 + DEBUG_VALUE_FLOAT128 = 9 + DEBUG_VALUE_VECTOR64 = 10 + DEBUG_VALUE_VECTOR128 = 11 + DEBUG_VALUE_TYPES = 12 + +# UUID for DebugControl7 interface. +DebugControl7IID = IID(0xb86fb3b1, 0x80d4, 0x475b, IID_Data4_Type(0xae, 0xa3, 0xcf, 0x06, 0x53, 0x9c, 0xf6, 0x3a)) + +class IDebugControl7(Structure): + pass + +class IDebugControl7Vtbl(Structure): + wrp = partial(WINFUNCTYPE, c_long, POINTER(IDebugControl7)) + idc_getnumbereventfilters = wrp(c_ulong_p, c_ulong_p, c_ulong_p) + idc_setexceptionfiltersecondcommand = wrp(c_ulong, c_char_p) + idc_waitforevent = wrp(c_long, c_long) + idc_execute = wrp(c_long, c_char_p, c_long) + idc_setexpressionsyntax = wrp(c_ulong) + idc_addbreakpoint2 = wrp(c_ulong, c_ulong, POINTER(POINTER(DebugBreakpoint2))) + idc_setexecutionstatus = wrp(c_ulong) + idc_getexecutionstatus = wrp(c_ulong_p) + idc_getstacktraceex = wrp(c_ulonglong, c_ulonglong, c_ulonglong, PDEBUG_STACK_FRAME_EX, c_ulong, c_ulong_p) + idc_evaluate = wrp(c_char_p, c_ulong, PDEBUG_VALUE, c_ulong_p) + _fields_ = [ + ("QueryInterface", c_void_p), + ("AddRef", c_void_p), + ("Release", c_void_p), + ("GetInterrupt", c_void_p), + ("SetInterrupt", c_void_p), + ("GetInterruptTimeout", c_void_p), + ("SetInterruptTimeout", c_void_p), + ("GetLogFile", c_void_p), + ("OpenLogFile", c_void_p), + ("CloseLogFile", c_void_p), + ("GetLogMask", c_void_p), + ("SetLogMask", c_void_p), + ("Input", c_void_p), + ("ReturnInput", c_void_p), + ("Output", c_void_p), + ("OutputVaList", c_void_p), + ("ControlledOutput", c_void_p), + ("ControlledOutputVaList", c_void_p), + ("OutputPrompt", c_void_p), + ("OutputPromptVaList", c_void_p), + ("GetPromptText", c_void_p), + ("OutputCurrentState", c_void_p), + ("OutputVersionInformation", c_void_p), + ("GetNotifyEventHandle", c_void_p), + ("SetNotifyEventHandle", c_void_p), + ("Assemble", c_void_p), + ("Disassemble", c_void_p), + ("GetDisassembleEffectiveOffset", c_void_p), + ("OutputDisassembly", c_void_p), + ("OutputDisassemblyLines", c_void_p), + ("GetNearInstruction", c_void_p), + ("GetStackTrace", c_void_p), + ("GetReturnOffset", c_void_p), + ("OutputStackTrace", c_void_p), + ("GetDebuggeeType", c_void_p), + ("GetActualProcessorType", c_void_p), + ("GetExecutingProcessorType", c_void_p), + ("GetNumberPossibleExecutingProcessorTypes", c_void_p), + ("GetPossibleExecutingProcessorTypes", c_void_p), + ("GetNumberProcessors", c_void_p), + ("GetSystemVersion", c_void_p), + ("GetPageSize", c_void_p), + ("IsPointer64Bit", c_void_p), + ("ReadBugCheckData", c_void_p), + ("GetNumberSupportedProcessorTypes", c_void_p), + ("GetSupportedProcessorTypes", c_void_p), + ("GetProcessorTypeNames", c_void_p), + ("GetEffectiveProcessorType", c_void_p), + ("SetEffectiveProcessorType", c_void_p), + ("GetExecutionStatus", idc_getexecutionstatus), + ("SetExecutionStatus", idc_setexecutionstatus), + ("GetCodeLevel", c_void_p), + ("SetCodeLevel", c_void_p), + ("GetEngineOptions", c_void_p), + ("AddEngineOptions", c_void_p), + ("RemoveEngineOptions", c_void_p), + ("SetEngineOptions", c_void_p), + ("GetSystemErrorControl", c_void_p), + ("SetSystemErrorControl", c_void_p), + ("GetTextMacro", c_void_p), + ("SetTextMacro", c_void_p), + ("GetRadix", c_void_p), + ("SetRadix", c_void_p), + ("Evaluate", idc_evaluate), + ("CoerceValue", c_void_p), + ("CoerceValues", c_void_p), + ("Execute", idc_execute), + ("ExecuteCommandFile", c_void_p), + ("GetNumberBreakpoints", c_void_p), + ("GetBreakpointByIndex", c_void_p), + ("GetBreakpointById", c_void_p), + ("GetBreakpointParameters", c_void_p), + ("AddBreakpoint", c_void_p), + ("RemoveBreakpoint", c_void_p), + ("AddExtension", c_void_p), + ("RemoveExtension", c_void_p), + ("GetExtensionByPath", c_void_p), + ("CallExtension", c_void_p), + ("GetExtensionFunction", c_void_p), + ("GetWindbgExtensionApis32", c_void_p), + ("GetWindbgExtensionApis64", c_void_p), + ("GetNumberEventFilters", idc_getnumbereventfilters), + ("GetEventFilterText", c_void_p), + ("GetEventFilterCommand", c_void_p), + ("SetEventFilterCommand", c_void_p), + ("GetSpecificFilterParameters", c_void_p), + ("SetSpecificFilterParameters", c_void_p), + ("GetSpecificFilterArgument", c_void_p), + ("SetSpecificFilterArgument", c_void_p), + ("GetExceptionFilterParameters", c_void_p), + ("SetExceptionFilterParameters", c_void_p), + ("GetExceptionFilterSecondCommand", c_void_p), + ("SetExceptionFilterSecondCommand", idc_setexceptionfiltersecondcommand), + ("WaitForEvent", idc_waitforevent), + ("GetLastEventInformation", c_void_p), + ("GetCurrentTimeDate", c_void_p), + ("GetCurrentSystemUpTime", c_void_p), + ("GetDumpFormatFlags", c_void_p), + ("GetNumberTextReplacements", c_void_p), + ("GetTextReplacement", c_void_p), + ("SetTextReplacement", c_void_p), + ("RemoveTextReplacements", c_void_p), + ("OutputTextReplacements", c_void_p), + ("GetAssemblyOptions", c_void_p), + ("AddAssemblyOptions", c_void_p), + ("RemoveAssemblyOptions", c_void_p), + ("SetAssemblyOptions", c_void_p), + ("GetExpressionSyntax", c_void_p), + ("SetExpressionSyntax", idc_setexpressionsyntax), + ("SetExpressionSyntaxByName", c_void_p), + ("GetNumberExpressionSyntaxes", c_void_p), + ("GetExpressionSyntaxNames", c_void_p), + ("GetNumberEvents", c_void_p), + ("GetEventIndexDescription", c_void_p), + ("GetCurrentEventIndex", c_void_p), + ("SetNextEventIndex", c_void_p), + ("GetLogFileWide", c_void_p), + ("OpenLogFileWide", c_void_p), + ("InputWide", c_void_p), + ("ReturnInputWide", c_void_p), + ("OutputWide", c_void_p), + ("OutputVaListWide", c_void_p), + ("ControlledOutputWide", c_void_p), + ("ControlledOutputVaListWide", c_void_p), + ("OutputPromptWide", c_void_p), + ("OutputPromptVaListWide", c_void_p), + ("GetPromptTextWide", c_void_p), + ("AssembleWide", c_void_p), + ("DisassembleWide", c_void_p), + ("GetProcessrTypeNamesWide", c_void_p), + ("GetTextMacroWide", c_void_p), + ("SetTextMacroWide", c_void_p), + ("EvaluateWide", c_void_p), + ("ExecuteWide", c_void_p), + ("ExecuteCommandFileWide", c_void_p), + ("GetBreakpointByIndex2", c_void_p), + ("GetBreakpointById2", c_void_p), + ("AddBreakpoint2", idc_addbreakpoint2), + ("RemoveBreakpoint2", c_void_p), + ("AddExtensionWide", c_void_p), + ("GetExtensionByPathWide", c_void_p), + ("CallExtensionWide", c_void_p), + ("GetExtensionFunctionWide", c_void_p), + ("GetEventFilterTextWide", c_void_p), + ("GetEventfilterCommandWide", c_void_p), + ("SetEventFilterCommandWide", c_void_p), + ("GetSpecificFilterArgumentWide", c_void_p), + ("SetSpecificFilterArgumentWide", c_void_p), + ("GetExceptionFilterSecondCommandWide", c_void_p), + ("SetExceptionFilterSecondCommandWider", c_void_p), + ("GetLastEventInformationWide", c_void_p), + ("GetTextReplacementWide", c_void_p), + ("SetTextReplacementWide", c_void_p), + ("SetExpressionSyntaxByNameWide", c_void_p), + ("GetExpressionSyntaxNamesWide", c_void_p), + ("GetEventIndexDescriptionWide", c_void_p), + ("GetLogFile2", c_void_p), + ("OpenLogFile2", c_void_p), + ("GetLogFile2Wide", c_void_p), + ("OpenLogFile2Wide", c_void_p), + ("GetSystemVersionValues", c_void_p), + ("GetSystemVersionString", c_void_p), + ("GetSystemVersionStringWide", c_void_p), + ("GetContextStackTrace", c_void_p), + ("OutputContextStackTrace", c_void_p), + ("GetStoredEventInformation", c_void_p), + ("GetManagedStatus", c_void_p), + ("GetManagedStatusWide", c_void_p), + ("ResetManagedStatus", c_void_p), + ("GetStackTraceEx", idc_getstacktraceex), + ("OutputStackTraceEx", c_void_p), + ("GetContextStackTraceEx", c_void_p), + ("OutputContextStackTraceEx", c_void_p), + ("GetBreakpointByGuid", c_void_p), + ("GetExecutionStatusEx", c_void_p), + ("GetSynchronizationStatus", c_void_p), + ("GetDebuggeeType2", c_void_p) + ] + +IDebugControl7._fields_ = [("lpVtbl", POINTER(IDebugControl7Vtbl))] + +class DebugStatus(IntEnum): + DEBUG_STATUS_NO_CHANGE = 0 + DEBUG_STATUS_GO = 1 + DEBUG_STATUS_GO_HANDLED = 2 + DEBUG_STATUS_GO_NOT_HANDLED = 3 + DEBUG_STATUS_STEP_OVER = 4 + DEBUG_STATUS_STEP_INTO = 5 + DEBUG_STATUS_BREAK = 6 + DEBUG_STATUS_NO_DEBUGGEE = 7 + DEBUG_STATUS_STEP_BRANCH = 8 + DEBUG_STATUS_IGNORE_EVENT = 9 + DEBUG_STATUS_RESTART_REQUESTED = 10 + DEBUG_STATUS_REVERSE_GO = 11 + DEBUG_STATUS_REVERSE_STEP_BRANCH = 12 + DEBUG_STATUS_REVERSE_STEP_OVER = 13 + DEBUG_STATUS_REVERSE_STEP_INTO = 14 + DEBUG_STATUS_OUT_OF_SYNC = 15 + DEBUG_STATUS_WAIT_INPUT = 16 + DEBUG_STATUS_TIMEOUT = 17 + +class DebugSyntax(IntEnum): + DEBUG_EXPR_MASM = 0 + DEBUG_EXPR_CPLUSPLUS = 1 + +class Control(object): + def __init__(self, control): + self.ptr = control + self.control = control.contents + self.vt = self.control.lpVtbl.contents + # Keep a handy ulong for passing into C methods. + self.ulong = c_ulong() + + def GetExecutionStatus(self, doprint=False): + ret = self.vt.GetExecutionStatus(self.control, byref(self.ulong)) + aborter(ret, "GetExecutionStatus") + status = DebugStatus(self.ulong.value) + if doprint: + print("Execution status: {}".format(status)) + return status + + def SetExecutionStatus(self, status): + assert isinstance(status, DebugStatus) + res = self.vt.SetExecutionStatus(self.control, status.value) + aborter(res, "SetExecutionStatus") + + def WaitForEvent(self, timeout=100): + # No flags are taken by WaitForEvent, hence 0 + ret = self.vt.WaitForEvent(self.control, 0, timeout) + aborter(ret, "WaitforEvent", ignore=[S_FALSE]) + return ret + + def GetNumberEventFilters(self): + specific_events = c_ulong() + specific_exceptions = c_ulong() + arbitrary_exceptions = c_ulong() + res = self.vt.GetNumberEventFilters(self.control, byref(specific_events), + byref(specific_exceptions), + byref(arbitrary_exceptions)) + aborter(res, "GetNumberEventFilters") + return (specific_events.value, specific_exceptions.value, + arbitrary_exceptions.value) + + def SetExceptionFilterSecondCommand(self, index, command): + buf = create_string_buffer(command.encode('ascii')) + res = self.vt.SetExceptionFilterSecondCommand(self.control, index, buf) + aborter(res, "SetExceptionFilterSecondCommand") + return + + def AddBreakpoint2(self, offset=None, enabled=None): + breakpoint = POINTER(DebugBreakpoint2)() + res = self.vt.AddBreakpoint2(self.control, BreakpointTypes.DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, byref(breakpoint)) + aborter(res, "Add breakpoint 2") + bp = Breakpoint(breakpoint) + + if offset is not None: + bp.SetOffset(offset) + if enabled is not None and enabled: + bp.SetFlags(BreakpointFlags.DEBUG_BREAKPOINT_ENABLED) + + return bp + + def RemoveBreakpoint(self, bp): + res = self.vt.RemoveBreakpoint2(self.control, bp.breakpoint) + aborter(res, "RemoveBreakpoint2") + bp.die() + + def GetStackTraceEx(self): + # XXX -- I can't find a way to query for how many stack frames there _are_ + # in advance. Guess 128 for now. + num_frames_buffer = 128 + + frames = (DEBUG_STACK_FRAME_EX * num_frames_buffer)() + numframes = c_ulong() + + # First three args are frame/stack/IP offsets -- leave them as zero to + # default to the current instruction. + res = self.vt.GetStackTraceEx(self.control, 0, 0, 0, frames, num_frames_buffer, byref(numframes)) + aborter(res, "GetStackTraceEx") + return frames, numframes.value + + def Execute(self, command): + # First zero is DEBUG_OUTCTL_*, which we leave as a default, second + # zero is DEBUG_EXECUTE_* flags, of which we set none. + res = self.vt.Execute(self.control, 0, command.encode('ascii'), 0) + aborter(res, "Client execute") + + def SetExpressionSyntax(self, cpp=True): + if cpp: + syntax = DebugSyntax.DEBUG_EXPR_CPLUSPLUS + else: + syntax = DebugSyntax.DEBUG_EXPR_MASM + + res = self.vt.SetExpressionSyntax(self.control, syntax) + aborter(res, "SetExpressionSyntax") + + def Evaluate(self, expr): + ptr = DEBUG_VALUE() + res = self.vt.Evaluate(self.control, expr.encode("ascii"), DebugValueType.DEBUG_VALUE_INVALID, byref(ptr), None) + aborter(res, "Evaluate", ignore=[E_INTERNALEXCEPTION, E_FAIL]) + if res != 0: + return None + + val_type = DebugValueType(ptr.Type) + + # Here's a map from debug value types to fields. Unclear what happens + # with unsigned values, as DbgEng doesn't present any unsigned fields. + + extract_map = { + DebugValueType.DEBUG_VALUE_INT8 : ("I8", "char"), + DebugValueType.DEBUG_VALUE_INT16 : ("I16", "short"), + DebugValueType.DEBUG_VALUE_INT32 : ("I32", "int"), + DebugValueType.DEBUG_VALUE_INT64 : ("I64", "long"), + DebugValueType.DEBUG_VALUE_FLOAT32 : ("F32", "float"), + DebugValueType.DEBUG_VALUE_FLOAT64 : ("F64", "double") + } # And everything else is invalid. + + if val_type not in extract_map: + raise Exception("Unexpected debug value type {} when evalutaing".format(val_type)) + + # Also produce a type name... + + return getattr(ptr.U, extract_map[val_type][0]), extract_map[val_type][1] |