[PATCH 2/5] dbgeng: Implement GetNumberModules().

Nikolay Sivov nsivov at codeweavers.com
Mon Apr 22 01:42:26 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dbgeng/dbgeng.c       | 63 ++++++++++++++++++++++++++++----
 dlls/dbgeng/tests/dbgeng.c | 73 +++++++++++++++++++++++++++++++++-----
 2 files changed, 121 insertions(+), 15 deletions(-)

diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c
index 8ce7ac656a..077de3be51 100644
--- a/dlls/dbgeng/dbgeng.c
+++ b/dlls/dbgeng/dbgeng.c
@@ -25,6 +25,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winternl.h"
+#include "psapi.h"
 
 #include "initguid.h"
 #include "dbgeng.h"
@@ -44,6 +45,12 @@ struct target_process
     unsigned int pid;
     unsigned int attach_flags;
     HANDLE handle;
+    struct
+    {
+        unsigned int loaded;
+        unsigned int unloaded;
+        BOOL initialized;
+    } modules;
 };
 
 struct debug_client
@@ -58,6 +65,37 @@ struct debug_client
     IDebugEventCallbacks *event_callbacks;
 };
 
+static struct target_process *debug_client_get_target(struct debug_client *debug_client)
+{
+    if (list_empty(&debug_client->targets))
+        return NULL;
+
+    return LIST_ENTRY(list_head(&debug_client->targets), struct target_process, entry);
+}
+
+static HRESULT debug_target_init_modules_info(struct target_process *target)
+{
+    DWORD needed;
+
+    if (target->modules.initialized)
+        return S_OK;
+
+    if (!target->handle)
+        return E_UNEXPECTED;
+
+    needed = 0;
+    EnumProcessModules(target->handle, NULL, 0, &needed);
+    if (!needed)
+        return E_FAIL;
+
+    target->modules.loaded = needed / sizeof(HMODULE);
+    target->modules.unloaded = 0; /* FIXME */
+
+    target->modules.initialized = TRUE;
+
+    return S_OK;
+}
+
 static void debug_client_detach_target(struct target_process *target)
 {
     NTSTATUS status;
@@ -255,7 +293,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient *iface,
         return E_NOTIMPL;
     }
 
-    if (!(process = heap_alloc(sizeof(*process))))
+    if (!(process = heap_alloc_zero(sizeof(*process))))
         return E_OUTOFMEMORY;
 
     process->pid = pid;
@@ -897,9 +935,22 @@ static HRESULT STDMETHODCALLTYPE debugsymbols_GetOffsetByLine(IDebugSymbols3 *if
 
 static HRESULT STDMETHODCALLTYPE debugsymbols_GetNumberModules(IDebugSymbols3 *iface, ULONG *loaded, ULONG *unloaded)
 {
-    FIXME("%p, %p, %p stub.\n", iface, loaded, unloaded);
+    struct debug_client *debug_client = impl_from_IDebugSymbols3(iface);
+    static struct target_process *target;
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p.\n", iface, loaded, unloaded);
+
+    if (!(target = debug_client_get_target(debug_client)))
+        return E_UNEXPECTED;
+
+    if (FAILED(hr = debug_target_init_modules_info(target)))
+        return hr;
+
+    *loaded = target->modules.loaded;
+    *unloaded = target->modules.unloaded;
+
+    return S_OK;
 }
 
 static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleByIndex(IDebugSymbols3 *iface, ULONG index, ULONG64 *base)
@@ -2679,15 +2730,13 @@ static HRESULT STDMETHODCALLTYPE debugcontrol_WaitForEvent(IDebugControl2 *iface
 
     /* FIXME: only one target is used currently */
 
-    if (list_empty(&debug_client->targets))
+    if (!(target = debug_client_get_target(debug_client)))
         return E_UNEXPECTED;
 
-    target = LIST_ENTRY(list_head(&debug_client->targets), struct target_process, entry);
-
     if (target->attach_flags & DEBUG_ATTACH_NONINVASIVE)
     {
         BOOL suspend = !(target->attach_flags & DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND);
-        DWORD access = PROCESS_VM_READ | PROCESS_VM_WRITE;
+        DWORD access = PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_LIMITED_INFORMATION;
         NTSTATUS status;
 
         if (suspend)
diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c
index 650ab4abae..6e6e2d3123 100644
--- a/dlls/dbgeng/tests/dbgeng.c
+++ b/dlls/dbgeng/tests/dbgeng.c
@@ -226,17 +226,27 @@ static const IDebugEventCallbacksVtbl event_callbacks_vtbl =
 
 static const char *event_name = "dbgeng_test_event";
 
+static BOOL create_target_process(PROCESS_INFORMATION *info)
+{
+    char path_name[MAX_PATH];
+    STARTUPINFOA startup;
+    char **argv;
+
+    winetest_get_mainargs(&argv);
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    sprintf(path_name, "%s dbgeng target", argv[0]);
+    return CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, info);
+}
+
 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;
 
@@ -252,11 +262,7 @@ static void test_attach(void)
     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),
+    ret = create_target_process(&info);
     ok(ret, "Failed to create target process.\n");
 
     is_debugged = TRUE;
@@ -300,6 +306,56 @@ todo_wine
     control->lpVtbl->Release(control);
 }
 
+static void test_module_information(void)
+{
+    unsigned int loaded, unloaded;
+    PROCESS_INFORMATION info;
+    IDebugSymbols *symbols;
+    IDebugControl *control;
+    IDebugClient *client;
+    HANDLE event;
+    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->QueryInterface(client, &IID_IDebugSymbols, (void **)&symbols);
+    ok(hr == S_OK, "Failed to get interface pointer, hr %#x.\n", hr);
+
+    event = CreateEventA(NULL, FALSE, FALSE, event_name);
+    ok(event != NULL, "Failed to create event.\n");
+
+    ret = create_target_process(&info);
+    ok(ret, "Failed to create target process.\n");
+
+    hr = client->lpVtbl->AttachProcess(client, 0, info.dwProcessId, DEBUG_ATTACH_NONINVASIVE);
+    ok(hr == S_OK, "Failed to attach to process, hr %#x.\n", hr);
+
+    hr = control->lpVtbl->WaitForEvent(control, 0, INFINITE);
+    ok(hr == S_OK, "Waiting for event failed, hr %#x.\n", hr);
+
+    /* Number of modules. */
+    hr = symbols->lpVtbl->GetNumberModules(symbols, &loaded, &unloaded);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = client->lpVtbl->DetachProcesses(client);
+    ok(hr == S_OK, "Failed to detach, hr %#x.\n", hr);
+
+    SetEvent(event);
+    winetest_wait_child_process(info.hProcess);
+
+    CloseHandle(info.hProcess);
+    CloseHandle(info.hThread);
+
+    client->lpVtbl->Release(client);
+    control->lpVtbl->Release(control);
+    symbols->lpVtbl->Release(symbols);
+}
+
 static void target_proc(void)
 {
     HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, event_name);
@@ -330,4 +386,5 @@ START_TEST(dbgeng)
 
     test_engine_options();
     test_attach();
+    test_module_information();
 }
-- 
2.20.1




More information about the wine-devel mailing list