[PATCH 1/2] dbgeng: Keep a list of processes to attach to.

Nikolay Sivov nsivov at codeweavers.com
Thu Apr 11 08:03:10 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dbgeng/dbgeng.c       |  39 ++++++-
 dlls/dbgeng/tests/dbgeng.c | 231 +++++++++++++++++++++++++++++++++++++
 include/dbgeng.h           |  89 ++++++++++++++
 3 files changed, 357 insertions(+), 2 deletions(-)

diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c
index 75ae4505db..9aed1b0506 100644
--- a/dlls/dbgeng/dbgeng.c
+++ b/dlls/dbgeng/dbgeng.c
@@ -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,9 +212,26 @@ 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;
 
-    return E_NOTIMPL;
+    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,
@@ -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;
 
diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c
index a76b25a128..f5d50c899a 100644
--- a/dlls/dbgeng/tests/dbgeng.c
+++ b/dlls/dbgeng/tests/dbgeng.c
@@ -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)
 {
+    char **argv;
+    int argc;
+
+    argc = winetest_get_mainargs(&argv);
+
+    if (argc >= 3 && !strcmp(argv[2], "target"))
+    {
+        target_proc();
+        return;
+    }
+
     test_engine_options();
+    test_attach();
 }
diff --git a/include/dbgeng.h b/include/dbgeng.h
index 8c5c78c07f..3b7ff2be4f 100644
--- a/include/dbgeng.h
+++ b/include/dbgeng.h
@@ -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;
-- 
2.20.1




More information about the wine-devel mailing list