ntdll: Implement NtWaitForDebugEvent().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d848a25b76
commit
7999af8244
|
@ -2614,7 +2614,6 @@ todo_wine
|
|||
SetLastError(0xdeadbeef);
|
||||
ret = WaitForDebugEvent(&de, 0);
|
||||
ok(!ret, "WaitForDebugEvent should fail\n");
|
||||
todo_wine
|
||||
ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
|
@ -33,7 +34,6 @@
|
|||
#include "werapi.h"
|
||||
|
||||
#include "wine/exception.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/asm.h"
|
||||
#include "kernelbase.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -313,111 +313,6 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilte
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WaitForDebugEvent (kernelbase.@)
|
||||
*/
|
||||
BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeout )
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD res;
|
||||
int i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HANDLE wait = 0;
|
||||
debug_event_t data;
|
||||
SERVER_START_REQ( wait_debug_event )
|
||||
{
|
||||
req->get_handle = (timeout != 0);
|
||||
wine_server_set_reply( req, &data, sizeof(data) );
|
||||
if (!(ret = !wine_server_call_err( req ))) goto done;
|
||||
|
||||
if (!wine_server_reply_size( reply )) /* timeout */
|
||||
{
|
||||
wait = wine_server_ptr_handle( reply->wait );
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
event->dwDebugEventCode = data.code;
|
||||
event->dwProcessId = (DWORD)reply->pid;
|
||||
event->dwThreadId = (DWORD)reply->tid;
|
||||
switch (data.code)
|
||||
{
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
if (data.exception.exc_code == DBG_PRINTEXCEPTION_C && data.exception.nb_params >= 2)
|
||||
{
|
||||
event->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
|
||||
event->u.DebugString.lpDebugStringData = wine_server_get_ptr( data.exception.params[1] );
|
||||
event->u.DebugString.fUnicode = FALSE;
|
||||
event->u.DebugString.nDebugStringLength = data.exception.params[0];
|
||||
break;
|
||||
}
|
||||
else if (data.exception.exc_code == DBG_RIPEXCEPTION && data.exception.nb_params >= 2)
|
||||
{
|
||||
event->dwDebugEventCode = RIP_EVENT;
|
||||
event->u.RipInfo.dwError = data.exception.params[0];
|
||||
event->u.RipInfo.dwType = data.exception.params[1];
|
||||
break;
|
||||
}
|
||||
event->u.Exception.dwFirstChance = data.exception.first;
|
||||
event->u.Exception.ExceptionRecord.ExceptionCode = data.exception.exc_code;
|
||||
event->u.Exception.ExceptionRecord.ExceptionFlags = data.exception.flags;
|
||||
event->u.Exception.ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data.exception.record );
|
||||
event->u.Exception.ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data.exception.address );
|
||||
event->u.Exception.ExceptionRecord.NumberParameters = data.exception.nb_params;
|
||||
for (i = 0; i < data.exception.nb_params; i++)
|
||||
event->u.Exception.ExceptionRecord.ExceptionInformation[i] = data.exception.params[i];
|
||||
break;
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
event->u.CreateThread.hThread = wine_server_ptr_handle( data.create_thread.handle );
|
||||
event->u.CreateThread.lpThreadLocalBase = wine_server_get_ptr( data.create_thread.teb );
|
||||
event->u.CreateThread.lpStartAddress = wine_server_get_ptr( data.create_thread.start );
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
event->u.CreateProcessInfo.hFile = wine_server_ptr_handle( data.create_process.file );
|
||||
event->u.CreateProcessInfo.hProcess = wine_server_ptr_handle( data.create_process.process );
|
||||
event->u.CreateProcessInfo.hThread = wine_server_ptr_handle( data.create_process.thread );
|
||||
event->u.CreateProcessInfo.lpBaseOfImage = wine_server_get_ptr( data.create_process.base );
|
||||
event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.create_process.dbg_offset;
|
||||
event->u.CreateProcessInfo.nDebugInfoSize = data.create_process.dbg_size;
|
||||
event->u.CreateProcessInfo.lpThreadLocalBase = wine_server_get_ptr( data.create_process.teb );
|
||||
event->u.CreateProcessInfo.lpStartAddress = wine_server_get_ptr( data.create_process.start );
|
||||
event->u.CreateProcessInfo.lpImageName = wine_server_get_ptr( data.create_process.name );
|
||||
event->u.CreateProcessInfo.fUnicode = data.create_process.unicode;
|
||||
break;
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
event->u.ExitThread.dwExitCode = data.exit.exit_code;
|
||||
break;
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
event->u.ExitProcess.dwExitCode = data.exit.exit_code;
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
event->u.LoadDll.hFile = wine_server_ptr_handle( data.load_dll.handle );
|
||||
event->u.LoadDll.lpBaseOfDll = wine_server_get_ptr( data.load_dll.base );
|
||||
event->u.LoadDll.dwDebugInfoFileOffset = data.load_dll.dbg_offset;
|
||||
event->u.LoadDll.nDebugInfoSize = data.load_dll.dbg_size;
|
||||
event->u.LoadDll.lpImageName = wine_server_get_ptr( data.load_dll.name );
|
||||
event->u.LoadDll.fUnicode = data.load_dll.unicode;
|
||||
break;
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
event->u.UnloadDll.lpBaseOfDll = wine_server_get_ptr( data.unload_dll.base );
|
||||
break;
|
||||
}
|
||||
done:
|
||||
/* nothing */ ;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (ret) return TRUE;
|
||||
if (!wait) break;
|
||||
res = WaitForSingleObject( wait, timeout );
|
||||
CloseHandle( wait );
|
||||
if (res != STATUS_WAIT_0) break;
|
||||
}
|
||||
SetLastError( ERROR_SEM_TIMEOUT );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* format_exception_msg
|
||||
*/
|
||||
|
|
|
@ -350,6 +350,35 @@ DWORD WINAPI DECLSPEC_HOTPATCH WaitForMultipleObjectsEx( DWORD count, const HAND
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WaitForDebugEvent (kernelbase.@)
|
||||
*/
|
||||
BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeout )
|
||||
{
|
||||
NTSTATUS status;
|
||||
LARGE_INTEGER time;
|
||||
DBGUI_WAIT_STATE_CHANGE state;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
status = DbgUiWaitStateChange( &state, get_nt_timeout( &time, timeout ) );
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_SUCCESS:
|
||||
DbgUiConvertStateChangeStructure( &state, event );
|
||||
return TRUE;
|
||||
case STATUS_USER_APC:
|
||||
continue;
|
||||
case STATUS_TIMEOUT:
|
||||
SetLastError( ERROR_SEM_TIMEOUT );
|
||||
return FALSE;
|
||||
default:
|
||||
return set_ntstatus( status );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WaitOnAddress (kernelbase.@)
|
||||
*/
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
@ stdcall DbgUiRemoteBreakin(ptr)
|
||||
@ stdcall DbgUiSetThreadDebugObject(long)
|
||||
@ stdcall DbgUiStopDebugging(long)
|
||||
@ stub DbgUiWaitStateChange
|
||||
@ stdcall DbgUiWaitStateChange(ptr ptr)
|
||||
@ stdcall DbgUserBreakPoint()
|
||||
@ stdcall EtwEventActivityIdControl(long ptr)
|
||||
@ stdcall EtwEventEnabled(int64 ptr)
|
||||
|
@ -422,7 +422,7 @@
|
|||
@ stdcall -syscall NtUnmapViewOfSection(long ptr)
|
||||
@ stub NtVdmControl
|
||||
@ stub NtW32Call
|
||||
# @ stub NtWaitForDebugEvent
|
||||
@ stdcall -syscall NtWaitForDebugEvent(long long ptr ptr)
|
||||
@ stdcall -syscall NtWaitForKeyedEvent(long ptr long ptr)
|
||||
@ stdcall -syscall NtWaitForMultipleObjects(long ptr long long ptr)
|
||||
@ stub NtWaitForProcessMutant
|
||||
|
@ -1427,7 +1427,7 @@
|
|||
@ stdcall -private -syscall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection
|
||||
@ stub ZwVdmControl
|
||||
@ stub ZwW32Call
|
||||
# @ stub ZwWaitForDebugEvent
|
||||
@ stdcall -private -syscall ZwWaitForDebugEvent(long long ptr ptr) NtWaitForDebugEvent
|
||||
@ stdcall -private -syscall ZwWaitForKeyedEvent(long ptr long ptr) NtWaitForKeyedEvent
|
||||
@ stdcall -private -syscall ZwWaitForMultipleObjects(long ptr long long ptr) NtWaitForMultipleObjects
|
||||
@ stub ZwWaitForProcessMutant
|
||||
|
|
|
@ -178,6 +178,14 @@ NTSTATUS WINAPI DbgUiContinue( CLIENT_ID *client, NTSTATUS status )
|
|||
return NtDebugContinue( DbgUiGetThreadDebugObject(), client, status );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DbgUiWaitStateChange (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI DbgUiWaitStateChange( DBGUI_WAIT_STATE_CHANGE *state, LARGE_INTEGER *timeout )
|
||||
{
|
||||
return NtWaitForDebugEvent( DbgUiGetThreadDebugObject(), TRUE, timeout, state );
|
||||
}
|
||||
|
||||
/* helper for DbgUiConvertStateChangeStructure */
|
||||
static inline void *get_thread_teb( HANDLE thread )
|
||||
{
|
||||
|
|
|
@ -964,6 +964,108 @@ NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS
|
|||
}
|
||||
|
||||
|
||||
/* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
|
||||
static NTSTATUS event_data_to_state_change( const debug_event_t *data, DBGUI_WAIT_STATE_CHANGE *state )
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (data->code)
|
||||
{
|
||||
case DbgIdle:
|
||||
case DbgReplyPending:
|
||||
return STATUS_PENDING;
|
||||
case DbgCreateThreadStateChange:
|
||||
{
|
||||
DBGUI_CREATE_THREAD *info = &state->StateInfo.CreateThread;
|
||||
info->HandleToThread = wine_server_ptr_handle( data->create_thread.handle );
|
||||
info->NewThread.StartAddress = wine_server_get_ptr( data->create_thread.start );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
case DbgCreateProcessStateChange:
|
||||
{
|
||||
DBGUI_CREATE_PROCESS *info = &state->StateInfo.CreateProcessInfo;
|
||||
info->HandleToProcess = wine_server_ptr_handle( data->create_process.process );
|
||||
info->HandleToThread = wine_server_ptr_handle( data->create_process.thread );
|
||||
info->NewProcess.FileHandle = wine_server_ptr_handle( data->create_process.file );
|
||||
info->NewProcess.BaseOfImage = wine_server_get_ptr( data->create_process.base );
|
||||
info->NewProcess.DebugInfoFileOffset = data->create_process.dbg_offset;
|
||||
info->NewProcess.DebugInfoSize = data->create_process.dbg_size;
|
||||
info->NewProcess.InitialThread.StartAddress = wine_server_get_ptr( data->create_process.start );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
case DbgExitThreadStateChange:
|
||||
state->StateInfo.ExitThread.ExitStatus = data->exit.exit_code;
|
||||
return STATUS_SUCCESS;
|
||||
case DbgExitProcessStateChange:
|
||||
state->StateInfo.ExitProcess.ExitStatus = data->exit.exit_code;
|
||||
return STATUS_SUCCESS;
|
||||
case DbgExceptionStateChange:
|
||||
case DbgBreakpointStateChange:
|
||||
case DbgSingleStepStateChange:
|
||||
{
|
||||
DBGKM_EXCEPTION *info = &state->StateInfo.Exception;
|
||||
info->FirstChance = data->exception.first;
|
||||
info->ExceptionRecord.ExceptionCode = data->exception.exc_code;
|
||||
info->ExceptionRecord.ExceptionFlags = data->exception.flags;
|
||||
info->ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data->exception.record );
|
||||
info->ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data->exception.address );
|
||||
info->ExceptionRecord.NumberParameters = data->exception.nb_params;
|
||||
for (i = 0; i < data->exception.nb_params; i++)
|
||||
info->ExceptionRecord.ExceptionInformation[i] = data->exception.params[i];
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
case DbgLoadDllStateChange:
|
||||
{
|
||||
DBGKM_LOAD_DLL *info = &state->StateInfo.LoadDll;
|
||||
info->FileHandle = wine_server_ptr_handle( data->load_dll.handle );
|
||||
info->BaseOfDll = wine_server_get_ptr( data->load_dll.base );
|
||||
info->DebugInfoFileOffset = data->load_dll.dbg_offset;
|
||||
info->DebugInfoSize = data->load_dll.dbg_size;
|
||||
info->NamePointer = wine_server_get_ptr( data->load_dll.name );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
case DbgUnloadDllStateChange:
|
||||
state->StateInfo.UnloadDll.BaseAddress = wine_server_get_ptr( data->unload_dll.base );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* NtWaitForDebugEvent (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout,
|
||||
DBGUI_WAIT_STATE_CHANGE *state )
|
||||
{
|
||||
debug_event_t data;
|
||||
NTSTATUS ret;
|
||||
BOOL wait = TRUE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SERVER_START_REQ( wait_debug_event )
|
||||
{
|
||||
req->debug = wine_server_obj_handle( handle );
|
||||
wine_server_set_reply( req, &data, sizeof(data) );
|
||||
ret = wine_server_call( req );
|
||||
if (!ret && !(ret = event_data_to_state_change( &data, state )))
|
||||
{
|
||||
state->NewState = data.code;
|
||||
state->AppClientId.UniqueProcess = ULongToHandle( reply->pid );
|
||||
state->AppClientId.UniqueThread = ULongToHandle( reply->tid );
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret != STATUS_PENDING) return ret;
|
||||
if (!wait) return STATUS_TIMEOUT;
|
||||
wait = FALSE;
|
||||
ret = NtWaitForSingleObject( handle, alertable, timeout );
|
||||
if (ret != STATUS_WAIT_0) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* NtCreateDirectoryObject (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -74,7 +74,6 @@ typedef union
|
|||
{
|
||||
int code;
|
||||
obj_handle_t handle;
|
||||
client_ptr_t teb;
|
||||
client_ptr_t start;
|
||||
} create_thread;
|
||||
struct
|
||||
|
@ -86,10 +85,7 @@ typedef union
|
|||
mod_handle_t base;
|
||||
int dbg_offset;
|
||||
int dbg_size;
|
||||
client_ptr_t teb;
|
||||
client_ptr_t start;
|
||||
client_ptr_t name;
|
||||
int unicode;
|
||||
} create_process;
|
||||
struct
|
||||
{
|
||||
|
@ -104,7 +100,6 @@ typedef union
|
|||
int dbg_offset;
|
||||
int dbg_size;
|
||||
client_ptr_t name;
|
||||
int unicode;
|
||||
} load_dll;
|
||||
struct
|
||||
{
|
||||
|
@ -2030,16 +2025,14 @@ struct create_debug_obj_reply
|
|||
struct wait_debug_event_request
|
||||
{
|
||||
struct request_header __header;
|
||||
int get_handle;
|
||||
obj_handle_t debug;
|
||||
};
|
||||
struct wait_debug_event_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
process_id_t pid;
|
||||
thread_id_t tid;
|
||||
obj_handle_t wait;
|
||||
/* VARARG(event,debug_event); */
|
||||
char __pad_20[4];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -3129,6 +3129,7 @@ NTSYSAPI NTSTATUS WINAPI DbgUiIssueRemoteBreakin(HANDLE);
|
|||
NTSYSAPI void WINAPI DbgUiRemoteBreakin(void*);
|
||||
NTSYSAPI void WINAPI DbgUiSetThreadDebugObject(HANDLE);
|
||||
NTSYSAPI NTSTATUS WINAPI DbgUiStopDebugging(HANDLE);
|
||||
NTSYSAPI NTSTATUS WINAPI DbgUiWaitStateChange(DBGUI_WAIT_STATE_CHANGE*,LARGE_INTEGER*);
|
||||
NTSYSAPI void WINAPI DbgUserBreakPoint(void);
|
||||
NTSYSAPI NTSTATUS WINAPI LdrAccessResource(HMODULE,const IMAGE_RESOURCE_DATA_ENTRY*,void**,PULONG);
|
||||
NTSYSAPI NTSTATUS WINAPI LdrAddDllDirectory(const UNICODE_STRING*,void**);
|
||||
|
@ -3400,6 +3401,7 @@ NTSYSAPI NTSTATUS WINAPI NtUnlockFile(HANDLE,PIO_STATUS_BLOCK,PLARGE_INTEGER,PL
|
|||
NTSYSAPI NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG);
|
||||
NTSYSAPI NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID);
|
||||
NTSYSAPI NTSTATUS WINAPI NtVdmControl(ULONG,PVOID);
|
||||
NTSYSAPI NTSTATUS WINAPI NtWaitForDebugEvent(HANDLE,BOOLEAN,LARGE_INTEGER*,DBGUI_WAIT_STATE_CHANGE*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtWaitForKeyedEvent(HANDLE,const void*,BOOLEAN,const LARGE_INTEGER*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,const LARGE_INTEGER*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtWaitForMultipleObjects(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*);
|
||||
|
|
|
@ -131,10 +131,8 @@ static void fill_exception_event( struct debug_event *event, const void *arg )
|
|||
|
||||
static void fill_create_thread_event( struct debug_event *event, const void *arg )
|
||||
{
|
||||
struct thread *thread = event->sender;
|
||||
const client_ptr_t *entry = arg;
|
||||
|
||||
event->data.create_thread.teb = thread->teb;
|
||||
if (entry) event->data.create_thread.start = *entry;
|
||||
}
|
||||
|
||||
|
@ -145,13 +143,10 @@ static void fill_create_process_event( struct debug_event *event, const void *ar
|
|||
struct process_dll *exe_module = get_process_exe_module( process );
|
||||
const client_ptr_t *entry = arg;
|
||||
|
||||
event->data.create_process.teb = thread->teb;
|
||||
event->data.create_process.base = exe_module->base;
|
||||
event->data.create_process.start = *entry;
|
||||
event->data.create_process.dbg_offset = exe_module->dbg_offset;
|
||||
event->data.create_process.dbg_size = exe_module->dbg_size;
|
||||
event->data.create_process.name = exe_module->name;
|
||||
event->data.create_process.unicode = 1;
|
||||
|
||||
/* the doc says write access too, but this doesn't seem a good idea */
|
||||
event->file = get_mapping_file( process, exe_module->base, GENERIC_READ,
|
||||
|
@ -180,7 +175,6 @@ static void fill_load_dll_event( struct debug_event *event, const void *arg )
|
|||
event->data.load_dll.dbg_offset = dll->dbg_offset;
|
||||
event->data.load_dll.dbg_size = dll->dbg_size;
|
||||
event->data.load_dll.name = dll->name;
|
||||
event->data.load_dll.unicode = 1;
|
||||
event->file = get_mapping_file( process, dll->base, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE );
|
||||
}
|
||||
|
||||
|
@ -192,17 +186,17 @@ static void fill_unload_dll_event( struct debug_event *event, const void *arg )
|
|||
|
||||
typedef void (*fill_event_func)( struct debug_event *event, const void *arg );
|
||||
|
||||
#define NB_DEBUG_EVENTS UNLOAD_DLL_DEBUG_EVENT
|
||||
|
||||
static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] =
|
||||
static const fill_event_func fill_debug_event[] =
|
||||
{
|
||||
fill_exception_event, /* EXCEPTION_DEBUG_EVENT */
|
||||
fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */
|
||||
fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */
|
||||
fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */
|
||||
fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */
|
||||
fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */
|
||||
fill_unload_dll_event /* UNLOAD_DLL_DEBUG_EVENT */
|
||||
fill_create_thread_event, /* DbgCreateThreadStateChange */
|
||||
fill_create_process_event, /* DbgCreateProcessStateChange */
|
||||
fill_exit_thread_event, /* DbgExitThreadStateChange */
|
||||
fill_exit_process_event, /* DbgExitProcessStateChange */
|
||||
fill_exception_event, /* DbgExceptionStateChange */
|
||||
fill_exception_event, /* DbgBreakpointStateChange */
|
||||
fill_exception_event, /* DbgSingleStepStateChange */
|
||||
fill_load_dll_event, /* DbgLoadDllStateChange */
|
||||
fill_unload_dll_event /* DbgUnloadDllStateChange */
|
||||
};
|
||||
|
||||
/* allocate the necessary handles in the event data */
|
||||
|
@ -210,11 +204,11 @@ static void alloc_event_handles( struct debug_event *event, struct process *proc
|
|||
{
|
||||
switch (event->data.code)
|
||||
{
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
case DbgCreateThreadStateChange:
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
event->data.create_thread.handle = alloc_handle( process, event->sender, THREAD_ALL_ACCESS, 0 );
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
case DbgCreateProcessStateChange:
|
||||
event->data.create_process.thread = alloc_handle( process, event->sender, THREAD_ALL_ACCESS, 0 );
|
||||
/* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
|
||||
event->data.create_process.process = alloc_handle( process, event->sender->process,
|
||||
|
@ -222,7 +216,7 @@ static void alloc_event_handles( struct debug_event *event, struct process *proc
|
|||
if (event->file)
|
||||
event->data.create_process.file = alloc_handle( process, event->file, GENERIC_READ, 0 );
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
case DbgLoadDllStateChange:
|
||||
if (event->file)
|
||||
event->data.load_dll.handle = alloc_handle( process, event->file, GENERIC_READ, 0 );
|
||||
break;
|
||||
|
@ -434,7 +428,7 @@ static struct debug_event *alloc_debug_event( struct thread *thread, int code, c
|
|||
{
|
||||
struct debug_event *event;
|
||||
|
||||
assert( code > 0 && code <= NB_DEBUG_EVENTS );
|
||||
assert( code >= DbgCreateThreadStateChange && code <= DbgUnloadDllStateChange );
|
||||
|
||||
/* build the event */
|
||||
if (!(event = alloc_object( &debug_event_ops ))) return NULL;
|
||||
|
@ -442,8 +436,7 @@ static struct debug_event *alloc_debug_event( struct thread *thread, int code, c
|
|||
event->sender = (struct thread *)grab_object( thread );
|
||||
event->file = NULL;
|
||||
memset( &event->data, 0, sizeof(event->data) );
|
||||
|
||||
fill_debug_event[code-1]( event, arg );
|
||||
fill_debug_event[code - DbgCreateThreadStateChange]( event, arg );
|
||||
event->data.code = code;
|
||||
return event;
|
||||
}
|
||||
|
@ -550,28 +543,28 @@ void generate_startup_debug_events( struct process *process, client_ptr_t entry
|
|||
struct list *ptr;
|
||||
struct thread *thread, *first_thread = get_process_first_thread( process );
|
||||
|
||||
generate_debug_event( first_thread, CREATE_PROCESS_DEBUG_EVENT, &entry );
|
||||
generate_debug_event( first_thread, DbgCreateProcessStateChange, &entry );
|
||||
ptr = list_head( &process->dlls ); /* skip main module reported in create process event */
|
||||
|
||||
/* generate ntdll.dll load event */
|
||||
if (ptr && (ptr = list_next( &process->dlls, ptr )))
|
||||
{
|
||||
struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry );
|
||||
generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll );
|
||||
generate_debug_event( first_thread, DbgLoadDllStateChange, dll );
|
||||
}
|
||||
|
||||
/* generate creation events */
|
||||
LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
|
||||
{
|
||||
if (thread != first_thread)
|
||||
generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, NULL );
|
||||
generate_debug_event( thread, DbgCreateThreadStateChange, NULL );
|
||||
}
|
||||
|
||||
/* generate dll events (in loading order) */
|
||||
while (ptr && (ptr = list_next( &process->dlls, ptr )))
|
||||
{
|
||||
struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry );
|
||||
generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll );
|
||||
generate_debug_event( first_thread, DbgLoadDllStateChange, dll );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,15 +607,11 @@ DECL_HANDLER(create_debug_obj)
|
|||
/* Wait for a debug event */
|
||||
DECL_HANDLER(wait_debug_event)
|
||||
{
|
||||
struct debug_obj *debug_obj = current->debug_obj;
|
||||
struct debug_obj *debug_obj;
|
||||
struct debug_event *event;
|
||||
|
||||
if (!debug_obj) /* current thread is not a debugger */
|
||||
{
|
||||
set_error( STATUS_INVALID_HANDLE );
|
||||
return;
|
||||
}
|
||||
reply->wait = 0;
|
||||
if (!(debug_obj = get_debug_obj( current->process, req->debug, DEBUG_READ_EVENT ))) return;
|
||||
|
||||
if ((event = find_event_to_send( debug_obj )))
|
||||
{
|
||||
event->state = EVENT_SENT;
|
||||
|
@ -632,13 +621,12 @@ DECL_HANDLER(wait_debug_event)
|
|||
alloc_event_handles( event, current->process );
|
||||
set_reply_data( &event->data, min( get_reply_max_size(), sizeof(event->data) ));
|
||||
}
|
||||
else /* no event ready */
|
||||
else
|
||||
{
|
||||
reply->pid = 0;
|
||||
reply->tid = 0;
|
||||
if (req->get_handle)
|
||||
reply->wait = alloc_handle( current->process, debug_obj, SYNCHRONIZE, 0 );
|
||||
int state = list_empty( &debug_obj->event_queue ) ? DbgIdle : DbgReplyPending;
|
||||
set_reply_data( &state, min( get_reply_max_size(), sizeof(state) ));
|
||||
}
|
||||
release_object( debug_obj );
|
||||
}
|
||||
|
||||
/* Continue a debug event */
|
||||
|
@ -724,7 +712,7 @@ DECL_HANDLER(queue_exception_event)
|
|||
data.exception.nb_params = req->len / sizeof(client_ptr_t);
|
||||
memcpy( data.exception.params, get_req_data(), req->len );
|
||||
|
||||
if ((event = alloc_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data )))
|
||||
if ((event = alloc_debug_event( thread, DbgExceptionStateChange, &data )))
|
||||
{
|
||||
if ((reply->handle = alloc_handle( thread->process, event, SYNCHRONIZE, 0 )))
|
||||
{
|
||||
|
|
|
@ -837,7 +837,7 @@ static void process_unload_dll( struct process *process, mod_handle_t base )
|
|||
free( dll->filename );
|
||||
list_remove( &dll->entry );
|
||||
free( dll );
|
||||
generate_debug_event( current, UNLOAD_DLL_DEBUG_EVENT, &base );
|
||||
generate_debug_event( current, DbgUnloadDllStateChange, &base );
|
||||
}
|
||||
else set_error( STATUS_INVALID_PARAMETER );
|
||||
}
|
||||
|
@ -968,10 +968,10 @@ void remove_process_thread( struct process *process, struct thread *thread )
|
|||
{
|
||||
/* we have removed the last running thread, exit the process */
|
||||
process->exit_code = thread->exit_code;
|
||||
generate_debug_event( thread, EXIT_PROCESS_DEBUG_EVENT, process );
|
||||
generate_debug_event( thread, DbgExitProcessStateChange, process );
|
||||
process_killed( process );
|
||||
}
|
||||
else generate_debug_event( thread, EXIT_THREAD_DEBUG_EVENT, thread );
|
||||
else generate_debug_event( thread, DbgExitThreadStateChange, thread );
|
||||
release_object( thread );
|
||||
}
|
||||
|
||||
|
@ -1562,7 +1562,7 @@ DECL_HANDLER(load_dll)
|
|||
dll->name = req->name;
|
||||
/* only generate event if initialization is done */
|
||||
if (is_process_init_done( current->process ))
|
||||
generate_debug_event( current, LOAD_DLL_DEBUG_EVENT, dll );
|
||||
generate_debug_event( current, DbgLoadDllStateChange, dll );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ typedef union
|
|||
int code; /* event code */
|
||||
struct
|
||||
{
|
||||
int code; /* EXCEPTION_DEBUG_EVENT */
|
||||
int code; /* DbgExceptionStateChange */
|
||||
int first; /* first chance exception? */
|
||||
unsigned int exc_code; /* exception code */
|
||||
unsigned int flags; /* exception flags */
|
||||
|
@ -88,43 +88,38 @@ typedef union
|
|||
} exception;
|
||||
struct
|
||||
{
|
||||
int code; /* CREATE_THREAD_DEBUG_EVENT */
|
||||
int code; /* DbgCreateThreadStateChange */
|
||||
obj_handle_t handle; /* handle to the new thread */
|
||||
client_ptr_t teb; /* thread teb (in debugged process address space) */
|
||||
client_ptr_t start; /* thread startup routine */
|
||||
} create_thread;
|
||||
struct
|
||||
{
|
||||
int code; /* CREATE_PROCESS_DEBUG_EVENT */
|
||||
int code; /* DbgCreateProcessStateChange */
|
||||
obj_handle_t file; /* handle to the process exe file */
|
||||
obj_handle_t process; /* handle to the new process */
|
||||
obj_handle_t thread; /* handle to the new thread */
|
||||
mod_handle_t base; /* base of executable image */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
client_ptr_t teb; /* thread teb (in debugged process address space) */
|
||||
client_ptr_t start; /* thread startup routine */
|
||||
client_ptr_t name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
} create_process;
|
||||
struct
|
||||
{
|
||||
int code; /* EXIT_THREAD_DEBUG_EVENT/EXIT_PROCESS_DEBUG_EVENT */
|
||||
int code; /* DbgExitThreadStateChange/DbgExitProcessStateChange */
|
||||
int exit_code; /* thread or process exit code */
|
||||
} exit;
|
||||
struct
|
||||
{
|
||||
int code; /* LOAD_DLL_DEBUG_EVENT */
|
||||
int code; /* DbgLoadDllStateChange */
|
||||
obj_handle_t handle; /* file handle for the dll */
|
||||
mod_handle_t base; /* base address of the dll */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
client_ptr_t name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
} load_dll;
|
||||
struct
|
||||
{
|
||||
int code; /* UNLOAD_DLL_DEBUG_EVENT */
|
||||
int code; /* DbgUnloadDllStateChange */
|
||||
int __pad;
|
||||
mod_handle_t base; /* base address of the dll */
|
||||
} unload_dll;
|
||||
|
@ -1600,11 +1595,10 @@ struct process_info
|
|||
|
||||
/* Wait for a debug event */
|
||||
@REQ(wait_debug_event)
|
||||
int get_handle; /* should we alloc a handle for waiting? */
|
||||
obj_handle_t debug; /* debug object */
|
||||
@REPLY
|
||||
process_id_t pid; /* process id */
|
||||
thread_id_t tid; /* thread id */
|
||||
obj_handle_t wait; /* wait handle if no event ready */
|
||||
VARARG(event,debug_event); /* debug event data */
|
||||
@END
|
||||
|
||||
|
|
|
@ -1138,12 +1138,11 @@ C_ASSERT( FIELD_OFFSET(struct create_debug_obj_request, flags) == 16 );
|
|||
C_ASSERT( sizeof(struct create_debug_obj_request) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_reply, handle) == 8 );
|
||||
C_ASSERT( sizeof(struct create_debug_obj_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_request, get_handle) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_request, debug) == 12 );
|
||||
C_ASSERT( sizeof(struct wait_debug_event_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_reply, pid) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_reply, tid) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_reply, wait) == 16 );
|
||||
C_ASSERT( sizeof(struct wait_debug_event_reply) == 24 );
|
||||
C_ASSERT( sizeof(struct wait_debug_event_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct queue_exception_event_request, first) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct queue_exception_event_request, code) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct queue_exception_event_request, flags) == 20 );
|
||||
|
|
|
@ -1449,7 +1449,7 @@ DECL_HANDLER(init_thread)
|
|||
if (process->unix_pid != current->unix_pid)
|
||||
process->unix_pid = -1; /* can happen with linuxthreads */
|
||||
init_thread_context( current );
|
||||
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry );
|
||||
generate_debug_event( current, DbgCreateThreadStateChange, &req->entry );
|
||||
set_thread_affinity( current, current->affinity );
|
||||
}
|
||||
debug_level = max( debug_level, req->debug_level );
|
||||
|
|
|
@ -780,8 +780,39 @@ static void dump_varargs_debug_event( const char *prefix, data_size_t size )
|
|||
|
||||
switch(event.code)
|
||||
{
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
fprintf( stderr, "%s{exception,first=%d,exc_code=%08x,flags=%08x", prefix,
|
||||
case DbgIdle:
|
||||
fprintf( stderr, "%s{idle}", prefix );
|
||||
break;
|
||||
case DbgReplyPending:
|
||||
fprintf( stderr, "%s{pending}", prefix );
|
||||
break;
|
||||
case DbgCreateThreadStateChange:
|
||||
fprintf( stderr, "%s{create_thread,thread=%04x", prefix, event.create_thread.handle );
|
||||
dump_uint64( ",start=", &event.create_thread.start );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case DbgCreateProcessStateChange:
|
||||
fprintf( stderr, "%s{create_process,file=%04x,process=%04x,thread=%04x", prefix,
|
||||
event.create_process.file, event.create_process.process,
|
||||
event.create_process.thread );
|
||||
dump_uint64( ",base=", &event.create_process.base );
|
||||
fprintf( stderr, ",offset=%d,size=%d",
|
||||
event.create_process.dbg_offset, event.create_process.dbg_size );
|
||||
dump_uint64( ",start=", &event.create_process.start );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case DbgExitThreadStateChange:
|
||||
fprintf( stderr, "%s{exit_thread,code=%d}", prefix, event.exit.exit_code );
|
||||
break;
|
||||
case DbgExitProcessStateChange:
|
||||
fprintf( stderr, "%s{exit_process,code=%d}", prefix, event.exit.exit_code );
|
||||
break;
|
||||
case DbgExceptionStateChange:
|
||||
case DbgBreakpointStateChange:
|
||||
case DbgSingleStepStateChange:
|
||||
fprintf( stderr, "%s{%s,first=%d,exc_code=%08x,flags=%08x", prefix,
|
||||
event.code == DbgBreakpointStateChange ? "breakpoint" :
|
||||
event.code == DbgSingleStepStateChange ? "singlestep" : "exception",
|
||||
event.exception.first, event.exception.exc_code, event.exception.flags );
|
||||
dump_uint64( ",record=", &event.exception.record );
|
||||
dump_uint64( ",address=", &event.exception.address );
|
||||
|
@ -794,46 +825,19 @@ static void dump_varargs_debug_event( const char *prefix, data_size_t size )
|
|||
}
|
||||
fprintf( stderr, "}}" );
|
||||
break;
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
fprintf( stderr, "%s{create_thread,thread=%04x", prefix, event.create_thread.handle );
|
||||
dump_uint64( ",teb=", &event.create_thread.teb );
|
||||
dump_uint64( ",start=", &event.create_thread.start );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
fprintf( stderr, "%s{create_process,file=%04x,process=%04x,thread=%04x", prefix,
|
||||
event.create_process.file, event.create_process.process,
|
||||
event.create_process.thread );
|
||||
dump_uint64( ",base=", &event.create_process.base );
|
||||
fprintf( stderr, ",offset=%d,size=%d",
|
||||
event.create_process.dbg_offset, event.create_process.dbg_size );
|
||||
dump_uint64( ",teb=", &event.create_process.teb );
|
||||
dump_uint64( ",start=", &event.create_process.start );
|
||||
dump_uint64( ",name=", &event.create_process.name );
|
||||
fprintf( stderr, ",unicode=%d}", event.create_process.unicode );
|
||||
break;
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
fprintf( stderr, "%s{exit_thread,code=%d}", prefix, event.exit.exit_code );
|
||||
break;
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
fprintf( stderr, "%s{exit_process,code=%d}", prefix, event.exit.exit_code );
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
case DbgLoadDllStateChange:
|
||||
fprintf( stderr, "%s{load_dll,file=%04x", prefix, event.load_dll.handle );
|
||||
dump_uint64( ",base=", &event.load_dll.base );
|
||||
fprintf( stderr, ",offset=%d,size=%d",
|
||||
event.load_dll.dbg_offset, event.load_dll.dbg_size );
|
||||
dump_uint64( ",name=", &event.load_dll.name );
|
||||
fprintf( stderr, ",unicode=%d}", event.load_dll.unicode );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
case DbgUnloadDllStateChange:
|
||||
fprintf( stderr, "%s{unload_dll", prefix );
|
||||
dump_uint64( ",base=", &event.unload_dll.base );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case 0: /* zero is the code returned on timeouts */
|
||||
fprintf( stderr, "%s{}", prefix );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%s{code=??? (%d)}", prefix, event.code );
|
||||
break;
|
||||
|
@ -2165,14 +2169,13 @@ static void dump_create_debug_obj_reply( const struct create_debug_obj_reply *re
|
|||
|
||||
static void dump_wait_debug_event_request( const struct wait_debug_event_request *req )
|
||||
{
|
||||
fprintf( stderr, " get_handle=%d", req->get_handle );
|
||||
fprintf( stderr, " debug=%04x", req->debug );
|
||||
}
|
||||
|
||||
static void dump_wait_debug_event_reply( const struct wait_debug_event_reply *req )
|
||||
{
|
||||
fprintf( stderr, " pid=%04x", req->pid );
|
||||
fprintf( stderr, ", tid=%04x", req->tid );
|
||||
fprintf( stderr, ", wait=%04x", req->wait );
|
||||
dump_varargs_debug_event( ", event=", cur_size );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue