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