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 17 18class DebugAttach(IntFlag): 19 DEBUG_ATTACH_DEFAULT = 0 20 DEBUG_ATTACH_NONINVASIVE = 1 21 DEBUG_ATTACH_EXISTING = 2 22 DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND = 4 23 DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK = 8 24 DEBUG_ATTACH_INVASIVE_RESUME_PROCESS = 0x10 25 DEBUG_ATTACH_NONINVASIVE_ALLOW_PARTIAL = 0x20 26 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 pass 48 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_ulong 58 ) 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_ulong 168 169 # Call DebugCreate to create a new debug client 170 ptr = POINTER(IDebugClient7)() 171 res = DbgEng.DebugCreate(byref(DebugClient7IID), ptr) 172 aborter(res, "DebugCreate") 173 self.client = ptr.contents 174 self.vt = vt = self.client.lpVtbl.contents 175 176 def QI(iface, ptr): 177 return vt.QueryInterface(self.client, byref(iface), byref(ptr)) 178 179 # Query for a control object 180 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 object 187 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 object 194 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_DEFAULT 204 ) 205 aborter(res, "AttachProcess") 206 return 207 208 def DetachProcesses(self): 209 res = self.vt.DetachProcesses(self.client) 210 aborter(res, "DetachProcesses") 211 return 212 213 def TerminateProcesses(self): 214 res = self.vt.TerminateProcesses(self.client) 215 aborter(res, "TerminateProcesses") 216 return 217 218 def CreateProcessAndAttach2(self, cmdline): 219 options = DEBUG_CREATE_PROCESS_OPTIONS() 220 options.CreateFlags = 0x2 # DEBUG_ONLY_THIS_PROCESS 221 options.EngCreateFlags = 0 222 options.VerifierFlags = 0 223 options.Reserved = 0 224 attach_flags = 0 225 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 return 238