xref: /llvm-project/cross-project-tests/debuginfo-tests/dexter/dex/debugger/dbgeng/client.py (revision f98ee40f4b5d7474fc67e82824bf6abbaedb7b1c)
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