Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dbgeng/dbgeng.c | 74 +++++++++++++++++++++++++++++++++++--- dlls/dbgeng/tests/dbgeng.c | 63 ++++++++++++++++++++++++-------- 2 files changed, 119 insertions(+), 18 deletions(-)
diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c index 077de3be51..d4f8205726 100644 --- a/dlls/dbgeng/dbgeng.c +++ b/dlls/dbgeng/dbgeng.c @@ -39,6 +39,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbgeng); extern NTSTATUS WINAPI NtSuspendProcess(HANDLE handle); extern NTSTATUS WINAPI NtResumeProcess(HANDLE handle);
+struct module_info +{ + DEBUG_MODULE_PARAMETERS params; +}; + struct target_process { struct list entry; @@ -47,6 +52,7 @@ struct target_process HANDLE handle; struct { + struct module_info *info; unsigned int loaded; unsigned int unloaded; BOOL initialized; @@ -75,6 +81,9 @@ static struct target_process *debug_client_get_target(struct debug_client *debug
static HRESULT debug_target_init_modules_info(struct target_process *target) { + unsigned int i, count; + HMODULE *modules; + MODULEINFO info; DWORD needed;
if (target->modules.initialized) @@ -88,7 +97,35 @@ static HRESULT debug_target_init_modules_info(struct target_process *target) if (!needed) return E_FAIL;
- target->modules.loaded = needed / sizeof(HMODULE); + count = needed / sizeof(HMODULE); + + if (!(modules = heap_alloc(count * sizeof(*modules)))) + return E_OUTOFMEMORY; + + if (!(target->modules.info = heap_alloc_zero(count * sizeof(*target->modules.info)))) + { + heap_free(modules); + return E_OUTOFMEMORY; + } + + if (EnumProcessModules(target->handle, modules, count * sizeof(*modules), &needed)) + { + for (i = 0; i < count; ++i) + { + if (!GetModuleInformation(target->handle, modules[i], &info, sizeof(info))) + { + WARN("Failed to get module information, error %d.\n", GetLastError()); + continue; + } + + target->modules.info[i].params.Base = (ULONG_PTR)info.lpBaseOfDll; + target->modules.info[i].params.Size = info.SizeOfImage; + } + } + + heap_free(modules); + + target->modules.loaded = count; target->modules.unloaded = 0; /* FIXME */
target->modules.initialized = TRUE; @@ -96,6 +133,17 @@ static HRESULT debug_target_init_modules_info(struct target_process *target) return S_OK; }
+static const struct module_info *debug_target_get_module_info(struct target_process *target, unsigned int i) +{ + if (FAILED(debug_target_init_modules_info(target))) + return NULL; + + if (i >= target->modules.loaded) + return NULL; + + return &target->modules.info[i]; +} + static void debug_client_detach_target(struct target_process *target) { NTSTATUS status; @@ -185,6 +233,12 @@ static ULONG STDMETHODCALLTYPE debugclient_AddRef(IDebugClient *iface) return refcount; }
+static void debug_target_free(struct target_process *target) +{ + heap_free(target->modules.info); + heap_free(target); +} + static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface) { struct debug_client *debug_client = impl_from_IDebugClient(iface); @@ -199,7 +253,7 @@ static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface) { debug_client_detach_target(cur); list_remove(&cur->entry); - heap_free(cur); + debug_target_free(cur); } if (debug_client->event_callbacks) debug_client->event_callbacks->lpVtbl->Release(debug_client->event_callbacks); @@ -955,9 +1009,21 @@ static HRESULT STDMETHODCALLTYPE debugsymbols_GetNumberModules(IDebugSymbols3 *i
static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleByIndex(IDebugSymbols3 *iface, ULONG index, ULONG64 *base) { - FIXME("%p, %u, %p stub.\n", iface, index, base); + struct debug_client *debug_client = impl_from_IDebugSymbols3(iface); + const struct module_info *info; + struct target_process *target;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, base); + + if (!(target = debug_client_get_target(debug_client))) + return E_UNEXPECTED; + + if (!(info = debug_target_get_module_info(target, index))) + return E_INVALIDARG; + + *base = info->params.Base; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleByModuleName(IDebugSymbols3 *iface, const char *name, diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c index 6e6e2d3123..74f9e7ceb6 100644 --- a/dlls/dbgeng/tests/dbgeng.c +++ b/dlls/dbgeng/tests/dbgeng.c @@ -224,23 +224,36 @@ static const IDebugEventCallbacksVtbl event_callbacks_vtbl = event_callbacks_ChangeSymbolState, };
-static const char *event_name = "dbgeng_test_event"; - -static BOOL create_target_process(PROCESS_INFORMATION *info) +static BOOL create_target_process(const char *event_name, PROCESS_INFORMATION *info) { + static const char *event_target_ready_name = "dbgeng_test_target_ready_event"; char path_name[MAX_PATH]; STARTUPINFOA startup; + HANDLE ready_event; char **argv; + BOOL ret; + + ready_event = CreateEventA(NULL, FALSE, FALSE, event_target_ready_name); + ok(ready_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]); - return CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, info); + sprintf(path_name, "%s dbgeng target %s %s", argv[0], event_name, event_target_ready_name); + ret = CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, info); + if (ret) + { + WaitForSingleObject(ready_event, INFINITE); + } + + CloseHandle(ready_event); + + return ret; }
static void test_attach(void) { + static const char *event_name = "dbgeng_test_event"; IDebugEventCallbacks event_callbacks = { &event_callbacks_vtbl }; PROCESS_INFORMATION info; IDebugControl *control; @@ -262,7 +275,7 @@ static void test_attach(void) event = CreateEventA(NULL, FALSE, FALSE, event_name); ok(event != NULL, "Failed to create event.\n");
- ret = create_target_process(&info); + ret = create_target_process(event_name, &info); ok(ret, "Failed to create target process.\n");
is_debugged = TRUE; @@ -308,11 +321,13 @@ todo_wine
static void test_module_information(void) { + static const char *event_name = "dbgeng_test_event"; unsigned int loaded, unloaded; PROCESS_INFORMATION info; IDebugSymbols *symbols; IDebugControl *control; IDebugClient *client; + ULONG64 base; HANDLE event; HRESULT hr; BOOL ret; @@ -329,9 +344,12 @@ static void test_module_information(void) event = CreateEventA(NULL, FALSE, FALSE, event_name); ok(event != NULL, "Failed to create event.\n");
- ret = create_target_process(&info); + ret = create_target_process(event_name, &info); ok(ret, "Failed to create target process.\n");
+ hr = control->lpVtbl->SetEngineOptions(control, DEBUG_ENGOPT_INITIAL_BREAK); + ok(hr == S_OK, "Failed to set engine options, hr %#x.\n", hr); + hr = client->lpVtbl->AttachProcess(client, 0, info.dwProcessId, DEBUG_ATTACH_NONINVASIVE); ok(hr == S_OK, "Failed to attach to process, hr %#x.\n", hr);
@@ -341,6 +359,16 @@ static void test_module_information(void) /* Number of modules. */ hr = symbols->lpVtbl->GetNumberModules(symbols, &loaded, &unloaded); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(loaded > 0, "Unexpected module count %u.\n", loaded); + + /* Module base. */ + hr = symbols->lpVtbl->GetModuleByIndex(symbols, loaded, &base); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + + base = 0; + hr = symbols->lpVtbl->GetModuleByIndex(symbols, 0, &base); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!base, "Unexpected module base.\n");
hr = client->lpVtbl->DetachProcesses(client); ok(hr == S_OK, "Failed to detach, hr %#x.\n", hr); @@ -356,19 +384,26 @@ static void test_module_information(void) symbols->lpVtbl->Release(symbols); }
-static void target_proc(void) +static void target_proc(const char *event_name, const char *event_ready_name) { - HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, event_name); + HANDLE terminate_event, ready_event;
- ok(event != NULL, "Failed to open event handle.\n"); + terminate_event = OpenEventA(SYNCHRONIZE, FALSE, event_name); + ok(terminate_event != NULL, "Failed to open event handle.\n"); + + ready_event = OpenEventA(EVENT_MODIFY_STATE, FALSE, event_ready_name); + ok(ready_event != NULL, "Failed to open event handle.\n"); + + SetEvent(ready_event);
for (;;) { - if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0) + if (WaitForSingleObject(terminate_event, 100) == WAIT_OBJECT_0) break; }
- CloseHandle(event); + CloseHandle(terminate_event); + CloseHandle(ready_event); }
START_TEST(dbgeng) @@ -378,9 +413,9 @@ START_TEST(dbgeng)
argc = winetest_get_mainargs(&argv);
- if (argc >= 3 && !strcmp(argv[2], "target")) + if (argc > 4 && !strcmp(argv[2], "target")) { - target_proc(); + target_proc(argv[3], argv[4]); return; }