Signed-off-by: Nikolay Sivov nsivov@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(); }