diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 47fb3cf4649..861fc321729 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -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); diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 272f255cf0c..8f8389ac372 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -20,6 +20,7 @@ #include #include +#include #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 */ diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index e8e51b1c573..f4bee2d134b 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -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.@) */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index df643445e7d..0a2c2493334 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -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 diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 3ff38691bbc..a86eb80e0cc 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -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 ) { diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 5132daf9e0e..383e9c93273 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -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.@) */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 20cf142e832..a0fe7dbfba1 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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]; }; diff --git a/include/winternl.h b/include/winternl.h index 5523544fd36..c79292b55b0 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -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*); diff --git a/server/debugger.c b/server/debugger.c index 32992a733c7..927fe42929e 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -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 ))) { diff --git a/server/process.c b/server/process.c index bd04c5609c7..95e030777c9 100644 --- a/server/process.c +++ b/server/process.c @@ -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 ); } } diff --git a/server/protocol.def b/server/protocol.def index 7fc83435bc5..13edee9ba52 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 diff --git a/server/request.h b/server/request.h index eb63475a9f2..13e1f663e81 100644 --- a/server/request.h +++ b/server/request.h @@ -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 ); diff --git a/server/thread.c b/server/thread.c index 296f0848027..fd3538c51f3 100644 --- a/server/thread.c +++ b/server/thread.c @@ -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 ); diff --git a/server/trace.c b/server/trace.c index 074652b2567..73215ede59f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ); }