dbgeng: Implement GetNumberModules().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4557a007d7
commit
73a8fe94e6
|
@ -25,6 +25,7 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
#include "psapi.h"
|
||||||
|
|
||||||
#include "initguid.h"
|
#include "initguid.h"
|
||||||
#include "dbgeng.h"
|
#include "dbgeng.h"
|
||||||
|
@ -44,6 +45,12 @@ struct target_process
|
||||||
unsigned int pid;
|
unsigned int pid;
|
||||||
unsigned int attach_flags;
|
unsigned int attach_flags;
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int loaded;
|
||||||
|
unsigned int unloaded;
|
||||||
|
BOOL initialized;
|
||||||
|
} modules;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct debug_client
|
struct debug_client
|
||||||
|
@ -58,6 +65,37 @@ struct debug_client
|
||||||
IDebugEventCallbacks *event_callbacks;
|
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)
|
static void debug_client_detach_target(struct target_process *target)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
@ -255,7 +293,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient *iface,
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(process = heap_alloc(sizeof(*process))))
|
if (!(process = heap_alloc_zero(sizeof(*process))))
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
process->pid = pid;
|
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)
|
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)
|
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 */
|
/* FIXME: only one target is used currently */
|
||||||
|
|
||||||
if (list_empty(&debug_client->targets))
|
if (!(target = debug_client_get_target(debug_client)))
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
|
|
||||||
target = LIST_ENTRY(list_head(&debug_client->targets), struct target_process, entry);
|
|
||||||
|
|
||||||
if (target->attach_flags & DEBUG_ATTACH_NONINVASIVE)
|
if (target->attach_flags & DEBUG_ATTACH_NONINVASIVE)
|
||||||
{
|
{
|
||||||
BOOL suspend = !(target->attach_flags & DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND);
|
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;
|
NTSTATUS status;
|
||||||
|
|
||||||
if (suspend)
|
if (suspend)
|
||||||
|
|
|
@ -226,17 +226,27 @@ static const IDebugEventCallbacksVtbl event_callbacks_vtbl =
|
||||||
|
|
||||||
static const char *event_name = "dbgeng_test_event";
|
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)
|
static void test_attach(void)
|
||||||
{
|
{
|
||||||
IDebugEventCallbacks event_callbacks = { &event_callbacks_vtbl };
|
IDebugEventCallbacks event_callbacks = { &event_callbacks_vtbl };
|
||||||
PROCESS_INFORMATION info;
|
PROCESS_INFORMATION info;
|
||||||
char path_name[MAX_PATH];
|
|
||||||
IDebugControl *control;
|
IDebugControl *control;
|
||||||
IDebugClient *client;
|
IDebugClient *client;
|
||||||
STARTUPINFOA startup;
|
|
||||||
BOOL is_debugged;
|
BOOL is_debugged;
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
char **argv;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
|
|
||||||
|
@ -252,11 +262,7 @@ static void test_attach(void)
|
||||||
event = CreateEventA(NULL, FALSE, FALSE, event_name);
|
event = CreateEventA(NULL, FALSE, FALSE, event_name);
|
||||||
ok(event != NULL, "Failed to create event.\n");
|
ok(event != NULL, "Failed to create event.\n");
|
||||||
|
|
||||||
winetest_get_mainargs(&argv);
|
ret = create_target_process(&info);
|
||||||
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),
|
|
||||||
ok(ret, "Failed to create target process.\n");
|
ok(ret, "Failed to create target process.\n");
|
||||||
|
|
||||||
is_debugged = TRUE;
|
is_debugged = TRUE;
|
||||||
|
@ -300,6 +306,56 @@ todo_wine
|
||||||
control->lpVtbl->Release(control);
|
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)
|
static void target_proc(void)
|
||||||
{
|
{
|
||||||
HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, event_name);
|
HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, event_name);
|
||||||
|
@ -330,4 +386,5 @@ START_TEST(dbgeng)
|
||||||
|
|
||||||
test_engine_options();
|
test_engine_options();
|
||||||
test_attach();
|
test_attach();
|
||||||
|
test_module_information();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue