2 * Copyright 2019 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/test.h"
31 static void test_engine_options(void)
33 IDebugControl
*control
;
37 hr
= DebugCreate(&IID_IDebugControl
, (void **)&control
);
38 ok(hr
== S_OK
, "Failed to create engine object, hr %#x.\n", hr
);
41 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
42 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
43 ok(options
== 0, "Unexpected options %#x.\n", options
);
45 hr
= control
->lpVtbl
->AddEngineOptions(control
, DEBUG_ENGOPT_INITIAL_BREAK
);
46 ok(hr
== S_OK
, "Failed to add engine options, hr %#x.\n", hr
);
49 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
50 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
51 ok(options
== DEBUG_ENGOPT_INITIAL_BREAK
, "Unexpected options %#x.\n", options
);
53 hr
= control
->lpVtbl
->AddEngineOptions(control
, 0x01000000);
54 ok(hr
== E_INVALIDARG
, "Unexpected hr %#x.\n", hr
);
57 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
58 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
59 ok(options
== DEBUG_ENGOPT_INITIAL_BREAK
, "Unexpected options %#x.\n", options
);
61 hr
= control
->lpVtbl
->RemoveEngineOptions(control
, 0x01000000);
62 ok(hr
== S_OK
, "Failed to remove options, hr %#x.\n", hr
);
64 hr
= control
->lpVtbl
->AddEngineOptions(control
, DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION
);
65 ok(hr
== S_OK
, "Failed to add engine options, hr %#x.\n", hr
);
68 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
69 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
70 ok(options
== (DEBUG_ENGOPT_INITIAL_BREAK
| DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION
),
71 "Unexpected options %#x.\n", options
);
73 hr
= control
->lpVtbl
->RemoveEngineOptions(control
, DEBUG_ENGOPT_INITIAL_BREAK
);
74 ok(hr
== S_OK
, "Failed to remove options, hr %#x.\n", hr
);
77 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
78 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
79 ok(options
== DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION
, "Unexpected options %#x.\n", options
);
81 hr
= control
->lpVtbl
->SetEngineOptions(control
, DEBUG_ENGOPT_INITIAL_BREAK
);
82 ok(hr
== S_OK
, "Failed to set options, hr %#x.\n", hr
);
85 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
86 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
87 ok(options
== DEBUG_ENGOPT_INITIAL_BREAK
, "Unexpected options %#x.\n", options
);
89 hr
= control
->lpVtbl
->SetEngineOptions(control
, 0x01000000);
90 ok(hr
== E_INVALIDARG
, "Unexpected hr %#x.\n", hr
);
92 hr
= control
->lpVtbl
->SetEngineOptions(control
, 0x01000000 | DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION
);
93 ok(hr
== E_INVALIDARG
, "Unexpected hr %#x.\n", hr
);
96 hr
= control
->lpVtbl
->GetEngineOptions(control
, &options
);
97 ok(hr
== S_OK
, "Failed to get engine options, hr %#x.\n", hr
);
98 ok(options
== DEBUG_ENGOPT_INITIAL_BREAK
, "Unexpected options %#x.\n", options
);
100 control
->lpVtbl
->Release(control
);
103 static HRESULT WINAPI
event_callbacks_QueryInterface(IDebugEventCallbacks
*iface
, REFIID riid
, void **out
)
105 if (IsEqualIID(riid
, &IID_IDebugEventCallbacks
) ||
106 IsEqualIID(riid
, &IID_IUnknown
))
109 iface
->lpVtbl
->AddRef(iface
);
114 return E_NOINTERFACE
;
117 static ULONG WINAPI
event_callbacks_AddRef(IDebugEventCallbacks
*iface
)
122 static ULONG WINAPI
event_callbacks_Release(IDebugEventCallbacks
*iface
)
127 static HRESULT WINAPI
event_callbacks_GetInterestMask(IDebugEventCallbacks
*iface
, ULONG
*mask
)
133 static HRESULT WINAPI
event_callbacks_Breakpoint(IDebugEventCallbacks
*iface
, PDEBUG_BREAKPOINT breakpoint
)
138 static HRESULT WINAPI
event_callbacks_Exception(IDebugEventCallbacks
*iface
, EXCEPTION_RECORD64
*exception
,
144 static HRESULT WINAPI
event_callbacks_CreateThread(IDebugEventCallbacks
*iface
, ULONG64 handle
, ULONG64 data_offset
,
145 ULONG64 start_offset
)
150 static HRESULT WINAPI
event_callbacks_ExitThread(IDebugEventCallbacks
*iface
, ULONG exit_code
)
155 static HRESULT WINAPI
event_callbacks_CreateProcess(IDebugEventCallbacks
*iface
, ULONG64 image_handle
, ULONG64 handle
,
156 ULONG64 base_offset
, ULONG module_size
, const char *module_name
, const char *image_name
, ULONG checksum
,
157 ULONG timedatestamp
, ULONG64 initial_thread_handle
, ULONG64 thread_data_offset
, ULONG64 start_offset
)
162 static HRESULT WINAPI
event_callbacks_ExitProcess(IDebugEventCallbacks
*iface
, ULONG exit_code
)
167 static HRESULT WINAPI
event_callbacks_LoadModule(IDebugEventCallbacks
*iface
, ULONG64 image_handle
,
168 ULONG64 base_offset
, ULONG module_size
, const char *module_name
, const char *image_name
, ULONG checksum
,
174 static HRESULT WINAPI
event_callbacks_UnloadModule(IDebugEventCallbacks
*iface
, const char *image_basename
,
180 static HRESULT WINAPI
event_callbacks_SystemError(IDebugEventCallbacks
*iface
, ULONG error
, ULONG level
)
185 static HRESULT WINAPI
event_callbacks_SessionStatus(IDebugEventCallbacks
*iface
, ULONG status
)
190 static HRESULT WINAPI
event_callbacks_ChangeDebuggeeState(IDebugEventCallbacks
*iface
, ULONG flags
, ULONG64 argument
)
195 static HRESULT WINAPI
event_callbacks_ChangeEngineState(IDebugEventCallbacks
*iface
, ULONG flags
, ULONG64 argument
)
200 static HRESULT WINAPI
event_callbacks_ChangeSymbolState(IDebugEventCallbacks
*iface
, ULONG flags
, ULONG64 argument
)
206 static const IDebugEventCallbacksVtbl event_callbacks_vtbl
=
208 event_callbacks_QueryInterface
,
209 event_callbacks_AddRef
,
210 event_callbacks_Release
,
211 event_callbacks_GetInterestMask
,
212 event_callbacks_Breakpoint
,
213 event_callbacks_Exception
,
214 event_callbacks_CreateThread
,
215 event_callbacks_ExitThread
,
216 event_callbacks_CreateProcess
,
217 event_callbacks_ExitProcess
,
218 event_callbacks_LoadModule
,
219 event_callbacks_UnloadModule
,
220 event_callbacks_SystemError
,
221 event_callbacks_SessionStatus
,
222 event_callbacks_ChangeDebuggeeState
,
223 event_callbacks_ChangeEngineState
,
224 event_callbacks_ChangeSymbolState
,
227 static BOOL
create_target_process(const char *event_name
, PROCESS_INFORMATION
*info
)
229 static const char *event_target_ready_name
= "dbgeng_test_target_ready_event";
230 char path_name
[MAX_PATH
];
231 STARTUPINFOA startup
;
236 ready_event
= CreateEventA(NULL
, FALSE
, FALSE
, event_target_ready_name
);
237 ok(ready_event
!= NULL
, "Failed to create event.\n");
239 winetest_get_mainargs(&argv
);
240 memset(&startup
, 0, sizeof(startup
));
241 startup
.cb
= sizeof(startup
);
242 sprintf(path_name
, "%s dbgeng target %s %s", argv
[0], event_name
, event_target_ready_name
);
243 ret
= CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, info
);
246 WaitForSingleObject(ready_event
, INFINITE
);
249 CloseHandle(ready_event
);
254 static void test_attach(void)
256 static const char *event_name
= "dbgeng_test_event";
257 IDebugEventCallbacks event_callbacks
= { &event_callbacks_vtbl
};
258 PROCESS_INFORMATION info
;
259 IDebugControl
*control
;
260 IDebugClient
*client
;
266 hr
= DebugCreate(&IID_IDebugClient
, (void **)&client
);
267 ok(hr
== S_OK
, "Failed to create engine object, hr %#x.\n", hr
);
269 hr
= client
->lpVtbl
->QueryInterface(client
, &IID_IDebugControl
, (void **)&control
);
270 ok(hr
== S_OK
, "Failed to get interface pointer, hr %#x.\n", hr
);
272 hr
= client
->lpVtbl
->SetEventCallbacks(client
, &event_callbacks
);
273 ok(hr
== S_OK
, "Failed to set event callbacks, hr %#x.\n", hr
);
275 event
= CreateEventA(NULL
, FALSE
, FALSE
, event_name
);
276 ok(event
!= NULL
, "Failed to create event.\n");
278 ret
= create_target_process(event_name
, &info
);
279 ok(ret
, "Failed to create target process.\n");
282 CheckRemoteDebuggerPresent(info
.hProcess
, &is_debugged
);
283 ok(!is_debugged
, "Unexpected mode.\n");
285 /* Non-invasive mode. */
286 hr
= client
->lpVtbl
->AttachProcess(client
, 0, info
.dwProcessId
, DEBUG_ATTACH_NONINVASIVE
);
287 ok(hr
== S_OK
, "Failed to attach to process, hr %#x.\n", hr
);
290 ret
= CheckRemoteDebuggerPresent(info
.hProcess
, &is_debugged
);
291 ok(ret
, "Failed to check target status.\n");
292 ok(!is_debugged
, "Unexpected mode.\n");
294 hr
= control
->lpVtbl
->WaitForEvent(control
, 0, INFINITE
);
295 ok(hr
== S_OK
, "Waiting for event failed, hr %#x.\n", hr
);
298 ret
= CheckRemoteDebuggerPresent(info
.hProcess
, &is_debugged
);
299 ok(ret
, "Failed to check target status.\n");
300 ok(!is_debugged
, "Unexpected mode.\n");
302 hr
= client
->lpVtbl
->DetachProcesses(client
);
303 ok(hr
== S_OK
, "Failed to detach, hr %#x.\n", hr
);
305 hr
= client
->lpVtbl
->EndSession(client
, DEBUG_END_ACTIVE_DETACH
);
307 ok(hr
== S_OK
, "Failed to end session, hr %#x.\n", hr
);
311 wait_child_process(info
.hProcess
);
313 CloseHandle(info
.hProcess
);
314 CloseHandle(info
.hThread
);
318 client
->lpVtbl
->Release(client
);
319 control
->lpVtbl
->Release(control
);
322 static void test_module_information(void)
324 static const char *event_name
= "dbgeng_test_event";
325 unsigned int loaded
, unloaded
, index
, length
;
326 DEBUG_MODULE_PARAMETERS params
[2];
327 IDebugDataSpaces
*dataspaces
;
328 PROCESS_INFORMATION info
;
329 IDebugSymbols2
*symbols
;
330 IDebugControl
*control
;
331 ULONG64 bases
[2], base
;
332 char buffer
[MAX_PATH
];
333 IDebugClient
*client
;
338 hr
= DebugCreate(&IID_IDebugClient
, (void **)&client
);
339 ok(hr
== S_OK
, "Failed to create engine object, hr %#x.\n", hr
);
341 hr
= client
->lpVtbl
->QueryInterface(client
, &IID_IDebugControl
, (void **)&control
);
342 ok(hr
== S_OK
, "Failed to get interface pointer, hr %#x.\n", hr
);
344 hr
= client
->lpVtbl
->QueryInterface(client
, &IID_IDebugSymbols2
, (void **)&symbols
);
345 ok(hr
== S_OK
, "Failed to get interface pointer, hr %#x.\n", hr
);
347 hr
= client
->lpVtbl
->QueryInterface(client
, &IID_IDebugDataSpaces
, (void **)&dataspaces
);
348 ok(hr
== S_OK
, "Failed to get interface pointer, hr %#x.\n", hr
);
350 hr
= control
->lpVtbl
->IsPointer64Bit(control
);
351 ok(hr
== E_UNEXPECTED
, "Unexpected hr %#x.\n", hr
);
353 event
= CreateEventA(NULL
, FALSE
, FALSE
, event_name
);
354 ok(event
!= NULL
, "Failed to create event.\n");
356 ret
= create_target_process(event_name
, &info
);
357 ok(ret
, "Failed to create target process.\n");
359 hr
= control
->lpVtbl
->SetEngineOptions(control
, DEBUG_ENGOPT_INITIAL_BREAK
);
360 ok(hr
== S_OK
, "Failed to set engine options, hr %#x.\n", hr
);
362 hr
= client
->lpVtbl
->AttachProcess(client
, 0, info
.dwProcessId
, DEBUG_ATTACH_NONINVASIVE
);
363 ok(hr
== S_OK
, "Failed to attach to process, hr %#x.\n", hr
);
365 hr
= control
->lpVtbl
->IsPointer64Bit(control
);
366 ok(hr
== E_UNEXPECTED
, "Unexpected hr %#x.\n", hr
);
368 hr
= control
->lpVtbl
->WaitForEvent(control
, 0, INFINITE
);
369 ok(hr
== S_OK
, "Waiting for event failed, hr %#x.\n", hr
);
371 hr
= control
->lpVtbl
->IsPointer64Bit(control
);
372 ok(SUCCEEDED(hr
), "Failed to get pointer length, hr %#x.\n", hr
);
374 /* Number of modules. */
375 hr
= symbols
->lpVtbl
->GetNumberModules(symbols
, &loaded
, &unloaded
);
376 ok(hr
== S_OK
, "Unexpected hr %#x.\n", hr
);
377 ok(loaded
> 0, "Unexpected module count %u.\n", loaded
);
380 hr
= symbols
->lpVtbl
->GetModuleByIndex(symbols
, loaded
, &base
);
381 ok(FAILED(hr
), "Unexpected hr %#x.\n", hr
);
384 hr
= symbols
->lpVtbl
->GetModuleByIndex(symbols
, 0, &base
);
385 ok(hr
== S_OK
, "Unexpected hr %#x.\n", hr
);
386 ok(!!base
, "Unexpected module base.\n");
388 hr
= symbols
->lpVtbl
->GetModuleByOffset(symbols
, 0, 0, &index
, &base
);
389 ok(FAILED(hr
), "Unexpected hr %#x.\n", hr
);
391 hr
= symbols
->lpVtbl
->GetModuleByOffset(symbols
, base
, 0, &index
, &base
);
392 ok(hr
== S_OK
, "Failed to get module, hr %#x.\n", hr
);
394 hr
= symbols
->lpVtbl
->GetModuleByOffset(symbols
, base
, 0, NULL
, NULL
);
395 ok(hr
== S_OK
, "Failed to get module, hr %#x.\n", hr
);
397 hr
= symbols
->lpVtbl
->GetModuleByOffset(symbols
, base
+ 1, 0, NULL
, NULL
);
398 ok(hr
== S_OK
, "Failed to get module, hr %#x.\n", hr
);
400 hr
= symbols
->lpVtbl
->GetModuleByOffset(symbols
, base
, loaded
, NULL
, NULL
);
401 ok(FAILED(hr
), "Unexpected hr %#x.\n", hr
);
405 hr
= symbols
->lpVtbl
->GetModuleByIndex(symbols
, 0, &base
);
406 ok(hr
== S_OK
, "Unexpected hr %#x.\n", hr
);
407 ok(!!base
, "Unexpected module base.\n");
409 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 1, NULL
, 0, params
);
410 ok(hr
== S_OK
, "Failed to get module parameters, hr %#x.\n", hr
);
411 ok(params
[0].Base
== base
, "Unexpected module base.\n");
413 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 1, &base
, 100, params
);
414 ok(hr
== S_OK
, "Failed to get module parameters, hr %#x.\n", hr
);
415 ok(params
[0].Base
== base
, "Unexpected module base.\n");
419 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 2, bases
, 0, params
);
420 ok(hr
== S_OK
|| broken(hr
== E_NOINTERFACE
) /* XP */, "Failed to get module parameters, hr %#x.\n", hr
);
421 ok(params
[0].Base
== DEBUG_INVALID_OFFSET
, "Unexpected module base.\n");
422 ok(params
[0].Size
== 0, "Unexpected module size.\n");
423 ok(params
[1].Base
== base
, "Unexpected module base.\n");
424 ok(params
[1].Size
!= 0, "Unexpected module size.\n");
426 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 1, bases
, 0, params
);
427 ok(hr
== S_OK
|| broken(hr
== E_NOINTERFACE
) /* XP */, "Failed to get module parameters, hr %#x.\n", hr
);
429 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 1, bases
, loaded
, params
);
430 ok(hr
== S_OK
|| broken(hr
== E_NOINTERFACE
) /* XP */, "Failed to get module parameters, hr %#x.\n", hr
);
432 hr
= symbols
->lpVtbl
->GetModuleParameters(symbols
, 1, NULL
, loaded
, params
);
433 ok(FAILED(hr
), "Unexpected hr %#x.\n", hr
);
436 hr
= symbols
->lpVtbl
->GetModuleNameString(symbols
, DEBUG_MODNAME_IMAGE
, 0, 0, buffer
, sizeof(buffer
), &length
);
437 ok(hr
== S_OK
, "Failed to get image name, hr %#x.\n", hr
);
438 ok(strlen(buffer
) + 1 == length
, "Unexpected length.\n");
440 hr
= symbols
->lpVtbl
->GetModuleNameString(symbols
, DEBUG_MODNAME_IMAGE
, 0, 0, NULL
, sizeof(buffer
), &length
);
441 ok(hr
== S_OK
, "Failed to get image name, hr %#x.\n", hr
);
442 ok(length
> 0, "Unexpected length.\n");
444 hr
= symbols
->lpVtbl
->GetModuleNameString(symbols
, DEBUG_MODNAME_IMAGE
, DEBUG_ANY_ID
, base
, buffer
, sizeof(buffer
),
446 ok(hr
== S_OK
, "Failed to get image name, hr %#x.\n", hr
);
447 ok(strlen(buffer
) + 1 == length
, "Unexpected length.\n");
449 hr
= symbols
->lpVtbl
->GetModuleNameString(symbols
, DEBUG_MODNAME_IMAGE
, 0, 0, buffer
, length
- 1, &length
);
450 ok(hr
== S_FALSE
, "Failed to get image name, hr %#x.\n", hr
);
451 ok(strlen(buffer
) + 2 == length
, "Unexpected length %u.\n", length
);
453 hr
= symbols
->lpVtbl
->GetModuleNameString(symbols
, DEBUG_MODNAME_IMAGE
, 0, 0, NULL
, length
- 1, NULL
);
454 ok(hr
== S_FALSE
, "Failed to get image name, hr %#x.\n", hr
);
458 hr
= symbols
->lpVtbl
->GetModuleByIndex(symbols
, 0, &base
);
459 ok(hr
== S_OK
, "Unexpected hr %#x.\n", hr
);
460 ok(!!base
, "Unexpected module base.\n");
462 hr
= dataspaces
->lpVtbl
->ReadVirtual(dataspaces
, base
, buffer
, sizeof(buffer
), &length
);
463 ok(hr
== S_OK
, "Failed to read process memory, hr %#x.\n", hr
);
464 ok(length
== sizeof(buffer
), "Unexpected length %u.\n", length
);
465 ok(buffer
[0] == 'M' && buffer
[1] == 'Z', "Unexpected contents.\n");
467 memset(buffer
, 0, sizeof(buffer
));
468 hr
= dataspaces
->lpVtbl
->ReadVirtual(dataspaces
, base
, buffer
, sizeof(buffer
), NULL
);
469 ok(hr
== S_OK
, "Failed to read process memory, hr %#x.\n", hr
);
470 ok(buffer
[0] == 'M' && buffer
[1] == 'Z', "Unexpected contents.\n");
472 hr
= client
->lpVtbl
->DetachProcesses(client
);
473 ok(hr
== S_OK
, "Failed to detach, hr %#x.\n", hr
);
476 wait_child_process(info
.hProcess
);
478 CloseHandle(info
.hProcess
);
479 CloseHandle(info
.hThread
);
482 client
->lpVtbl
->Release(client
);
483 control
->lpVtbl
->Release(control
);
484 symbols
->lpVtbl
->Release(symbols
);
485 dataspaces
->lpVtbl
->Release(dataspaces
);
488 static void target_proc(const char *event_name
, const char *event_ready_name
)
490 HANDLE terminate_event
, ready_event
;
492 terminate_event
= OpenEventA(SYNCHRONIZE
, FALSE
, event_name
);
493 ok(terminate_event
!= NULL
, "Failed to open event handle.\n");
495 ready_event
= OpenEventA(EVENT_MODIFY_STATE
, FALSE
, event_ready_name
);
496 ok(ready_event
!= NULL
, "Failed to open event handle.\n");
498 SetEvent(ready_event
);
502 if (WaitForSingleObject(terminate_event
, 100) == WAIT_OBJECT_0
)
506 CloseHandle(terminate_event
);
507 CloseHandle(ready_event
);
515 argc
= winetest_get_mainargs(&argv
);
517 if (argc
> 4 && !strcmp(argv
[2], "target"))
519 target_proc(argv
[3], argv
[4]);
523 test_engine_options();
525 test_module_information();