Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dbgeng/dbgeng.c | 81 ++++++++++++++++++++++++++++++++++++-- dlls/dbgeng/tests/dbgeng.c | 2 - 2 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c index c54d13f6cd..8ce7ac656a 100644 --- a/dlls/dbgeng/dbgeng.c +++ b/dlls/dbgeng/dbgeng.c @@ -35,11 +35,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(dbgeng);
+extern NTSTATUS WINAPI NtSuspendProcess(HANDLE handle); +extern NTSTATUS WINAPI NtResumeProcess(HANDLE handle); + struct target_process { struct list entry; unsigned int pid; unsigned int attach_flags; + HANDLE handle; };
struct debug_client @@ -54,6 +58,28 @@ struct debug_client IDebugEventCallbacks *event_callbacks; };
+static void debug_client_detach_target(struct target_process *target) +{ + NTSTATUS status; + + if (!target->handle) + return; + + if (target->attach_flags & DEBUG_ATTACH_NONINVASIVE) + { + BOOL resume = !(target->attach_flags & DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND); + + if (resume) + { + if ((status = NtResumeProcess(target->handle))) + WARN("Failed to resume process, status %#x.\n", status); + } + } + + CloseHandle(target->handle); + target->handle = NULL; +} + static struct debug_client *impl_from_IDebugClient(IDebugClient *iface) { return CONTAINING_RECORD(iface, struct debug_client, IDebugClient_iface); @@ -133,6 +159,7 @@ static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface) { LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &debug_client->targets, struct target_process, entry) { + debug_client_detach_target(cur); list_remove(&cur->entry); heap_free(cur); } @@ -329,9 +356,17 @@ static HRESULT STDMETHODCALLTYPE debugclient_TerminateProcesses(IDebugClient *if
static HRESULT STDMETHODCALLTYPE debugclient_DetachProcesses(IDebugClient *iface) { - FIXME("%p stub.\n", iface); + struct debug_client *debug_client = impl_from_IDebugClient(iface); + struct target_process *target;
- return E_NOTIMPL; + TRACE("%p.\n", iface); + + LIST_FOR_EACH_ENTRY(target, &debug_client->targets, struct target_process, entry) + { + debug_client_detach_target(target); + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE debugclient_EndSession(IDebugClient *iface, ULONG flags) @@ -2637,7 +2672,47 @@ static HRESULT STDMETHODCALLTYPE debugcontrol_SetExceptionFilterSecondCommand(ID
static HRESULT STDMETHODCALLTYPE debugcontrol_WaitForEvent(IDebugControl2 *iface, ULONG flags, ULONG timeout) { - FIXME("%p, %#x, %u stub.\n", iface, flags, timeout); + struct debug_client *debug_client = impl_from_IDebugControl2(iface); + struct target_process *target; + + TRACE("%p, %#x, %u.\n", iface, flags, timeout); + + /* FIXME: only one target is used currently */ + + if (list_empty(&debug_client->targets)) + 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; + NTSTATUS status; + + if (suspend) + access |= PROCESS_SUSPEND_RESUME; + + target->handle = OpenProcess(access, FALSE, target->pid); + if (!target->handle) + { + WARN("Failed to get process handle for pid %#x.\n", target->pid); + return E_UNEXPECTED; + } + + if (suspend) + { + status = NtSuspendProcess(target->handle); + if (status) + WARN("Failed to suspend a process, status %#x.\n", status); + } + + return S_OK; + } + else + { + FIXME("Unsupported attach flags %#x.\n", target->attach_flags); + }
return E_NOTIMPL; } diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c index baec60a9c9..650ab4abae 100644 --- a/dlls/dbgeng/tests/dbgeng.c +++ b/dlls/dbgeng/tests/dbgeng.c @@ -273,7 +273,6 @@ static void test_attach(void) 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; @@ -282,7 +281,6 @@ todo_wine 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);
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(); }
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; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dbgeng/dbgeng.c | 55 +++++++++++++++++++++++++++++++++++--- dlls/dbgeng/tests/dbgeng.c | 29 ++++++++++++++++++++ include/dbgeng.h | 2 ++ 3 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c index d4f8205726..b5650d8679 100644 --- a/dlls/dbgeng/dbgeng.c +++ b/dlls/dbgeng/dbgeng.c @@ -144,6 +144,22 @@ static const struct module_info *debug_target_get_module_info(struct target_proc return &target->modules.info[i]; }
+static const struct module_info *debug_target_get_module_info_by_base(struct target_process *target, ULONG64 base) +{ + unsigned int i; + + if (FAILED(debug_target_init_modules_info(target))) + return NULL; + + for (i = 0; i < target->modules.loaded; ++i) + { + if (target->modules.info[i].params.Base == base) + return &target->modules.info[i]; + } + + return NULL; +} + static void debug_client_detach_target(struct target_process *target) { NTSTATUS status; @@ -1055,11 +1071,44 @@ static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleNames(IDebugSymbols3 *ifa }
static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleParameters(IDebugSymbols3 *iface, ULONG count, ULONG64 *bases, - ULONG start, DEBUG_MODULE_PARAMETERS *parameters) + ULONG start, DEBUG_MODULE_PARAMETERS *params) { - FIXME("%p, %u, %p, %u, %p stub.\n", iface, count, bases, start, parameters); + struct debug_client *debug_client = impl_from_IDebugSymbols3(iface); + const struct module_info *info; + struct target_process *target; + unsigned int i;
- return E_NOTIMPL; + TRACE("%p, %u, %p, %u, %p.\n", iface, count, bases, start, params); + + if (!(target = debug_client_get_target(debug_client))) + return E_UNEXPECTED; + + if (bases) + { + for (i = 0; i < count; ++i) + { + if ((info = debug_target_get_module_info_by_base(target, bases[i]))) + { + params[i] = info->params; + } + else + { + memset(¶ms[i], 0, sizeof(*params)); + params[i].Base = DEBUG_INVALID_OFFSET; + } + } + } + else + { + for (i = start; i < start + count; ++i) + { + if (!(info = debug_target_get_module_info(target, i))) + return E_INVALIDARG; + params[i] = info->params; + } + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE debugsymbols_GetSymbolModule(IDebugSymbols3 *iface, const char *symbol, ULONG64 *base) diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c index 74f9e7ceb6..2002beb37f 100644 --- a/dlls/dbgeng/tests/dbgeng.c +++ b/dlls/dbgeng/tests/dbgeng.c @@ -322,11 +322,13 @@ todo_wine static void test_module_information(void) { static const char *event_name = "dbgeng_test_event"; + DEBUG_MODULE_PARAMETERS params[2]; unsigned int loaded, unloaded; PROCESS_INFORMATION info; IDebugSymbols *symbols; IDebugControl *control; IDebugClient *client; + ULONG64 bases[2]; ULONG64 base; HANDLE event; HRESULT hr; @@ -370,6 +372,33 @@ static void test_module_information(void) ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!!base, "Unexpected module base.\n");
+ /* Parameters. */ + hr = symbols->lpVtbl->GetModuleParameters(symbols, 1, NULL, 0, params); + ok(hr == S_OK, "Failed to get module parameters, hr %#x.\n", hr); + ok(params[0].Base == base, "Unexpected module base.\n"); + + hr = symbols->lpVtbl->GetModuleParameters(symbols, 1, &base, 100, params); + ok(hr == S_OK, "Failed to get module parameters, hr %#x.\n", hr); + ok(params[0].Base == base, "Unexpected module base.\n"); + + bases[0] = base + 1; + bases[1] = base; + hr = symbols->lpVtbl->GetModuleParameters(symbols, 2, bases, 0, params); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* XP */, "Failed to get module parameters, hr %#x.\n", hr); + ok(params[0].Base == DEBUG_INVALID_OFFSET, "Unexpected module base.\n"); + ok(params[0].Size == 0, "Unexpected module size.\n"); + ok(params[1].Base == base, "Unexpected module base.\n"); + ok(params[1].Size != 0, "Unexpected module size.\n"); + + hr = symbols->lpVtbl->GetModuleParameters(symbols, 1, bases, 0, params); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* XP */, "Failed to get module parameters, hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleParameters(symbols, 1, bases, loaded, params); + ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* XP */, "Failed to get module parameters, hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleParameters(symbols, 1, NULL, loaded, params); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + hr = client->lpVtbl->DetachProcesses(client); ok(hr == S_OK, "Failed to detach, hr %#x.\n", hr);
diff --git a/include/dbgeng.h b/include/dbgeng.h index 3b7ff2be4f..f50a1ca21d 100644 --- a/include/dbgeng.h +++ b/include/dbgeng.h @@ -162,6 +162,8 @@ DEFINE_GUID(IID_IDebugSystemObjects3, 0xe9676e2f, 0xe286, 0x4ea3, 0xb0, 0xf9 #define DEBUG_CDS_REFRESH_INLINESTEP 16 #define DEBUG_CDS_REFRESH_INLINESTEP_PSEUDO 17
+#define DEBUG_INVALID_OFFSET ((ULONG64)-1) + typedef struct _DEBUG_MODULE_PARAMETERS { ULONG64 Base;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dbgeng/dbgeng.c | 25 +++++++++++++++++++++++-- dlls/dbgeng/tests/dbgeng.c | 22 +++++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c index b5650d8679..1acfe0b318 100644 --- a/dlls/dbgeng/dbgeng.c +++ b/dlls/dbgeng/dbgeng.c @@ -1053,9 +1053,30 @@ static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleByModuleName(IDebugSymbol static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleByOffset(IDebugSymbols3 *iface, ULONG64 offset, ULONG start_index, ULONG *index, ULONG64 *base) { - FIXME("%p, %s, %u, %p, %p stub.\n", iface, wine_dbgstr_longlong(offset), start_index, index, base); + struct debug_client *debug_client = impl_from_IDebugSymbols3(iface); + static struct target_process *target; + const struct module_info *info;
- return E_NOTIMPL; + TRACE("%p, %s, %u, %p, %p.\n", iface, wine_dbgstr_longlong(offset), start_index, index, base); + + if (!(target = debug_client_get_target(debug_client))) + return E_UNEXPECTED; + + while ((info = debug_target_get_module_info(target, start_index))) + { + if (offset >= info->params.Base && offset < info->params.Base + info->params.Size) + { + if (index) + *index = start_index; + if (base) + *base = info->params.Base; + return S_OK; + } + + start_index++; + } + + return E_INVALIDARG; }
static HRESULT STDMETHODCALLTYPE debugsymbols_GetModuleNames(IDebugSymbols3 *iface, ULONG index, ULONG64 base, diff --git a/dlls/dbgeng/tests/dbgeng.c b/dlls/dbgeng/tests/dbgeng.c index 2002beb37f..2a2dd3ad06 100644 --- a/dlls/dbgeng/tests/dbgeng.c +++ b/dlls/dbgeng/tests/dbgeng.c @@ -322,8 +322,8 @@ todo_wine static void test_module_information(void) { static const char *event_name = "dbgeng_test_event"; + unsigned int loaded, unloaded, index; DEBUG_MODULE_PARAMETERS params[2]; - unsigned int loaded, unloaded; PROCESS_INFORMATION info; IDebugSymbols *symbols; IDebugControl *control; @@ -372,7 +372,27 @@ static void test_module_information(void) ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!!base, "Unexpected module base.\n");
+ hr = symbols->lpVtbl->GetModuleByOffset(symbols, 0, 0, &index, &base); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleByOffset(symbols, base, 0, &index, &base); + ok(hr == S_OK, "Failed to get module, hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleByOffset(symbols, base, 0, NULL, NULL); + ok(hr == S_OK, "Failed to get module, hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleByOffset(symbols, base + 1, 0, NULL, NULL); + ok(hr == S_OK, "Failed to get module, hr %#x.\n", hr); + + hr = symbols->lpVtbl->GetModuleByOffset(symbols, base, loaded, NULL, NULL); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + /* Parameters. */ + 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 = symbols->lpVtbl->GetModuleParameters(symbols, 1, NULL, 0, params); ok(hr == S_OK, "Failed to get module parameters, hr %#x.\n", hr); ok(params[0].Base == base, "Unexpected module base.\n");