dbgeng: Keep a list of processes to attach to.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f1562cfd55
commit
8f3e72edd9
|
@ -31,9 +31,17 @@
|
|||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/heap.h"
|
||||
#include "wine/list.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbgeng);
|
||||
|
||||
struct target_process
|
||||
{
|
||||
struct list entry;
|
||||
unsigned int pid;
|
||||
unsigned int attach_flags;
|
||||
};
|
||||
|
||||
struct debug_client
|
||||
{
|
||||
IDebugClient IDebugClient_iface;
|
||||
|
@ -42,6 +50,7 @@ struct debug_client
|
|||
IDebugControl2 IDebugControl2_iface;
|
||||
LONG refcount;
|
||||
ULONG engine_options;
|
||||
struct list targets;
|
||||
};
|
||||
|
||||
static struct debug_client *impl_from_IDebugClient(IDebugClient *iface)
|
||||
|
@ -113,11 +122,19 @@ static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface)
|
|||
{
|
||||
struct debug_client *debug_client = impl_from_IDebugClient(iface);
|
||||
ULONG refcount = InterlockedDecrement(&debug_client->refcount);
|
||||
struct target_process *cur, *cur2;
|
||||
|
||||
TRACE("%p, %d.\n", debug_client, refcount);
|
||||
|
||||
if (!refcount)
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &debug_client->targets, struct target_process, entry)
|
||||
{
|
||||
list_remove(&cur->entry);
|
||||
heap_free(cur);
|
||||
}
|
||||
heap_free(debug_client);
|
||||
}
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
@ -195,11 +212,28 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessDescription(IDebug
|
|||
|
||||
static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient *iface, ULONG64 server, ULONG pid, ULONG flags)
|
||||
{
|
||||
FIXME("%p, %s, %u, %#x stub.\n", iface, wine_dbgstr_longlong(server), pid, flags);
|
||||
struct debug_client *debug_client = impl_from_IDebugClient(iface);
|
||||
struct target_process *process;
|
||||
|
||||
TRACE("%p, %s, %u, %#x.\n", iface, wine_dbgstr_longlong(server), pid, flags);
|
||||
|
||||
if (server)
|
||||
{
|
||||
FIXME("Remote debugging is not supported.\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (!(process = heap_alloc(sizeof(*process))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
process->pid = pid;
|
||||
process->attach_flags = flags;
|
||||
|
||||
list_add_head(&debug_client->targets, &process->entry);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess(IDebugClient *iface, ULONG64 server, char *cmdline,
|
||||
ULONG flags)
|
||||
{
|
||||
|
@ -2142,6 +2176,7 @@ HRESULT WINAPI DebugCreate(REFIID riid, void **obj)
|
|||
debug_client->IDebugSymbols_iface.lpVtbl = &debugsymbolsvtbl;
|
||||
debug_client->IDebugControl2_iface.lpVtbl = &debugcontrolvtbl;
|
||||
debug_client->refcount = 1;
|
||||
list_init(&debug_client->targets);
|
||||
|
||||
unk = (IUnknown *)&debug_client->IDebugClient_iface;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "windef.h"
|
||||
|
@ -99,7 +100,237 @@ static void test_engine_options(void)
|
|||
control->lpVtbl->Release(control);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_QueryInterface(IDebugEventCallbacks *iface, REFIID riid, void **out)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IDebugEventCallbacks) ||
|
||||
IsEqualIID(riid, &IID_IUnknown))
|
||||
{
|
||||
*out = iface;
|
||||
iface->lpVtbl->AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*out = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI event_callbacks_AddRef(IDebugEventCallbacks *iface)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI event_callbacks_Release(IDebugEventCallbacks *iface)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_GetInterestMask(IDebugEventCallbacks *iface, ULONG *mask)
|
||||
{
|
||||
*mask = ~0u;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_Breakpoint(IDebugEventCallbacks *iface, PDEBUG_BREAKPOINT breakpoint)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_Exception(IDebugEventCallbacks *iface, EXCEPTION_RECORD64 *exception,
|
||||
ULONG first_chance)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_CreateThread(IDebugEventCallbacks *iface, ULONG64 handle, ULONG64 data_offset,
|
||||
ULONG64 start_offset)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_ExitThread(IDebugEventCallbacks *iface, ULONG exit_code)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_CreateProcess(IDebugEventCallbacks *iface, ULONG64 image_handle, ULONG64 handle,
|
||||
ULONG64 base_offset, ULONG module_size, const char *module_name, const char *image_name, ULONG checksum,
|
||||
ULONG timedatestamp, ULONG64 initial_thread_handle, ULONG64 thread_data_offset, ULONG64 start_offset)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_ExitProcess(IDebugEventCallbacks *iface, ULONG exit_code)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_LoadModule(IDebugEventCallbacks *iface, ULONG64 image_handle,
|
||||
ULONG64 base_offset, ULONG module_size, const char *module_name, const char *image_name, ULONG checksum,
|
||||
ULONG timedatestamp)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_UnloadModule(IDebugEventCallbacks *iface, const char *image_basename,
|
||||
ULONG64 base_offset)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_SystemError(IDebugEventCallbacks *iface, ULONG error, ULONG level)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_SessionStatus(IDebugEventCallbacks *iface, ULONG status)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_ChangeDebuggeeState(IDebugEventCallbacks *iface, ULONG flags, ULONG64 argument)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_ChangeEngineState(IDebugEventCallbacks *iface, ULONG flags, ULONG64 argument)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI event_callbacks_ChangeSymbolState(IDebugEventCallbacks *iface, ULONG flags, ULONG64 argument)
|
||||
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const IDebugEventCallbacksVtbl event_callbacks_vtbl =
|
||||
{
|
||||
event_callbacks_QueryInterface,
|
||||
event_callbacks_AddRef,
|
||||
event_callbacks_Release,
|
||||
event_callbacks_GetInterestMask,
|
||||
event_callbacks_Breakpoint,
|
||||
event_callbacks_Exception,
|
||||
event_callbacks_CreateThread,
|
||||
event_callbacks_ExitThread,
|
||||
event_callbacks_CreateProcess,
|
||||
event_callbacks_ExitProcess,
|
||||
event_callbacks_LoadModule,
|
||||
event_callbacks_UnloadModule,
|
||||
event_callbacks_SystemError,
|
||||
event_callbacks_SessionStatus,
|
||||
event_callbacks_ChangeDebuggeeState,
|
||||
event_callbacks_ChangeEngineState,
|
||||
event_callbacks_ChangeSymbolState,
|
||||
};
|
||||
|
||||
static const char *event_name = "dbgeng_test_event";
|
||||
|
||||
static void test_attach(void)
|
||||
{
|
||||
IDebugEventCallbacks event_callbacks = { &event_callbacks_vtbl };
|
||||
PROCESS_INFORMATION info;
|
||||
char path_name[MAX_PATH];
|
||||
IDebugControl *control;
|
||||
IDebugClient *client;
|
||||
STARTUPINFOA startup;
|
||||
BOOL is_debugged;
|
||||
HANDLE event;
|
||||
char **argv;
|
||||
HRESULT hr;
|
||||
BOOL ret;
|
||||
|
||||
hr = DebugCreate(&IID_IDebugClient, (void **)&client);
|
||||
ok(hr == S_OK, "Failed to create engine object, hr %#x.\n", hr);
|
||||
|
||||
hr = client->lpVtbl->QueryInterface(client, &IID_IDebugControl, (void **)&control);
|
||||
ok(hr == S_OK, "Failed to get interface pointer, hr %#x.\n", hr);
|
||||
|
||||
hr = client->lpVtbl->SetEventCallbacks(client, &event_callbacks);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Failed to set event callbacks, hr %#x.\n", hr);
|
||||
|
||||
event = CreateEventA(NULL, FALSE, FALSE, event_name);
|
||||
ok(event != NULL, "Failed to create event.\n");
|
||||
|
||||
winetest_get_mainargs(&argv);
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
sprintf(path_name, "%s dbgeng target", argv[0]);
|
||||
ret = CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info),
|
||||
ok(ret, "Failed to create target process.\n");
|
||||
|
||||
is_debugged = TRUE;
|
||||
CheckRemoteDebuggerPresent(info.hProcess, &is_debugged);
|
||||
ok(!is_debugged, "Unexpected mode.\n");
|
||||
|
||||
/* Non-invasive mode. */
|
||||
hr = client->lpVtbl->AttachProcess(client, 0, info.dwProcessId, DEBUG_ATTACH_NONINVASIVE);
|
||||
ok(hr == S_OK, "Failed to attach to process, hr %#x.\n", hr);
|
||||
|
||||
is_debugged = TRUE;
|
||||
ret = CheckRemoteDebuggerPresent(info.hProcess, &is_debugged);
|
||||
ok(ret, "Failed to check target status.\n");
|
||||
ok(!is_debugged, "Unexpected mode.\n");
|
||||
|
||||
hr = control->lpVtbl->WaitForEvent(control, 0, INFINITE);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Waiting for event failed, hr %#x.\n", hr);
|
||||
|
||||
is_debugged = TRUE;
|
||||
ret = CheckRemoteDebuggerPresent(info.hProcess, &is_debugged);
|
||||
ok(ret, "Failed to check target status.\n");
|
||||
ok(!is_debugged, "Unexpected mode.\n");
|
||||
|
||||
hr = client->lpVtbl->DetachProcesses(client);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Failed to detach, hr %#x.\n", hr);
|
||||
|
||||
hr = client->lpVtbl->EndSession(client, DEBUG_END_ACTIVE_DETACH);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Failed to end session, hr %#x.\n", hr);
|
||||
|
||||
SetEvent(event);
|
||||
|
||||
winetest_wait_child_process(info.hProcess);
|
||||
|
||||
CloseHandle(info.hProcess);
|
||||
CloseHandle(info.hThread);
|
||||
|
||||
CloseHandle(event);
|
||||
|
||||
client->lpVtbl->Release(client);
|
||||
control->lpVtbl->Release(control);
|
||||
}
|
||||
|
||||
static void target_proc(void)
|
||||
{
|
||||
HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, event_name);
|
||||
|
||||
ok(event != NULL, "Failed to open event handle.\n");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0)
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
START_TEST(dbgeng)
|
||||
{
|
||||
test_engine_options();
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
argc = winetest_get_mainargs(&argv);
|
||||
|
||||
if (argc >= 3 && !strcmp(argv[2], "target"))
|
||||
{
|
||||
target_proc();
|
||||
return;
|
||||
}
|
||||
|
||||
test_engine_options();
|
||||
test_attach();
|
||||
}
|
||||
|
|
|
@ -73,6 +73,95 @@ DEFINE_GUID(IID_IDebugSystemObjects3, 0xe9676e2f, 0xe286, 0x4ea3, 0xb0, 0xf9
|
|||
#define DEBUG_ATTACH_INVASIVE_RESUME_PROCESS 0x00000010
|
||||
#define DEBUG_ATTACH_NONINVASIVE_ALLOW_PARTIAL 0x00000020
|
||||
|
||||
/* EndSession() flags */
|
||||
#define DEBUG_END_PASSIVE 0x00000000
|
||||
#define DEBUG_END_ACTIVE_TERMINATE 0x00000001
|
||||
#define DEBUG_END_ACTIVE_DETACH 0x00000002
|
||||
#define DEBUG_END_REENTRANT 0x00000003
|
||||
#define DEBUG_END_DISCONNECT 0x00000004
|
||||
|
||||
/* ChangeEngineState() flags */
|
||||
#define DEBUG_CES_CURRENT_THREAD 0x00000001
|
||||
#define DEBUG_CES_EFFECTIVE_PROCESSOR 0x00000002
|
||||
#define DEBUG_CES_BREAKPOINTS 0x00000004
|
||||
#define DEBUG_CES_CODE_LEVEL 0x00000008
|
||||
#define DEBUG_CES_EXECUTION_STATUS 0x00000010
|
||||
#define DEBUG_CES_ENGINE_OPTIONS 0x00000020
|
||||
#define DEBUG_CES_LOG_FILE 0x00000040
|
||||
#define DEBUG_CES_RADIX 0x00000080
|
||||
#define DEBUG_CES_EVENT_FILTERS 0x00000100
|
||||
#define DEBUG_CES_PROCESS_OPTIONS 0x00000200
|
||||
#define DEBUG_CES_EXTENSIONS 0x00000400
|
||||
#define DEBUG_CES_SYSTEMS 0x00000800
|
||||
#define DEBUG_CES_ASSEMBLY_OPTIONS 0x00001000
|
||||
#define DEBUG_CES_EXPRESSION_SYNTAX 0x00002000
|
||||
#define DEBUG_CES_TEXT_REPLACEMENTS 0x00004000
|
||||
#define DEBUG_CES_ALL 0xffffffff
|
||||
|
||||
#define DEBUG_STATUS_NO_CHANGE 0
|
||||
#define DEBUG_STATUS_GO 1
|
||||
#define DEBUG_STATUS_GO_HANDLED 2
|
||||
#define DEBUG_STATUS_GO_NOT_HANDLED 3
|
||||
#define DEBUG_STATUS_STEP_OVER 4
|
||||
#define DEBUG_STATUS_STEP_INTO 5
|
||||
#define DEBUG_STATUS_BREAK 6
|
||||
#define DEBUG_STATUS_NO_DEBUGGEE 7
|
||||
#define DEBUG_STATUS_STEP_BRANCH 8
|
||||
#define DEBUG_STATUS_IGNORE_EVENT 9
|
||||
#define DEBUG_STATUS_RESTART_REQUESTED 10
|
||||
#define DEBUG_STATUS_REVERSE_GO 11
|
||||
#define DEBUG_STATUS_REVERSE_STEP_BRANCH 12
|
||||
#define DEBUG_STATUS_REVERSE_STEP_OVER 13
|
||||
#define DEBUG_STATUS_REVERSE_STEP_INTO 14
|
||||
#define DEBUG_STATUS_OUT_OF_SYNC 15
|
||||
#define DEBUG_STATUS_WAIT_INPUT 16
|
||||
#define DEBUG_STATUS_TIMEOUT 17
|
||||
#define DEBUG_STATUS_MASK 0x1f
|
||||
|
||||
/* ChangeSymbolState() flags */
|
||||
#define DEBUG_CSS_LOADS 0x00000001
|
||||
#define DEBUG_CSS_UNLOADS 0x00000002
|
||||
#define DEBUG_CSS_SCOPE 0x00000004
|
||||
#define DEBUG_CSS_PATHS 0x00000008
|
||||
#define DEBUG_CSS_SYMBOL_OPTIONS 0x00000010
|
||||
#define DEBUG_CSS_TYPE_OPTIONS 0x00000020
|
||||
#define DEBUG_CSS_COLLAPSE_CHILDREN 0x00000040
|
||||
#define DEBUG_CSS_ALL 0xffffffff
|
||||
|
||||
/* SessionStatus() flags */
|
||||
#define DEBUG_SESSION_ACTIVE 0x00000000
|
||||
#define DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE 0x00000001
|
||||
#define DEBUG_SESSION_END_SESSION_ACTIVE_DETACH 0x00000002
|
||||
#define DEBUG_SESSION_END_SESSION_PASSIVE 0x00000003
|
||||
#define DEBUG_SESSION_END 0x00000004
|
||||
#define DEBUG_SESSION_REBOOT 0x00000005
|
||||
#define DEBUG_SESSION_HIBERNATE 0x00000006
|
||||
#define DEBUG_SESSION_FAILURE 0x00000007
|
||||
|
||||
/* ChangeDebuggeeState() flags */
|
||||
#define DEBUG_CDS_REGISTERS 0x00000001
|
||||
#define DEBUG_CDS_DATA 0x00000002
|
||||
#define DEBUG_CDS_REFRESH 0x00000004
|
||||
#define DEBUG_CDS_ALL 0xffffffff
|
||||
|
||||
#define DEBUG_CDS_REFRESH_EVALUATE 1
|
||||
#define DEBUG_CDS_REFRESH_EXECUTE 2
|
||||
#define DEBUG_CDS_REFRESH_EXECUTECOMMANDFILE 3
|
||||
#define DEBUG_CDS_REFRESH_ADDBREAKPOINT 4
|
||||
#define DEBUG_CDS_REFRESH_REMOVEBREAKPOINT 5
|
||||
#define DEBUG_CDS_REFRESH_WRITEVIRTUAL 6
|
||||
#define DEBUG_CDS_REFRESH_WRITEVIRTUALUNCACHED 7
|
||||
#define DEBUG_CDS_REFRESH_WRITEPHYSICAL 8
|
||||
#define DEBUG_CDS_REFRESH_WRITEPHYSICAL2 9
|
||||
#define DEBUG_CDS_REFRESH_SETVALUE 10
|
||||
#define DEBUG_CDS_REFRESH_SETVALUE2 11
|
||||
#define DEBUG_CDS_REFRESH_SETSCOPE 12
|
||||
#define DEBUG_CDS_REFRESH_SETSCOPEFRAMEBYINDEX 13
|
||||
#define DEBUG_CDS_REFRESH_SETSCOPEFROMJITDEBUGINFO 14
|
||||
#define DEBUG_CDS_REFRESH_SETSCOPEFROMSTOREDEVENT 15
|
||||
#define DEBUG_CDS_REFRESH_INLINESTEP 16
|
||||
#define DEBUG_CDS_REFRESH_INLINESTEP_PSEUDO 17
|
||||
|
||||
typedef struct _DEBUG_MODULE_PARAMETERS
|
||||
{
|
||||
ULONG64 Base;
|
||||
|
|
Loading…
Reference in New Issue