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 functools import partial 10 11from .utils import * 12 13# UUID For SystemObjects4 interface. 14DebugSystemObjects4IID = IID( 15 0x489468E6, 16 0x7D0F, 17 0x4AF5, 18 IID_Data4_Type(0x87, 0xAB, 0x25, 0x20, 0x74, 0x54, 0xD5, 0x53), 19) 20 21 22class IDebugSystemObjects4(Structure): 23 pass 24 25 26class IDebugSystemObjects4Vtbl(Structure): 27 wrp = partial(WINFUNCTYPE, c_long, POINTER(IDebugSystemObjects4)) 28 ids_getnumberprocesses = wrp(POINTER(c_ulong)) 29 ids_getprocessidsbyindex = wrp(c_ulong, c_ulong, c_ulong_p, c_ulong_p) 30 ids_setcurrentprocessid = wrp(c_ulong) 31 ids_getnumberthreads = wrp(c_ulong_p) 32 ids_getthreadidsbyindex = wrp(c_ulong, c_ulong, c_ulong_p, c_ulong_p) 33 ids_setcurrentthreadid = wrp(c_ulong) 34 _fields_ = [ 35 ("QueryInterface", c_void_p), 36 ("AddRef", c_void_p), 37 ("Release", c_void_p), 38 ("GetEventThread", c_void_p), 39 ("GetEventProcess", c_void_p), 40 ("GetCurrentThreadId", c_void_p), 41 ("SetCurrentThreadId", ids_setcurrentthreadid), 42 ("GetCurrentProcessId", c_void_p), 43 ("SetCurrentProcessId", ids_setcurrentprocessid), 44 ("GetNumberThreads", ids_getnumberthreads), 45 ("GetTotalNumberThreads", c_void_p), 46 ("GetThreadIdsByIndex", ids_getthreadidsbyindex), 47 ("GetThreadIdByProcessor", c_void_p), 48 ("GetCurrentThreadDataOffset", c_void_p), 49 ("GetThreadIdByDataOffset", c_void_p), 50 ("GetCurrentThreadTeb", c_void_p), 51 ("GetThreadIdByTeb", c_void_p), 52 ("GetCurrentThreadSystemId", c_void_p), 53 ("GetThreadIdBySystemId", c_void_p), 54 ("GetCurrentThreadHandle", c_void_p), 55 ("GetThreadIdByHandle", c_void_p), 56 ("GetNumberProcesses", ids_getnumberprocesses), 57 ("GetProcessIdsByIndex", ids_getprocessidsbyindex), 58 ("GetCurrentProcessDataOffset", c_void_p), 59 ("GetProcessIdByDataOffset", c_void_p), 60 ("GetCurrentProcessPeb", c_void_p), 61 ("GetProcessIdByPeb", c_void_p), 62 ("GetCurrentProcessSystemId", c_void_p), 63 ("GetProcessIdBySystemId", c_void_p), 64 ("GetCurrentProcessHandle", c_void_p), 65 ("GetProcessIdByHandle", c_void_p), 66 ("GetCurrentProcessExecutableName", c_void_p), 67 ("GetCurrentProcessUpTime", c_void_p), 68 ("GetImplicitThreadDataOffset", c_void_p), 69 ("SetImplicitThreadDataOffset", c_void_p), 70 ("GetImplicitProcessDataOffset", c_void_p), 71 ("SetImplicitProcessDataOffset", c_void_p), 72 ("GetEventSystem", c_void_p), 73 ("GetCurrentSystemId", c_void_p), 74 ("SetCurrentSystemId", c_void_p), 75 ("GetNumberSystems", c_void_p), 76 ("GetSystemIdsByIndex", c_void_p), 77 ("GetTotalNumberThreadsAndProcesses", c_void_p), 78 ("GetCurrentSystemServer", c_void_p), 79 ("GetSystemByServer", c_void_p), 80 ("GetCurrentSystemServerName", c_void_p), 81 ("GetCurrentProcessExecutableNameWide", c_void_p), 82 ("GetCurrentSystemServerNameWide", c_void_p), 83 ] 84 85 86IDebugSystemObjects4._fields_ = [("lpVtbl", POINTER(IDebugSystemObjects4Vtbl))] 87 88 89class SysObjects(object): 90 def __init__(self, sysobjects): 91 self.ptr = sysobjects 92 self.sysobjects = sysobjects.contents 93 self.vt = self.sysobjects.lpVtbl.contents 94 # Keep a handy ulong for passing into C methods. 95 self.ulong = c_ulong() 96 97 def GetNumberSystems(self): 98 res = self.vt.GetNumberSystems(self.sysobjects, byref(self.ulong)) 99 aborter(res, "GetNumberSystems") 100 return self.ulong.value 101 102 def GetNumberProcesses(self): 103 res = self.vt.GetNumberProcesses(self.sysobjects, byref(self.ulong)) 104 aborter(res, "GetNumberProcesses") 105 return self.ulong.value 106 107 def GetNumberThreads(self): 108 res = self.vt.GetNumberThreads(self.sysobjects, byref(self.ulong)) 109 aborter(res, "GetNumberThreads") 110 return self.ulong.value 111 112 def GetTotalNumberThreadsAndProcesses(self): 113 tthreads = c_ulong() 114 tprocs = c_ulong() 115 pulong3 = c_ulong() 116 res = self.vt.GetTotalNumberThreadsAndProcesses( 117 self.sysobjects, 118 byref(tthreads), 119 byref(tprocs), 120 byref(pulong3), 121 byref(pulong3), 122 byref(pulong3), 123 ) 124 aborter(res, "GettotalNumberThreadsAndProcesses") 125 return tthreads.value, tprocs.value 126 127 def GetCurrentProcessId(self): 128 res = self.vt.GetCurrentProcessId(self.sysobjects, byref(self.ulong)) 129 aborter(res, "GetCurrentProcessId") 130 return self.ulong.value 131 132 def SetCurrentProcessId(self, sysid): 133 res = self.vt.SetCurrentProcessId(self.sysobjects, sysid) 134 aborter(res, "SetCurrentProcessId") 135 return 136 137 def GetCurrentThreadId(self): 138 res = self.vt.GetCurrentThreadId(self.sysobjects, byref(self.ulong)) 139 aborter(res, "GetCurrentThreadId") 140 return self.ulong.value 141 142 def SetCurrentThreadId(self, sysid): 143 res = self.vt.SetCurrentThreadId(self.sysobjects, sysid) 144 aborter(res, "SetCurrentThreadId") 145 return 146 147 def GetProcessIdsByIndex(self): 148 num_processes = self.GetNumberProcesses() 149 if num_processes == 0: 150 return [] 151 engineids = (c_ulong * num_processes)() 152 pids = (c_ulong * num_processes)() 153 for x in range(num_processes): 154 engineids[x] = DEBUG_ANY_ID 155 pids[x] = DEBUG_ANY_ID 156 res = self.vt.GetProcessIdsByIndex( 157 self.sysobjects, 0, num_processes, engineids, pids 158 ) 159 aborter(res, "GetProcessIdsByIndex") 160 return list(zip(engineids, pids)) 161 162 def GetThreadIdsByIndex(self): 163 num_threads = self.GetNumberThreads() 164 if num_threads == 0: 165 return [] 166 engineids = (c_ulong * num_threads)() 167 tids = (c_ulong * num_threads)() 168 for x in range(num_threads): 169 engineids[x] = DEBUG_ANY_ID 170 tids[x] = DEBUG_ANY_ID 171 # Zero -> start index 172 res = self.vt.GetThreadIdsByIndex( 173 self.sysobjects, 0, num_threads, engineids, tids 174 ) 175 aborter(res, "GetThreadIdsByIndex") 176 return list(zip(engineids, tids)) 177 178 def GetCurThreadHandle(self): 179 pulong64 = c_ulonglong() 180 res = self.vt.GetCurrentThreadHandle(self.sysobjects, byref(pulong64)) 181 aborter(res, "GetCurrentThreadHandle") 182 return pulong64.value 183 184 def set_current_thread(self, pid, tid): 185 proc_sys_id = -1 186 for x in self.GetProcessIdsByIndex(): 187 sysid, procid = x 188 if procid == pid: 189 proc_sys_id = sysid 190 191 if proc_sys_id == -1: 192 raise Exception("Couldn't find designated PID {}".format(pid)) 193 194 self.SetCurrentProcessId(proc_sys_id) 195 196 thread_sys_id = -1 197 for x in self.GetThreadIdsByIndex(): 198 sysid, threadid = x 199 if threadid == tid: 200 thread_sys_id = sysid 201 202 if thread_sys_id == -1: 203 raise Exception("Couldn't find designated TID {}".format(tid)) 204 205 self.SetCurrentThreadId(thread_sys_id) 206 return 207 208 def print_current_procs_threads(self): 209 procs = [] 210 for x in self.GetProcessIdsByIndex(): 211 sysid, procid = x 212 procs.append(procid) 213 214 threads = [] 215 for x in self.GetThreadIdsByIndex(): 216 sysid, threadid = x 217 threads.append(threadid) 218 219 print("Current processes: {}".format(procs)) 220 print("Current threads: {}".format(threads)) 221