Author: hyperion Date: Sat Jan 17 11:40:42 2009 New Revision: 38828
URL: http://svn.reactos.org/svn/reactos?rev=38828&view=rev Log: modified dll/win32/kernel32/debug/output.c KJK::Hyperion vs KJK::Hyperion: finishing the job I started in 2003 "please uncomment when GCC supports SEH": it kind of does now, but it's totally unnecessary in K32CreateDBMonMutex "FIXME: this will be pointless until GCC does SEH": no longer pointless, I guess. 6 years after the fact, OutputDebugStringA finally sends the string to the user-mode debugger. Now if only we could test it... Use DBG_PRINTEXCEPTION_C symbolic constant instead of hardcoding its value Some [FORMATTING] Make K32CreateDBMonMutex, for symbol table hygiene My e-mail address changed
Modified: trunk/reactos/dll/win32/kernel32/debug/output.c
Modified: trunk/reactos/dll/win32/kernel32/debug/output.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/debug/ou... ============================================================================== --- trunk/reactos/dll/win32/kernel32/debug/output.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/debug/output.c [iso-8859-1] Sat Jan 17 11:40:42 2009 @@ -4,7 +4,7 @@ * PROJECT: ReactOS system libraries * FILE: lib/kernel32/debug/debugger.c * PURPOSE: OutputDebugString() - * PROGRAMMER: KJK::Hyperion noog@libero.it + * PROGRAMMER: KJK::Hyperion hackbunny@reactos.com */
/* INCLUDES ******************************************************************/ @@ -14,6 +14,7 @@ /* FUNCTIONS *****************************************************************/
/* Open or create the mutex used to communicate with the debug monitor */ +static HANDLE K32CreateDBMonMutex(void) { @@ -63,13 +64,7 @@ return NULL; }
- /* if the mutex doesn't exist, create it */ -#if 0 /* please uncomment when GCC supports SEH */ - __try - { -#else -#define __leave goto l_Cleanup -#endif + /* if the mutex doesn't exist, create it */
/* first, set up the mutex security */ /* allocate the NT AUTHORITY\SYSTEM SID */ @@ -86,7 +81,7 @@ &psidSystem);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate the BUILTIN\Administrators SID */ nErrCode = RtlAllocateAndInitializeSid(&siaNTAuth, @@ -102,7 +97,7 @@ &psidAdministrators);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate the Everyone SID */ nErrCode = RtlAllocateAndInitializeSid(&siaWorldAuth, @@ -118,7 +113,7 @@ &psidEveryone);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate space for the SIDs too */ nDaclBufSize += RtlLengthSid(psidSystem); @@ -129,13 +124,13 @@ pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize);
/* failure */ - if(pDaclBuf == NULL) __leave; + if(pDaclBuf == NULL) goto l_Cleanup;
/* create the DACL */ nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant the minimum required access to Everyone */ nErrCode = RtlAddAccessAllowedAce(pDaclBuf, @@ -146,7 +141,7 @@ psidEveryone);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant full access to BUILTIN\Administrators */ nErrCode = RtlAddAccessAllowedAce(pDaclBuf, @@ -155,7 +150,7 @@ psidAdministrators);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant full access to NT AUTHORITY\SYSTEM */ nErrCode = RtlAddAccessAllowedAce(pDaclBuf, @@ -164,14 +159,14 @@ psidSystem);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* create the security descriptor */ nErrCode = RtlCreateSecurityDescriptor(&sdMutexSecurity, SECURITY_DESCRIPTOR_REVISION);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* set the descriptor's DACL to the ACL we created */ nErrCode = RtlSetDaclSecurityDescriptor(&sdMutexSecurity, @@ -180,28 +175,19 @@ FALSE);
/* failure */ - if(!NT_SUCCESS(nErrCode)) __leave; + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* create the mutex */ hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex"); -#if 0 - } - __finally - { -#else + l_Cleanup: -#endif - /* free the buffers */ if(pDaclBuf) GlobalFree(pDaclBuf); if(psidEveryone) RtlFreeSid(psidEveryone); if(psidAdministrators) RtlFreeSid(psidAdministrators); if(psidSystem) RtlFreeSid(psidSystem); -#if 0 - } -#endif - - return hMutex; + + return hMutex; }
@@ -212,221 +198,195 @@ WINAPI OutputDebugStringA(LPCSTR _OutputString) { -#if 0 -/* FIXME: this will be pointless until GCC does SEH */ - __try - { - ULONG_PTR a_nArgs[2]; - - a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1); - a_nArgs[1] = (ULONG_PTR)_OutputString; - - /* send the string to the user-mode debugger */ - RaiseException(0x40010006, 0, 2, a_nArgs); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { -#endif - - /* no user-mode debugger: try the systemwide debug message monitor, or the - kernel debugger as a last resort */ - - /* mutex used to synchronize invocations of OutputDebugString */ - static HANDLE s_hDBMonMutex = NULL; - /* true if we already attempted to open/create the mutex */ - static BOOL s_bDBMonMutexTriedOpen = FALSE; - - /* local copy of the mutex handle */ - HANDLE hDBMonMutex = s_hDBMonMutex; - /* handle to the Section of the shared buffer */ - HANDLE hDBMonBuffer = NULL; - - /* pointer to the mapped view of the shared buffer. It consist of the current - process id followed by the message string */ - struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL; - - /* event: signaled by the debug message monitor when OutputDebugString can write - to the shared buffer */ - HANDLE hDBMonBufferReady = NULL; - - /* event: to be signaled by OutputDebugString when it's done writing to the - shared buffer */ - HANDLE hDBMonDataReady = NULL; - - /* mutex not opened, and no previous attempts to open/create it */ - if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen) - { - /* open/create the mutex */ - hDBMonMutex = K32CreateDBMonMutex(); - /* store the handle */ - s_hDBMonMutex = hDBMonMutex; - } - -#if 0 - __try - { -#endif - - /* opening the mutex failed */ - if(hDBMonMutex == NULL) - { - /* remember next time */ - s_bDBMonMutexTriedOpen = TRUE; - } - /* opening the mutex succeeded */ - else - { - do - { - /* synchronize with other invocations of OutputDebugString */ - WaitForSingleObject(hDBMonMutex, INFINITE); - - /* buffer of the system-wide debug message monitor */ - hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER"); - - /* couldn't open the buffer: send the string to the kernel debugger */ - if(hDBMonBuffer == NULL) break; - - /* map the buffer */ - pDBMonBuffer = MapViewOfFile(hDBMonBuffer, - SECTION_MAP_READ | SECTION_MAP_WRITE, - 0, - 0, - 0); - - /* couldn't map the buffer: send the string to the kernel debugger */ - if(pDBMonBuffer == NULL) break; - - /* open the event signaling that the buffer can be accessed */ - hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY"); - - /* couldn't open the event: send the string to the kernel debugger */ - if(hDBMonBufferReady == NULL) break; - - /* open the event to be signaled when the buffer has been filled */ - hDBMonDataReady = - OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY"); - } - while(0); - - /* we couldn't connect to the system-wide debug message monitor: send the - string to the kernel debugger */ - if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex); - } - -#if 0 - __try -#else - do -#endif - { - /* size of the current output block */ - SIZE_T nRoundLen; - - /* size of the remainder of the string */ - SIZE_T nOutputStringLen; - - /* output the whole string */ - nOutputStringLen = strlen(_OutputString); - - do - { - /* we're connected to the debug monitor: - write the current block to the shared buffer */ - if(hDBMonDataReady) - { - /* wait a maximum of 10 seconds for the debug monitor - to finish processing the shared buffer */ - if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0) - { - /* timeout or failure: give up */ - break; - } - - /* write the process id into the buffer */ - pDBMonBuffer->ProcessId = GetCurrentProcessId(); - - /* write only as many bytes as they fit in the buffer */ - if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1)) - nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1; - else - nRoundLen = nOutputStringLen; - - /* copy the current block into the buffer */ - memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen); - - /* null-terminate the current block */ - pDBMonBuffer->Buffer[nRoundLen] = 0; - - /* signal that the data contains meaningful data and can be read */ - SetEvent(hDBMonDataReady); - } - /* else, send the current block to the kernel debugger */ - else - { - /* output in blocks of 512 characters */ - CHAR a_cBuffer[512]; - - /* write a maximum of 511 bytes */ - if(nOutputStringLen > (sizeof(a_cBuffer) - 2)) - nRoundLen = sizeof(a_cBuffer) - 2; - else - nRoundLen = nOutputStringLen; - - /* copy the current block */ - memcpy(a_cBuffer, _OutputString, nRoundLen); - - /* null-terminate the current block */ - a_cBuffer[nRoundLen] = 0; - - /* send the current block to the kernel debugger */ - DbgPrint("%s", a_cBuffer); - } - - /* move to the next block */ - _OutputString += nRoundLen; - nOutputStringLen -= nRoundLen; - } - /* repeat until the string has been fully output */ - while (nOutputStringLen > 0); - - } -#if 0 - /* ignore access violations and let other exceptions fall through */ - __except - ( - (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH - ) - { - /* string copied verbatim from Microsoft's kernel32.dll */ - DbgPrint("\nOutputDebugString faulted during output\n"); - } -#else - while(0); -#endif - -#if 0 - } - __finally - { -#endif - - /* close all the still open resources */ - if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady); - if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer); - if(hDBMonBuffer) CloseHandle(hDBMonBuffer); - if(hDBMonDataReady) CloseHandle(hDBMonDataReady); - - /* leave the critical section */ - if(hDBMonDataReady != NULL) - ReleaseMutex(hDBMonMutex); - -#if 0 - } - } -#endif + _SEH2_TRY + { + ULONG_PTR a_nArgs[2]; + + a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1); + a_nArgs[1] = (ULONG_PTR)_OutputString; + + /* send the string to the user-mode debugger */ + RaiseException(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* no user-mode debugger: try the systemwide debug message monitor, or the + kernel debugger as a last resort */ + + /* mutex used to synchronize invocations of OutputDebugString */ + static HANDLE s_hDBMonMutex = NULL; + /* true if we already attempted to open/create the mutex */ + static BOOL s_bDBMonMutexTriedOpen = FALSE; + + /* local copy of the mutex handle */ + HANDLE hDBMonMutex = s_hDBMonMutex; + /* handle to the Section of the shared buffer */ + HANDLE hDBMonBuffer = NULL; + + /* pointer to the mapped view of the shared buffer. It consist of the current + process id followed by the message string */ + struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL; + + /* event: signaled by the debug message monitor when OutputDebugString can write + to the shared buffer */ + HANDLE hDBMonBufferReady = NULL; + + /* event: to be signaled by OutputDebugString when it's done writing to the + shared buffer */ + HANDLE hDBMonDataReady = NULL; + + /* mutex not opened, and no previous attempts to open/create it */ + if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen) + { + /* open/create the mutex */ + hDBMonMutex = K32CreateDBMonMutex(); + /* store the handle */ + s_hDBMonMutex = hDBMonMutex; + } + + _SEH2_TRY + { + /* opening the mutex failed */ + if(hDBMonMutex == NULL) + { + /* remember next time */ + s_bDBMonMutexTriedOpen = TRUE; + } + /* opening the mutex succeeded */ + else + { + do + { + /* synchronize with other invocations of OutputDebugString */ + WaitForSingleObject(hDBMonMutex, INFINITE); + + /* buffer of the system-wide debug message monitor */ + hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER"); + + /* couldn't open the buffer: send the string to the kernel debugger */ + if(hDBMonBuffer == NULL) break; + + /* map the buffer */ + pDBMonBuffer = MapViewOfFile(hDBMonBuffer, + SECTION_MAP_READ | SECTION_MAP_WRITE, + 0, + 0, + 0); + + /* couldn't map the buffer: send the string to the kernel debugger */ + if(pDBMonBuffer == NULL) break; + + /* open the event signaling that the buffer can be accessed */ + hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY"); + + /* couldn't open the event: send the string to the kernel debugger */ + if(hDBMonBufferReady == NULL) break; + + /* open the event to be signaled when the buffer has been filled */ + hDBMonDataReady = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY"); + } + while(0); + + /* we couldn't connect to the system-wide debug message monitor: send the + string to the kernel debugger */ + if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex); + } + + _SEH2_TRY + { + /* size of the current output block */ + SIZE_T nRoundLen; + + /* size of the remainder of the string */ + SIZE_T nOutputStringLen; + + /* output the whole string */ + nOutputStringLen = strlen(_OutputString); + + do + { + /* we're connected to the debug monitor: + write the current block to the shared buffer */ + if(hDBMonDataReady) + { + /* wait a maximum of 10 seconds for the debug monitor + to finish processing the shared buffer */ + if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0) + { + /* timeout or failure: give up */ + break; + } + + /* write the process id into the buffer */ + pDBMonBuffer->ProcessId = GetCurrentProcessId(); + + /* write only as many bytes as they fit in the buffer */ + if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1)) + nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1; + else + nRoundLen = nOutputStringLen; + + /* copy the current block into the buffer */ + memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen); + + /* null-terminate the current block */ + pDBMonBuffer->Buffer[nRoundLen] = 0; + + /* signal that the data contains meaningful data and can be read */ + SetEvent(hDBMonDataReady); + } + /* else, send the current block to the kernel debugger */ + else + { + /* output in blocks of 512 characters */ + CHAR a_cBuffer[512]; + + /* write a maximum of 511 bytes */ + if(nOutputStringLen > (sizeof(a_cBuffer) - 2)) + nRoundLen = sizeof(a_cBuffer) - 2; + else + nRoundLen = nOutputStringLen; + + /* copy the current block */ + memcpy(a_cBuffer, _OutputString, nRoundLen); + + /* null-terminate the current block */ + a_cBuffer[nRoundLen] = 0; + + /* send the current block to the kernel debugger */ + DbgPrint("%s", a_cBuffer); + } + + /* move to the next block */ + _OutputString += nRoundLen; + nOutputStringLen -= nRoundLen; + } + /* repeat until the string has been fully output */ + while (nOutputStringLen > 0); + } + /* ignore access violations and let other exceptions fall through */ + _SEH2_EXCEPT((_SEH2_GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + /* string copied verbatim from Microsoft's kernel32.dll */ + DbgPrint("\nOutputDebugString faulted during output\n"); + } + _SEH2_END; + } + _SEH2_FINALLY + { + /* close all the still open resources */ + if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady); + if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer); + if(hDBMonBuffer) CloseHandle(hDBMonBuffer); + if(hDBMonDataReady) CloseHandle(hDBMonDataReady); + + /* leave the critical section */ + if(hDBMonDataReady != NULL) + ReleaseMutex(hDBMonMutex); + } + _SEH2_END; + } + _SEH2_END; }
@@ -447,15 +407,15 @@
if(!NT_SUCCESS(nErrCode)) { - /* Microsoft's kernel32.dll always prints something, even in case the conversion fails */ - OutputDebugStringA(""); - } - else - { - /* output the converted string */ - OutputDebugStringA(strOut.Buffer); - - /* free the converted string */ - RtlFreeAnsiString(&strOut); - } + /* Microsoft's kernel32.dll always prints something, even in case the conversion fails */ + OutputDebugStringA(""); + } + else + { + /* output the converted string */ + OutputDebugStringA(strOut.Buffer); + + /* free the converted string */ + RtlFreeAnsiString(&strOut); + } }