[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