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

svn path=/trunk/; revision=38828
This commit is contained in:
KJK::Hyperion 2009-01-17 17:40:42 +00:00
parent c331fd3dad
commit 5b30cdcd87

View file

@ -4,7 +4,7 @@
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
* FILE: lib/kernel32/debug/debugger.c * FILE: lib/kernel32/debug/debugger.c
* PURPOSE: OutputDebugString() * PURPOSE: OutputDebugString()
* PROGRAMMER: KJK::Hyperion <noog@libero.it> * PROGRAMMER: KJK::Hyperion <hackbunny@reactos.com>
*/ */
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
@ -14,6 +14,7 @@
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
/* Open or create the mutex used to communicate with the debug monitor */ /* Open or create the mutex used to communicate with the debug monitor */
static
HANDLE HANDLE
K32CreateDBMonMutex(void) K32CreateDBMonMutex(void)
{ {
@ -63,13 +64,7 @@ K32CreateDBMonMutex(void)
return NULL; return NULL;
} }
/* if the mutex doesn't exist, create it */ /* if the mutex doesn't exist, create it */
#if 0 /* please uncomment when GCC supports SEH */
__try
{
#else
#define __leave goto l_Cleanup
#endif
/* first, set up the mutex security */ /* first, set up the mutex security */
/* allocate the NT AUTHORITY\SYSTEM SID */ /* allocate the NT AUTHORITY\SYSTEM SID */
@ -86,7 +81,7 @@ K32CreateDBMonMutex(void)
&psidSystem); &psidSystem);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate the BUILTIN\Administrators SID */ /* allocate the BUILTIN\Administrators SID */
nErrCode = RtlAllocateAndInitializeSid(&siaNTAuth, nErrCode = RtlAllocateAndInitializeSid(&siaNTAuth,
@ -102,7 +97,7 @@ K32CreateDBMonMutex(void)
&psidAdministrators); &psidAdministrators);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate the Everyone SID */ /* allocate the Everyone SID */
nErrCode = RtlAllocateAndInitializeSid(&siaWorldAuth, nErrCode = RtlAllocateAndInitializeSid(&siaWorldAuth,
@ -118,7 +113,7 @@ K32CreateDBMonMutex(void)
&psidEveryone); &psidEveryone);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* allocate space for the SIDs too */ /* allocate space for the SIDs too */
nDaclBufSize += RtlLengthSid(psidSystem); nDaclBufSize += RtlLengthSid(psidSystem);
@ -129,13 +124,13 @@ K32CreateDBMonMutex(void)
pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize); pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize);
/* failure */ /* failure */
if(pDaclBuf == NULL) __leave; if(pDaclBuf == NULL) goto l_Cleanup;
/* create the DACL */ /* create the DACL */
nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION); nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant the minimum required access to Everyone */ /* grant the minimum required access to Everyone */
nErrCode = RtlAddAccessAllowedAce(pDaclBuf, nErrCode = RtlAddAccessAllowedAce(pDaclBuf,
@ -146,7 +141,7 @@ K32CreateDBMonMutex(void)
psidEveryone); psidEveryone);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant full access to BUILTIN\Administrators */ /* grant full access to BUILTIN\Administrators */
nErrCode = RtlAddAccessAllowedAce(pDaclBuf, nErrCode = RtlAddAccessAllowedAce(pDaclBuf,
@ -155,7 +150,7 @@ K32CreateDBMonMutex(void)
psidAdministrators); psidAdministrators);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* grant full access to NT AUTHORITY\SYSTEM */ /* grant full access to NT AUTHORITY\SYSTEM */
nErrCode = RtlAddAccessAllowedAce(pDaclBuf, nErrCode = RtlAddAccessAllowedAce(pDaclBuf,
@ -164,14 +159,14 @@ K32CreateDBMonMutex(void)
psidSystem); psidSystem);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* create the security descriptor */ /* create the security descriptor */
nErrCode = RtlCreateSecurityDescriptor(&sdMutexSecurity, nErrCode = RtlCreateSecurityDescriptor(&sdMutexSecurity,
SECURITY_DESCRIPTOR_REVISION); SECURITY_DESCRIPTOR_REVISION);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* set the descriptor's DACL to the ACL we created */ /* set the descriptor's DACL to the ACL we created */
nErrCode = RtlSetDaclSecurityDescriptor(&sdMutexSecurity, nErrCode = RtlSetDaclSecurityDescriptor(&sdMutexSecurity,
@ -180,28 +175,19 @@ K32CreateDBMonMutex(void)
FALSE); FALSE);
/* failure */ /* failure */
if(!NT_SUCCESS(nErrCode)) __leave; if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
/* create the mutex */ /* create the mutex */
hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex"); hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex");
#if 0
}
__finally
{
#else
l_Cleanup:
#endif
l_Cleanup:
/* free the buffers */ /* free the buffers */
if(pDaclBuf) GlobalFree(pDaclBuf); if(pDaclBuf) GlobalFree(pDaclBuf);
if(psidEveryone) RtlFreeSid(psidEveryone); if(psidEveryone) RtlFreeSid(psidEveryone);
if(psidAdministrators) RtlFreeSid(psidAdministrators); if(psidAdministrators) RtlFreeSid(psidAdministrators);
if(psidSystem) RtlFreeSid(psidSystem); if(psidSystem) RtlFreeSid(psidSystem);
#if 0
}
#endif
return hMutex; return hMutex;
} }
@ -212,221 +198,195 @@ VOID
WINAPI WINAPI
OutputDebugStringA(LPCSTR _OutputString) OutputDebugStringA(LPCSTR _OutputString)
{ {
#if 0 _SEH2_TRY
/* FIXME: this will be pointless until GCC does SEH */ {
__try ULONG_PTR a_nArgs[2];
{
ULONG_PTR a_nArgs[2];
a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1); a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
a_nArgs[1] = (ULONG_PTR)_OutputString; a_nArgs[1] = (ULONG_PTR)_OutputString;
/* send the string to the user-mode debugger */ /* send the string to the user-mode debugger */
RaiseException(0x40010006, 0, 2, a_nArgs); RaiseException(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs);
} }
__except(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
#endif /* no user-mode debugger: try the systemwide debug message monitor, or the
kernel debugger as a last resort */
/* no user-mode debugger: try the systemwide debug message monitor, or the /* mutex used to synchronize invocations of OutputDebugString */
kernel debugger as a last resort */ static HANDLE s_hDBMonMutex = NULL;
/* true if we already attempted to open/create the mutex */
static BOOL s_bDBMonMutexTriedOpen = FALSE;
/* mutex used to synchronize invocations of OutputDebugString */ /* local copy of the mutex handle */
static HANDLE s_hDBMonMutex = NULL; HANDLE hDBMonMutex = s_hDBMonMutex;
/* true if we already attempted to open/create the mutex */ /* handle to the Section of the shared buffer */
static BOOL s_bDBMonMutexTriedOpen = FALSE; HANDLE hDBMonBuffer = NULL;
/* local copy of the mutex handle */ /* pointer to the mapped view of the shared buffer. It consist of the current
HANDLE hDBMonMutex = s_hDBMonMutex; process id followed by the message string */
/* handle to the Section of the shared buffer */ struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
HANDLE hDBMonBuffer = NULL;
/* pointer to the mapped view of the shared buffer. It consist of the current /* event: signaled by the debug message monitor when OutputDebugString can write
process id followed by the message string */ to the shared buffer */
struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL; HANDLE hDBMonBufferReady = NULL;
/* event: signaled by the debug message monitor when OutputDebugString can write /* event: to be signaled by OutputDebugString when it's done writing to the
to the shared buffer */ shared buffer */
HANDLE hDBMonBufferReady = NULL; HANDLE hDBMonDataReady = NULL;
/* event: to be signaled by OutputDebugString when it's done writing to the /* mutex not opened, and no previous attempts to open/create it */
shared buffer */ if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
HANDLE hDBMonDataReady = NULL; {
/* open/create the mutex */
hDBMonMutex = K32CreateDBMonMutex();
/* store the handle */
s_hDBMonMutex = hDBMonMutex;
}
/* mutex not opened, and no previous attempts to open/create it */ _SEH2_TRY
if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen) {
{ /* opening the mutex failed */
/* open/create the mutex */ if(hDBMonMutex == NULL)
hDBMonMutex = K32CreateDBMonMutex(); {
/* store the handle */ /* remember next time */
s_hDBMonMutex = hDBMonMutex; s_bDBMonMutexTriedOpen = TRUE;
} }
/* opening the mutex succeeded */
else
{
do
{
/* synchronize with other invocations of OutputDebugString */
WaitForSingleObject(hDBMonMutex, INFINITE);
#if 0 /* buffer of the system-wide debug message monitor */
__try hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
{
#endif
/* opening the mutex failed */ /* couldn't open the buffer: send the string to the kernel debugger */
if(hDBMonMutex == NULL) if(hDBMonBuffer == NULL) break;
{
/* 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 */ /* map the buffer */
hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER"); pDBMonBuffer = MapViewOfFile(hDBMonBuffer,
SECTION_MAP_READ | SECTION_MAP_WRITE,
0,
0,
0);
/* couldn't open the buffer: send the string to the kernel debugger */ /* couldn't map the buffer: send the string to the kernel debugger */
if(hDBMonBuffer == NULL) break; if(pDBMonBuffer == NULL) break;
/* map the buffer */ /* open the event signaling that the buffer can be accessed */
pDBMonBuffer = MapViewOfFile(hDBMonBuffer, hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
SECTION_MAP_READ | SECTION_MAP_WRITE,
0,
0,
0);
/* couldn't map the buffer: send the string to the kernel debugger */ /* couldn't open the event: send the string to the kernel debugger */
if(pDBMonBuffer == NULL) break; if(hDBMonBufferReady == NULL) break;
/* open the event signaling that the buffer can be accessed */ /* open the event to be signaled when the buffer has been filled */
hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY"); hDBMonDataReady = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
}
while(0);
/* couldn't open the event: send the string to the kernel debugger */ /* we couldn't connect to the system-wide debug message monitor: send the
if(hDBMonBufferReady == NULL) break; string to the kernel debugger */
if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
}
/* open the event to be signaled when the buffer has been filled */ _SEH2_TRY
hDBMonDataReady = {
OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY"); /* size of the current output block */
} SIZE_T nRoundLen;
while(0);
/* we couldn't connect to the system-wide debug message monitor: send the /* size of the remainder of the string */
string to the kernel debugger */ SIZE_T nOutputStringLen;
if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
}
#if 0 /* output the whole string */
__try nOutputStringLen = strlen(_OutputString);
#else
do
#endif
{
/* size of the current output block */
SIZE_T nRoundLen;
/* size of the remainder of the string */ do
SIZE_T nOutputStringLen; {
/* 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;
}
/* output the whole string */ /* write the process id into the buffer */
nOutputStringLen = strlen(_OutputString); pDBMonBuffer->ProcessId = GetCurrentProcessId();
do /* write only as many bytes as they fit in the buffer */
{ if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))
/* we're connected to the debug monitor: nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
write the current block to the shared buffer */ else
if(hDBMonDataReady) nRoundLen = nOutputStringLen;
{
/* 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 */ /* copy the current block into the buffer */
pDBMonBuffer->ProcessId = GetCurrentProcessId(); memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen);
/* write only as many bytes as they fit in the buffer */ /* null-terminate the current block */
if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1)) pDBMonBuffer->Buffer[nRoundLen] = 0;
nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
else
nRoundLen = nOutputStringLen;
/* copy the current block into the buffer */ /* signal that the data contains meaningful data and can be read */
memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen); SetEvent(hDBMonDataReady);
}
/* else, send the current block to the kernel debugger */
else
{
/* output in blocks of 512 characters */
CHAR a_cBuffer[512];
/* null-terminate the current block */ /* write a maximum of 511 bytes */
pDBMonBuffer->Buffer[nRoundLen] = 0; if(nOutputStringLen > (sizeof(a_cBuffer) - 2))
nRoundLen = sizeof(a_cBuffer) - 2;
else
nRoundLen = nOutputStringLen;
/* signal that the data contains meaningful data and can be read */ /* copy the current block */
SetEvent(hDBMonDataReady); memcpy(a_cBuffer, _OutputString, nRoundLen);
}
/* 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 */ /* null-terminate the current block */
if(nOutputStringLen > (sizeof(a_cBuffer) - 2)) a_cBuffer[nRoundLen] = 0;
nRoundLen = sizeof(a_cBuffer) - 2;
else
nRoundLen = nOutputStringLen;
/* copy the current block */ /* send the current block to the kernel debugger */
memcpy(a_cBuffer, _OutputString, nRoundLen); DbgPrint("%s", a_cBuffer);
}
/* null-terminate the current block */ /* move to the next block */
a_cBuffer[nRoundLen] = 0; _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);
/* send the current block to the kernel debugger */ /* leave the critical section */
DbgPrint("%s", a_cBuffer); if(hDBMonDataReady != NULL)
} ReleaseMutex(hDBMonMutex);
}
/* move to the next block */ _SEH2_END;
_OutputString += nRoundLen; }
nOutputStringLen -= nRoundLen; _SEH2_END;
}
/* 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
} }
@ -447,15 +407,15 @@ OutputDebugStringW(LPCWSTR _OutputString)
if(!NT_SUCCESS(nErrCode)) if(!NT_SUCCESS(nErrCode))
{ {
/* Microsoft's kernel32.dll always prints something, even in case the conversion fails */ /* Microsoft's kernel32.dll always prints something, even in case the conversion fails */
OutputDebugStringA(""); OutputDebugStringA("");
} }
else else
{ {
/* output the converted string */ /* output the converted string */
OutputDebugStringA(strOut.Buffer); OutputDebugStringA(strOut.Buffer);
/* free the converted string */ /* free the converted string */
RtlFreeAnsiString(&strOut); RtlFreeAnsiString(&strOut);
} }
} }