From 3b002685fe18ca3985af744d8f147f29b2c588f0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 8 Sep 2019 21:51:50 +0200 Subject: [PATCH] kernel32: Move debugger functions to kernelbase. Signed-off-by: Alexandre Julliard --- dlls/kernel32/debugger.c | 417 -------------------------------- dlls/kernel32/kernel32.spec | 16 +- dlls/kernelbase/Makefile.in | 1 + dlls/kernelbase/debug.c | 358 +++++++++++++++++++++++++++ dlls/kernelbase/kernelbase.spec | 18 +- 5 files changed, 376 insertions(+), 434 deletions(-) create mode 100644 dlls/kernelbase/debug.c diff --git a/dlls/kernel32/debugger.c b/dlls/kernel32/debugger.c index d78b0831785..3a2e9887410 100644 --- a/dlls/kernel32/debugger.c +++ b/dlls/kernel32/debugger.c @@ -33,373 +33,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(debugstr); - -/****************************************************************************** - * WaitForDebugEvent (KERNEL32.@) - * - * Waits for a debugging event to occur in a process being debugged before - * filling out the debug event structure. - * - * PARAMS - * event [O] Address of structure for event information. - * timeout [I] Number of milliseconds to wait for event. - * - * RETURNS - * - * Returns true if a debug event occurred and false if the call timed out. - */ -BOOL WINAPI WaitForDebugEvent( - LPDEBUG_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; -} - - -/********************************************************************** - * ContinueDebugEvent (KERNEL32.@) - * - * Enables a thread that previously produced a debug event to continue. - * - * PARAMS - * pid [I] The id of the process to continue. - * tid [I] The id of the thread to continue. - * status [I] The rule to apply to unhandled exceptions. - * - * RETURNS - * - * True if the debugger is listed as the processes owner and the process - * and thread are valid. - */ -BOOL WINAPI ContinueDebugEvent( - DWORD pid, - DWORD tid, - DWORD status) -{ - BOOL ret; - SERVER_START_REQ( continue_debug_event ) - { - req->pid = pid; - req->tid = tid; - req->status = status; - ret = !wine_server_call_err( req ); - } - SERVER_END_REQ; - return ret; -} - - -/********************************************************************** - * DebugActiveProcess (KERNEL32.@) - * - * Attempts to attach the debugger to a process. - * - * PARAMS - * pid [I] The process to be debugged. - * - * RETURNS - * - * True if the debugger was attached to process. - */ -BOOL WINAPI DebugActiveProcess( DWORD pid ) -{ - HANDLE process; - BOOL ret; - SERVER_START_REQ( debug_process ) - { - req->pid = pid; - req->attach = 1; - ret = !wine_server_call_err( req ); - } - SERVER_END_REQ; - if (!ret) return FALSE; - if (!(process = OpenProcess( PROCESS_CREATE_THREAD, FALSE, pid ))) return FALSE; - ret = DebugBreakProcess( process ); - NtClose( process ); - if (!ret) DebugActiveProcessStop( pid ); - return ret; -} - -/********************************************************************** - * DebugActiveProcessStop (KERNEL32.@) - * - * Attempts to detach the debugger from a process. - * - * PARAMS - * pid [I] The process to be detached. - * - * RETURNS - * - * True if the debugger was detached from the process. - */ -BOOL WINAPI DebugActiveProcessStop( DWORD pid ) -{ - BOOL ret; - SERVER_START_REQ( debug_process ) - { - req->pid = pid; - req->attach = 0; - ret = !wine_server_call_err( req ); - } - SERVER_END_REQ; - return ret; -} - -static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr ) -{ - EXCEPTION_RECORD *rec = eptr->ExceptionRecord; - return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; -} - -/*********************************************************************** - * OutputDebugStringA (KERNEL32.@) - * - * Output by an application of an ascii string to a debugger (if attached) - * and program log. - * - * PARAMS - * str [I] The message to be logged and given to the debugger. - * - * RETURNS - * - * Nothing. - */ -void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) -{ - static HANDLE DBWinMutex = NULL; - static BOOL mutex_inited = FALSE; - BOOL caught_by_dbg = TRUE; - - if (!str) str = ""; - WARN("%s\n", debugstr_a(str)); - - /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */ - __TRY - { - ULONG_PTR args[2]; - args[0] = strlen(str) + 1; - args[1] = (ULONG_PTR)str; - RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args ); - } - __EXCEPT(debug_exception_handler) - { - caught_by_dbg = FALSE; - } - __ENDTRY - if (caught_by_dbg) return; - - /* send string to a system-wide monitor */ - if (!mutex_inited) - { - /* first call to OutputDebugString, initialize mutex handle */ - static const WCHAR mutexname[] = {'D','B','W','i','n','M','u','t','e','x',0}; - HANDLE mutex = CreateMutexExW( NULL, mutexname, 0, SYNCHRONIZE ); - if (mutex) - { - if (InterlockedCompareExchangePointer( &DBWinMutex, mutex, 0 ) != 0) - { - /* someone beat us here... */ - CloseHandle( mutex ); - } - } - mutex_inited = TRUE; - } - - if (DBWinMutex) - { - static const WCHAR shmname[] = {'D','B','W','I','N','_','B','U','F','F','E','R',0}; - static const WCHAR eventbuffername[] = {'D','B','W','I','N','_','B','U','F','F','E','R','_','R','E','A','D','Y',0}; - static const WCHAR eventdataname[] = {'D','B','W','I','N','_','D','A','T','A','_','R','E','A','D','Y',0}; - HANDLE mapping; - - mapping = OpenFileMappingW( FILE_MAP_WRITE, FALSE, shmname ); - if (mapping) - { - LPVOID buffer; - HANDLE eventbuffer, eventdata; - - buffer = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); - eventbuffer = OpenEventW( SYNCHRONIZE, FALSE, eventbuffername ); - eventdata = OpenEventW( EVENT_MODIFY_STATE, FALSE, eventdataname ); - - if (buffer && eventbuffer && eventdata) - { - /* monitor is present, synchronize with other OutputDebugString invocations */ - WaitForSingleObject( DBWinMutex, INFINITE ); - - /* acquire control over the buffer */ - if (WaitForSingleObject( eventbuffer, 10000 ) == WAIT_OBJECT_0) - { - int str_len; - struct _mon_buffer_t { - DWORD pid; - char buffer[1]; - } *mon_buffer = (struct _mon_buffer_t*) buffer; - - str_len = strlen( str ); - if (str_len > (4096 - sizeof(DWORD) - 1)) - str_len = 4096 - sizeof(DWORD) - 1; - - mon_buffer->pid = GetCurrentProcessId(); - memcpy( mon_buffer->buffer, str, str_len ); - mon_buffer->buffer[str_len] = 0; - - /* signal data ready */ - SetEvent( eventdata ); - } - ReleaseMutex( DBWinMutex ); - } - - if (buffer) - UnmapViewOfFile( buffer ); - if (eventbuffer) - CloseHandle( eventbuffer ); - if (eventdata) - CloseHandle( eventdata ); - CloseHandle( mapping ); - } - } -} - - -/*********************************************************************** - * OutputDebugStringW (KERNEL32.@) - * - * Output by an application of a unicode string to a debugger (if attached) - * and program log. - * - * PARAMS - * str [I] The message to be logged and given to the debugger. - * - * RETURNS - * - * Nothing. - */ -void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) -{ - UNICODE_STRING strW; - STRING strA; - - RtlInitUnicodeString( &strW, str ); - if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE )) - { - OutputDebugStringA( strA.Buffer ); - RtlFreeAnsiString( &strA ); - } -} - - -/*********************************************************************** - * DebugBreak (KERNEL32.@) - * - * Raises an exception so that a debugger (if attached) - * can take some action. - */ -#if defined(__i386__) || defined(__x86_64__) -__ASM_STDCALL_FUNC( DebugBreak, 0, "jmp " __ASM_NAME("DbgBreakPoint") ) -#else -void WINAPI DebugBreak(void) -{ - DbgBreakPoint(); -} -#endif - /*********************************************************************** * DebugBreakProcess (KERNEL32.@) * @@ -425,56 +58,6 @@ BOOL WINAPI DebugBreakProcess(HANDLE process) } -/*********************************************************************** - * IsDebuggerPresent (KERNEL32.@) - * - * Allows a process to determine if there is a debugger attached. - * - * PARAMS - * - * RETURNS - * - * True if there is a debugger attached. - */ -BOOL WINAPI IsDebuggerPresent(void) -{ - return NtCurrentTeb()->Peb->BeingDebugged; -} - -/*********************************************************************** - * CheckRemoteDebuggerPresent (KERNEL32.@) - * - * Allows a process to determine if there is a remote debugger - * attached. - * - * PARAMS - * - * RETURNS - * - * TRUE because it is a stub. - */ -BOOL WINAPI CheckRemoteDebuggerPresent(HANDLE process, PBOOL DebuggerPresent) -{ - NTSTATUS status; - DWORD_PTR port; - - if(!process || !DebuggerPresent) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - status = NtQueryInformationProcess(process, ProcessDebugPort, &port, sizeof(port), NULL); - if (status != STATUS_SUCCESS) - { - SetLastError(RtlNtStatusToDosError(status)); - return FALSE; - } - - *DebuggerPresent = !!port; - return TRUE; -} - /*********************************************************************** * DebugSetProcessKillOnExit (KERNEL32.@) * diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 8bbb08d7669..061a064eb75 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -219,7 +219,7 @@ # @ stub CheckForReadOnlyResource @ stdcall CheckNameLegalDOS8Dot3A(str ptr long ptr ptr) @ stdcall CheckNameLegalDOS8Dot3W(wstr ptr long ptr ptr) -@ stdcall CheckRemoteDebuggerPresent(long ptr) +@ stdcall -import CheckRemoteDebuggerPresent(long ptr) @ stdcall ClearCommBreak(long) @ stdcall ClearCommError(long ptr ptr) @ stdcall CloseConsoleHandle(long) @@ -246,7 +246,7 @@ @ stdcall -import ConnectNamedPipe(long ptr) @ stub ConsoleMenuControl @ stub ConsoleSubst -@ stdcall ContinueDebugEvent(long long long) +@ stdcall -import ContinueDebugEvent(long long long) # @ stub ConvertCalDateTimeToSystemTime @ stdcall ConvertDefaultLocale (long) @ stdcall -import ConvertFiberToThread() @@ -347,8 +347,8 @@ @ stdcall -import CreateWaitableTimerW(ptr long wstr) # @ stub CtrlRoutine @ stdcall -import DeactivateActCtx(long long) -@ stdcall DebugActiveProcess(long) -@ stdcall DebugActiveProcessStop(long) +@ stdcall -import DebugActiveProcess(long) +@ stdcall -import DebugActiveProcessStop(long) @ stdcall DebugBreak() @ stdcall DebugBreakProcess(long) @ stdcall DebugSetProcessKillOnExit(long) @@ -977,7 +977,7 @@ # @ stub IsCalendarLeapYear @ stdcall IsDBCSLeadByte(long) @ stdcall IsDBCSLeadByteEx(long long) -@ stdcall IsDebuggerPresent() +@ stdcall -import IsDebuggerPresent() @ stub -i386 IsLSCallback # @ stub IsNLSDefinedString @ stdcall IsNormalizedString(long wstr long) @@ -1134,8 +1134,8 @@ @ stdcall -i386 OpenVxDHandle(long) @ stdcall OpenWaitableTimerA(long long str) @ stdcall -import OpenWaitableTimerW(long long wstr) -@ stdcall OutputDebugStringA(str) -@ stdcall OutputDebugStringW(wstr) +@ stdcall -import OutputDebugStringA(str) +@ stdcall -import OutputDebugStringW(wstr) @ stdcall PeekConsoleInputA(ptr ptr long ptr) @ stdcall PeekConsoleInputW(ptr ptr long ptr) @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) @@ -1571,7 +1571,7 @@ @ stdcall -import VirtualUnlock(ptr long) @ stdcall WTSGetActiveConsoleSessionId() @ stdcall WaitCommEvent(long ptr ptr) -@ stdcall WaitForDebugEvent(ptr long) +@ stdcall -import WaitForDebugEvent(ptr long) @ stdcall -import WaitForMultipleObjects(long ptr long long) @ stdcall -import WaitForMultipleObjectsEx(long ptr long long long) @ stdcall -import WaitForSingleObject(long long) diff --git a/dlls/kernelbase/Makefile.in b/dlls/kernelbase/Makefile.in index 9619ede7b4e..872e0d3290a 100644 --- a/dlls/kernelbase/Makefile.in +++ b/dlls/kernelbase/Makefile.in @@ -4,6 +4,7 @@ IMPORTS = uuid ntdll winecrt0 kernel32 EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -mno-cygwin C_SRCS = \ + debug.c \ file.c \ loader.c \ main.c \ diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c new file mode 100644 index 00000000000..9deed665a2c --- /dev/null +++ b/dlls/kernelbase/debug.c @@ -0,0 +1,358 @@ +/* + * Win32 debugger functions + * + * Copyright (C) 1999 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winerror.h" + +#include "wine/exception.h" +#include "wine/server.h" +#include "wine/asm.h" +#include "kernelbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(seh); + + +/*********************************************************************** + * CheckRemoteDebuggerPresent (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH CheckRemoteDebuggerPresent( HANDLE process, BOOL *present ) +{ + DWORD_PTR port; + + if (!process || !present) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!set_ntstatus( NtQueryInformationProcess( process, ProcessDebugPort, &port, sizeof(port), NULL ))) + return FALSE; + *present = !!port; + return TRUE; +} + + +/********************************************************************** + * ContinueDebugEvent (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ContinueDebugEvent( DWORD pid, DWORD tid, DWORD status ) +{ + BOOL ret; + SERVER_START_REQ( continue_debug_event ) + { + req->pid = pid; + req->tid = tid; + req->status = status; + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + return ret; +} + + +/********************************************************************** + * DebugActiveProcess (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid ) +{ + HANDLE process; + BOOL ret; + + SERVER_START_REQ( debug_process ) + { + req->pid = pid; + req->attach = 1; + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + if (!ret) return FALSE; + + if (!(process = OpenProcess( PROCESS_CREATE_THREAD, FALSE, pid ))) return FALSE; + ret = set_ntstatus( DbgUiIssueRemoteBreakin( process )); + NtClose( process ); + if (!ret) DebugActiveProcessStop( pid ); + return ret; +} + + +/********************************************************************** + * DebugActiveProcessStop (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcessStop( DWORD pid ) +{ + BOOL ret; + + SERVER_START_REQ( debug_process ) + { + req->pid = pid; + req->attach = 0; + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * DebugBreak (kernelbase.@) + */ +#if defined(__i386__) || defined(__x86_64__) +__ASM_STDCALL_FUNC( DebugBreak, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) ) +#else +void WINAPI DebugBreak(void) +{ + DbgBreakPoint(); +} +#endif + + +/*********************************************************************** + * IsDebuggerPresent (kernelbase.@) + */ +BOOL WINAPI IsDebuggerPresent(void) +{ + return NtCurrentTeb()->Peb->BeingDebugged; +} + + +static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} + +/*********************************************************************** + * OutputDebugStringA (kernelbase.@) + */ +void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) +{ + static HANDLE DBWinMutex = NULL; + static BOOL mutex_inited = FALSE; + BOOL caught_by_dbg = TRUE; + + if (!str) str = ""; + WARN( "%s\n", debugstr_a(str) ); + + /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */ + __TRY + { + ULONG_PTR args[2]; + args[0] = strlen(str) + 1; + args[1] = (ULONG_PTR)str; + RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args ); + } + __EXCEPT(debug_exception_handler) + { + caught_by_dbg = FALSE; + } + __ENDTRY + if (caught_by_dbg) return; + + /* send string to a system-wide monitor */ + if (!mutex_inited) + { + /* first call to OutputDebugString, initialize mutex handle */ + static const WCHAR mutexname[] = {'D','B','W','i','n','M','u','t','e','x',0}; + HANDLE mutex = CreateMutexExW( NULL, mutexname, 0, SYNCHRONIZE ); + if (mutex) + { + if (InterlockedCompareExchangePointer( &DBWinMutex, mutex, 0 ) != 0) + /* someone beat us here... */ + CloseHandle( mutex ); + } + mutex_inited = TRUE; + } + + if (DBWinMutex) + { + static const WCHAR shmname[] = {'D','B','W','I','N','_','B','U','F','F','E','R',0}; + static const WCHAR eventbuffername[] = {'D','B','W','I','N','_','B','U','F','F','E','R','_','R','E','A','D','Y',0}; + static const WCHAR eventdataname[] = {'D','B','W','I','N','_','D','A','T','A','_','R','E','A','D','Y',0}; + HANDLE mapping; + + mapping = OpenFileMappingW( FILE_MAP_WRITE, FALSE, shmname ); + if (mapping) + { + LPVOID buffer; + HANDLE eventbuffer, eventdata; + + buffer = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); + eventbuffer = OpenEventW( SYNCHRONIZE, FALSE, eventbuffername ); + eventdata = OpenEventW( EVENT_MODIFY_STATE, FALSE, eventdataname ); + + if (buffer && eventbuffer && eventdata) + { + /* monitor is present, synchronize with other OutputDebugString invocations */ + WaitForSingleObject( DBWinMutex, INFINITE ); + + /* acquire control over the buffer */ + if (WaitForSingleObject( eventbuffer, 10000 ) == WAIT_OBJECT_0) + { + int str_len = strlen( str ); + struct _mon_buffer_t + { + DWORD pid; + char buffer[1]; + } *mon_buffer = (struct _mon_buffer_t*) buffer; + + if (str_len > (4096 - sizeof(DWORD) - 1)) str_len = 4096 - sizeof(DWORD) - 1; + mon_buffer->pid = GetCurrentProcessId(); + memcpy( mon_buffer->buffer, str, str_len ); + mon_buffer->buffer[str_len] = 0; + + /* signal data ready */ + SetEvent( eventdata ); + } + ReleaseMutex( DBWinMutex ); + } + + if (buffer) UnmapViewOfFile( buffer ); + if (eventbuffer) CloseHandle( eventbuffer ); + if (eventdata) CloseHandle( eventdata ); + CloseHandle( mapping ); + } + } +} + + +/*********************************************************************** + * OutputDebugStringW (kernelbase.@) + */ +void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) +{ + UNICODE_STRING strW; + STRING strA; + + RtlInitUnicodeString( &strW, str ); + if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE )) + { + OutputDebugStringA( strA.Buffer ); + RtlFreeAnsiString( &strA ); + } +} + + +/****************************************************************************** + * 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; +} diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index dc108f148ec..e77523137b8 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -126,7 +126,7 @@ # @ stub CheckAllowDecryptedRemoteDestinationPolicy @ stub CheckGroupPolicyEnabled # @ stub CheckIfStateChangeNotificationExists -@ stdcall CheckRemoteDebuggerPresent(long ptr) kernel32.CheckRemoteDebuggerPresent +@ stdcall CheckRemoteDebuggerPresent(long ptr) # @ stub CheckTokenCapability @ stdcall CheckTokenMembership(long ptr ptr) # @ stub CheckTokenMembershipEx @@ -158,7 +158,7 @@ @ stdcall CompareStringOrdinal(wstr long wstr long long) kernel32.CompareStringOrdinal @ stdcall CompareStringW(long long wstr long wstr long) kernel32.CompareStringW @ stdcall ConnectNamedPipe(long ptr) -@ stdcall ContinueDebugEvent(long long long) kernel32.ContinueDebugEvent +@ stdcall ContinueDebugEvent(long long long) @ stdcall ConvertDefaultLocale(long) kernel32.ConvertDefaultLocale @ stdcall ConvertFiberToThread() @ stdcall ConvertThreadToFiber(ptr) @@ -237,9 +237,9 @@ # @ stub CtrlRoutine # @ stub CveEventWrite @ stdcall DeactivateActCtx(long long) -@ stdcall DebugActiveProcess(long) kernel32.DebugActiveProcess -@ stdcall DebugActiveProcessStop(long) kernel32.DebugActiveProcessStop -@ stdcall DebugBreak() kernel32.DebugBreak +@ stdcall DebugActiveProcess(long) +@ stdcall DebugActiveProcessStop(long) +@ stdcall DebugBreak() @ stdcall DecodePointer(ptr) ntdll.RtlDecodePointer # @ stub DecodeRemotePointer @ stdcall DecodeSystemPointer(ptr) ntdll.RtlDecodeSystemPointer @@ -856,7 +856,7 @@ @ stdcall IsCharXDigitW(long) @ stdcall IsDBCSLeadByte(long) kernel32.IsDBCSLeadByte @ stdcall IsDBCSLeadByteEx(long long) kernel32.IsDBCSLeadByteEx -@ stdcall IsDebuggerPresent() kernel32.IsDebuggerPresent +@ stdcall IsDebuggerPresent() # @ stub IsDeveloperModeEnabled # @ stub IsDeveloperModePolicyApplied # @ stub IsEnclaveTypeSupported @@ -1003,8 +1003,8 @@ @ stdcall OpenThread(long long long) @ stdcall OpenThreadToken(long long long ptr) @ stdcall OpenWaitableTimerW(long long wstr) -@ stdcall OutputDebugStringA(str) kernel32.OutputDebugStringA -@ stdcall OutputDebugStringW(wstr) kernel32.OutputDebugStringW +@ stdcall OutputDebugStringA(str) +@ stdcall OutputDebugStringW(wstr) # @ stub OverrideRoamingDataModificationTimesInRange # @ stub PackageFamilyNameFromFullName # @ stub PackageFamilyNameFromId @@ -1684,7 +1684,7 @@ # @ stub WTSGetServiceSessionId # @ stub WTSIsServerContainer @ stdcall WaitCommEvent(long ptr ptr) kernel32.WaitCommEvent -@ stdcall WaitForDebugEvent(ptr long) kernel32.WaitForDebugEvent +@ stdcall WaitForDebugEvent(ptr long) # @ stub WaitForDebugEventEx # @ stub WaitForMachinePolicyForegroundProcessingInternal @ stdcall WaitForMultipleObjects(long ptr long long)