• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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