dbgeng: Implement GetModuleByIndex().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
73a8fe94e6
commit
d33180aebd
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue