238 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 8from ctypes import *9from enum import *10from functools import partial11 12from .utils import *13from . import control14from . import symbols15from . import sysobjs16 17 18class DebugAttach(IntFlag):19 DEBUG_ATTACH_DEFAULT = 020 DEBUG_ATTACH_NONINVASIVE = 121 DEBUG_ATTACH_EXISTING = 222 DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND = 423 DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK = 824 DEBUG_ATTACH_INVASIVE_RESUME_PROCESS = 0x1025 DEBUG_ATTACH_NONINVASIVE_ALLOW_PARTIAL = 0x2026 27 28# UUID for DebugClient7 interface.29DebugClient7IID = IID(30 0x13586BE3,31 0x542E,32 0x481E,33 IID_Data4_Type(0xB1, 0xF2, 0x84, 0x97, 0xBA, 0x74, 0xF9, 0xA9),34)35 36 37class DEBUG_CREATE_PROCESS_OPTIONS(Structure):38 _fields_ = [39 ("CreateFlags", c_ulong),40 ("EngCreateFlags", c_ulong),41 ("VerifierFlags", c_ulong),42 ("Reserved", c_ulong),43 ]44 45 46class IDebugClient7(Structure):47 pass48 49 50class IDebugClient7Vtbl(Structure):51 wrp = partial(WINFUNCTYPE, c_long, POINTER(IDebugClient7))52 idc_queryinterface = wrp(POINTER(IID), POINTER(c_void_p))53 idc_attachprocess = wrp(c_longlong, c_long, c_long)54 idc_detachprocesses = wrp()55 idc_terminateprocesses = wrp()56 idc_createprocessandattach2 = wrp(57 c_ulonglong, c_char_p, c_void_p, c_ulong, c_char_p, c_char_p, c_ulong, c_ulong58 )59 _fields_ = [60 ("QueryInterface", idc_queryinterface),61 ("AddRef", c_void_p),62 ("Release", c_void_p),63 ("AttachKernel", c_void_p),64 ("GetKernelConnectionOptions", c_void_p),65 ("SetKernelConnectionOptions", c_void_p),66 ("StartProcessServer", c_void_p),67 ("ConnectProcessServer", c_void_p),68 ("DisconnectProcessServer", c_void_p),69 ("GetRunningProcessSystemIds", c_void_p),70 ("GetRunningProcessSystemIdsByExecutableName", c_void_p),71 ("GetRunningProcessDescription", c_void_p),72 ("AttachProcess", idc_attachprocess),73 ("CreateProcess", c_void_p),74 ("CreateProcessAndAttach", c_void_p),75 ("GetProcessOptions", c_void_p),76 ("AddProcessOptions", c_void_p),77 ("RemoveProcessOptions", c_void_p),78 ("SetProcessOptions", c_void_p),79 ("OpenDumpFile", c_void_p),80 ("WriteDumpFile", c_void_p),81 ("ConnectSession", c_void_p),82 ("StartServer", c_void_p),83 ("OutputServers", c_void_p),84 ("TerminateProcesses", idc_terminateprocesses),85 ("DetachProcesses", idc_detachprocesses),86 ("EndSession", c_void_p),87 ("GetExitCode", c_void_p),88 ("DispatchCallbacks", c_void_p),89 ("ExitDispatch", c_void_p),90 ("CreateClient", c_void_p),91 ("GetInputCallbacks", c_void_p),92 ("SetInputCallbacks", c_void_p),93 ("GetOutputCallbacks", c_void_p),94 ("SetOutputCallbacks", c_void_p),95 ("GetOutputMask", c_void_p),96 ("SetOutputMask", c_void_p),97 ("GetOtherOutputMask", c_void_p),98 ("SetOtherOutputMask", c_void_p),99 ("GetOutputWidth", c_void_p),100 ("SetOutputWidth", c_void_p),101 ("GetOutputLinePrefix", c_void_p),102 ("SetOutputLinePrefix", c_void_p),103 ("GetIdentity", c_void_p),104 ("OutputIdentity", c_void_p),105 ("GetEventCallbacks", c_void_p),106 ("SetEventCallbacks", c_void_p),107 ("FlushCallbacks", c_void_p),108 ("WriteDumpFile2", c_void_p),109 ("AddDumpInformationFile", c_void_p),110 ("EndProcessServer", c_void_p),111 ("WaitForProcessServerEnd", c_void_p),112 ("IsKernelDebuggerEnabled", c_void_p),113 ("TerminateCurrentProcess", c_void_p),114 ("DetachCurrentProcess", c_void_p),115 ("AbandonCurrentProcess", c_void_p),116 ("GetRunningProcessSystemIdByExecutableNameWide", c_void_p),117 ("GetRunningProcessDescriptionWide", c_void_p),118 ("CreateProcessWide", c_void_p),119 ("CreateProcessAndAttachWide", c_void_p),120 ("OpenDumpFileWide", c_void_p),121 ("WriteDumpFileWide", c_void_p),122 ("AddDumpInformationFileWide", c_void_p),123 ("GetNumberDumpFiles", c_void_p),124 ("GetDumpFile", c_void_p),125 ("GetDumpFileWide", c_void_p),126 ("AttachKernelWide", c_void_p),127 ("GetKernelConnectionOptionsWide", c_void_p),128 ("SetKernelConnectionOptionsWide", c_void_p),129 ("StartProcessServerWide", c_void_p),130 ("ConnectProcessServerWide", c_void_p),131 ("StartServerWide", c_void_p),132 ("OutputServerWide", c_void_p),133 ("GetOutputCallbacksWide", c_void_p),134 ("SetOutputCallbacksWide", c_void_p),135 ("GetOutputLinePrefixWide", c_void_p),136 ("SetOutputLinePrefixWide", c_void_p),137 ("GetIdentityWide", c_void_p),138 ("OutputIdentityWide", c_void_p),139 ("GetEventCallbacksWide", c_void_p),140 ("SetEventCallbacksWide", c_void_p),141 ("CreateProcess2", c_void_p),142 ("CreateProcess2Wide", c_void_p),143 ("CreateProcessAndAttach2", idc_createprocessandattach2),144 ("CreateProcessAndAttach2Wide", c_void_p),145 ("PushOutputLinePrefix", c_void_p),146 ("PushOutputLinePrefixWide", c_void_p),147 ("PopOutputLinePrefix", c_void_p),148 ("GetNumberInputCallbacks", c_void_p),149 ("GetNumberOutputCallbacks", c_void_p),150 ("GetNumberEventCallbacks", c_void_p),151 ("GetQuitLockString", c_void_p),152 ("SetQuitLockString", c_void_p),153 ("GetQuitLockStringWide", c_void_p),154 ("SetQuitLockStringWide", c_void_p),155 ("SetEventContextCallbacks", c_void_p),156 ("SetClientContext", c_void_p),157 ]158 159 160IDebugClient7._fields_ = [("lpVtbl", POINTER(IDebugClient7Vtbl))]161 162 163class Client(object):164 def __init__(self):165 DbgEng = WinDLL("DbgEng")166 DbgEng.DebugCreate.argtypes = [POINTER(IID), POINTER(POINTER(IDebugClient7))]167 DbgEng.DebugCreate.restype = c_ulong168 169 # Call DebugCreate to create a new debug client170 ptr = POINTER(IDebugClient7)()171 res = DbgEng.DebugCreate(byref(DebugClient7IID), ptr)172 aborter(res, "DebugCreate")173 self.client = ptr.contents174 self.vt = vt = self.client.lpVtbl.contents175 176 def QI(iface, ptr):177 return vt.QueryInterface(self.client, byref(iface), byref(ptr))178 179 # Query for a control object180 ptr = c_void_p()181 res = QI(control.DebugControl7IID, ptr)182 aborter(res, "QueryInterface control")183 self.control_ptr = cast(ptr, POINTER(control.IDebugControl7))184 self.Control = control.Control(self.control_ptr)185 186 # Query for a SystemObjects object187 ptr = c_void_p()188 res = QI(sysobjs.DebugSystemObjects4IID, ptr)189 aborter(res, "QueryInterface sysobjects")190 self.sysobjects_ptr = cast(ptr, POINTER(sysobjs.IDebugSystemObjects4))191 self.SysObjects = sysobjs.SysObjects(self.sysobjects_ptr)192 193 # Query for a Symbols object194 ptr = c_void_p()195 res = QI(symbols.DebugSymbols5IID, ptr)196 aborter(res, "QueryInterface debugsymbosl5")197 self.symbols_ptr = cast(ptr, POINTER(symbols.IDebugSymbols5))198 self.Symbols = symbols.Symbols(self.symbols_ptr)199 200 def AttachProcess(self, pid):201 # Zero process-server id means no process-server.202 res = self.vt.AttachProcess(203 self.client, 0, pid, DebugAttach.DEBUG_ATTACH_DEFAULT204 )205 aborter(res, "AttachProcess")206 return207 208 def DetachProcesses(self):209 res = self.vt.DetachProcesses(self.client)210 aborter(res, "DetachProcesses")211 return212 213 def TerminateProcesses(self):214 res = self.vt.TerminateProcesses(self.client)215 aborter(res, "TerminateProcesses")216 return217 218 def CreateProcessAndAttach2(self, cmdline):219 options = DEBUG_CREATE_PROCESS_OPTIONS()220 options.CreateFlags = 0x2 # DEBUG_ONLY_THIS_PROCESS221 options.EngCreateFlags = 0222 options.VerifierFlags = 0223 options.Reserved = 0224 attach_flags = 0225 res = self.vt.CreateProcessAndAttach2(226 self.client,227 0,228 cmdline.encode("ascii"),229 byref(options),230 sizeof(options),231 None,232 None,233 0,234 attach_flags,235 )236 aborter(res, "CreateProcessAndAttach2")237 return238