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