ntdll: Implement NtWaitForDebugEvent().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-02-01 11:45:29 +01:00
parent d848a25b76
commit 7999af8244
14 changed files with 224 additions and 212 deletions

View File

@ -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);

View File

@ -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
*/

View File

@ -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.@)
*/

View File

@ -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

View File

@ -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 )
{

View File

@ -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.@)
*/

View File

@ -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];
};

View File

@ -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*);

View File

@ -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 )))
{

View File

@ -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 );
}
}

View File

@ -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

View File

@ -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 );

View File

@ -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 );

View File

@ -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 );
}