3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/debug/debugger.c
6 * PURPOSE: OutputDebugString()
7 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
10 /* INCLUDES ******************************************************************/
14 /* FUNCTIONS *****************************************************************/
16 /* Open or create the mutex used to communicate with the debug monitor */
17 HANDLE K32CreateDBMonMutex(void)
19 static SID_IDENTIFIER_AUTHORITY siaNTAuth = {SECURITY_NT_AUTHORITY};
20 static SID_IDENTIFIER_AUTHORITY siaWorldAuth = {SECURITY_WORLD_SID_AUTHORITY};
24 /* SIDs to be used in the DACL */
25 PSID psidSystem = NULL;
26 PSID psidAdministrators = NULL;
27 PSID psidEveryone = NULL;
29 /* buffer for the DACL */
30 PVOID pDaclBuf = NULL;
33 minimum size of the DACL: an ACL descriptor and three ACCESS_ALLOWED_ACE
34 headers. We'll add the size of SIDs when we'll know it
39 sizeof(ACCESS_ALLOWED_ACE) -
40 sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart)
43 /* security descriptor of the mutex */
44 SECURITY_DESCRIPTOR sdMutexSecurity;
46 /* attributes of the mutex object we'll create */
47 SECURITY_ATTRIBUTES saMutexAttribs =
49 sizeof(saMutexAttribs),
56 /* first, try to open the mutex */
59 SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
69 /* error other than the mutex not being found */
70 else if(GetLastError() != ERROR_FILE_NOT_FOUND)
76 /* if the mutex doesn't exist, create it */
77 #if 0 /* please uncomment when GCC supports SEH */
81 #define __leave goto l_Cleanup
83 /* first, set up the mutex security */
84 /* allocate the NT AUTHORITY\SYSTEM SID */
85 nErrCode = RtlAllocateAndInitializeSid
89 SECURITY_LOCAL_SYSTEM_RID,
101 if(!NT_SUCCESS(nErrCode)) __leave;
103 /* allocate the BUILTIN\Administrators SID */
104 nErrCode = RtlAllocateAndInitializeSid
108 SECURITY_BUILTIN_DOMAIN_RID,
109 DOMAIN_ALIAS_RID_ADMINS,
120 if(!NT_SUCCESS(nErrCode)) __leave;
122 /* allocate the Everyone SID */
123 nErrCode = RtlAllocateAndInitializeSid
139 if(!NT_SUCCESS(nErrCode)) __leave;
141 /* allocate space for the SIDs too */
142 nDaclBufSize += RtlLengthSid(psidSystem);
143 nDaclBufSize += RtlLengthSid(psidAdministrators);
144 nDaclBufSize += RtlLengthSid(psidEveryone);
146 /* allocate the buffer for the DACL */
147 pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize);
150 if(pDaclBuf == NULL) __leave;
152 /* create the DACL */
153 nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION);
156 if(!NT_SUCCESS(nErrCode)) __leave;
158 /* grant the minimum required access to Everyone */
159 nErrCode = RtlAddAccessAllowedAce
163 SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
168 if(!NT_SUCCESS(nErrCode)) __leave;
170 /* grant full access to BUILTIN\Administrators */
171 nErrCode = RtlAddAccessAllowedAce
180 if(!NT_SUCCESS(nErrCode)) __leave;
182 /* grant full access to NT AUTHORITY\SYSTEM */
183 nErrCode = RtlAddAccessAllowedAce
192 if(!NT_SUCCESS(nErrCode)) __leave;
194 /* create the security descriptor */
195 nErrCode = RtlCreateSecurityDescriptor
198 SECURITY_DESCRIPTOR_REVISION
202 if(!NT_SUCCESS(nErrCode)) __leave;
204 /* set the descriptor's DACL to the ACL we created */
205 nErrCode = RtlSetDaclSecurityDescriptor
214 if(!NT_SUCCESS(nErrCode)) __leave;
216 /* create the mutex */
217 hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex");
225 /* free the buffers */
226 if(pDaclBuf) GlobalFree(pDaclBuf);
227 if(psidEveryone) RtlFreeSid(psidEveryone);
228 if(psidAdministrators) RtlFreeSid(psidAdministrators);
229 if(psidSystem) RtlFreeSid(psidSystem);
241 VOID WINAPI OutputDebugStringA(LPCSTR _OutputString)
244 /* FIXME: this will be pointless until GCC does SEH */
247 ULONG_PTR a_nArgs[2];
249 a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
250 a_nArgs[1] = (ULONG_PTR)_OutputString;
252 /* send the string to the user-mode debugger */
253 RaiseException(0x40010006, 0, 2, a_nArgs);
255 __except(EXCEPTION_EXECUTE_HANDLER)
259 no user-mode debugger: try the systemwide debug message monitor, or the
260 kernel debugger as a last resort
263 /* mutex used to synchronize invocations of OutputDebugString */
264 static HANDLE s_hDBMonMutex = NULL;
265 /* true if we already attempted to open/create the mutex */
266 static BOOL s_bDBMonMutexTriedOpen = FALSE;
268 /* local copy of the mutex handle */
269 HANDLE hDBMonMutex = s_hDBMonMutex;
270 /* handle to the Section of the shared buffer */
271 HANDLE hDBMonBuffer = NULL;
273 pointer to the mapped view of the shared buffer. It consist of the current
274 process id followed by the message string
276 struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
278 event: signaled by the debug message monitor when OutputDebugString can write
281 HANDLE hDBMonBufferReady = NULL;
283 event: to be signaled by OutputDebugString when it's done writing to the
286 HANDLE hDBMonDataReady = NULL;
288 /* mutex not opened, and no previous attempts to open/create it */
289 if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
291 /* open/create the mutex */
292 hDBMonMutex = K32CreateDBMonMutex();
293 /* store the handle */
294 s_hDBMonMutex = hDBMonMutex;
301 /* opening the mutex failed */
302 if(hDBMonMutex == NULL)
304 /* remember next time */
305 s_bDBMonMutexTriedOpen = TRUE;
307 /* opening the mutex succeeded */
312 /* synchronize with other invocations of OutputDebugString */
313 WaitForSingleObject(hDBMonMutex, INFINITE);
315 /* buffer of the system-wide debug message monitor */
316 hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
318 /* couldn't open the buffer: send the string to the kernel debugger */
319 if(hDBMonBuffer == NULL) break;
322 pDBMonBuffer = MapViewOfFile
325 SECTION_MAP_READ | SECTION_MAP_WRITE,
331 /* couldn't map the buffer: send the string to the kernel debugger */
332 if(pDBMonBuffer == NULL) break;
334 /* open the event signaling that the buffer can be accessed */
335 hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
337 /* couldn't open the event: send the string to the kernel debugger */
338 if(hDBMonBufferReady == NULL) break;
340 /* open the event to be signaled when the buffer has been filled */
342 OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
347 we couldn't connect to the system-wide debug message monitor: send the
348 string to the kernel debugger
350 if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
359 /* size of the current output block */
361 /* size of the remainder of the string */
362 SIZE_T nOutputStringLen;
366 /* output the whole string */
367 nOutputStringLen = strlen(_OutputString);
368 /* repeat until the string has been fully output */
369 nOutputStringLen > 0;
370 /* move to the next block */
371 _OutputString += nRoundLen, nOutputStringLen -= nRoundLen
375 we're connected to the debug monitor: write the current block to the
381 wait a maximum of 10 seconds for the debug monitor to finish processing
384 if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)
386 /* timeout or failure: give up */
390 /* write the process id into the buffer */
391 pDBMonBuffer->ProcessId = GetCurrentProcessId();
393 /* write only as many bytes as they fit in the buffer */
394 if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))
395 nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
397 nRoundLen = nOutputStringLen;
399 /* copy the current block into the buffer */
400 memcpy(pDBMonBuffer->Buffer, _OutputString, nOutputStringLen);
402 /* null-terminate the current block */
403 pDBMonBuffer->Buffer[nOutputStringLen] = 0;
405 /* signal that the data contains meaningful data and can be read */
406 SetEvent(hDBMonDataReady);
408 /* else, send the current block to the kernel debugger */
411 /* output in blocks of 512 characters */
414 /* write a maximum of 511 bytes */
415 if(nOutputStringLen > (sizeof(a_cBuffer) - 1))
416 nRoundLen = sizeof(a_cBuffer) - 1;
418 nRoundLen = nOutputStringLen;
420 /* copy the current block */
421 memcpy(a_cBuffer, _OutputString, nRoundLen);
423 /* null-terminate the current block */
424 a_cBuffer[nRoundLen] = 0;
426 /* send the current block to the kernel debugger */
427 DbgPrint("%s", a_cBuffer);
432 /* ignore access violations and let other exceptions fall through */
435 (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ?
436 EXCEPTION_EXECUTE_HANDLER :
437 EXCEPTION_CONTINUE_SEARCH
440 /* string copied verbatim from Microsoft's kernel32.dll */
441 DbgPrint("\nOutputDebugString faulted during output\n");
452 /* close all the still open resources */
453 if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady);
454 if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer);
455 if(hDBMonBuffer) CloseHandle(hDBMonBuffer);
456 if(hDBMonDataReady) CloseHandle(hDBMonDataReady);
458 /* leave the critical section */
459 ReleaseMutex(hDBMonMutex);
470 VOID WINAPI OutputDebugStringW(LPCWSTR _OutputString)
472 UNICODE_STRING wstrOut;
476 /* convert the string in ANSI */
477 RtlInitUnicodeString(&wstrOut, _OutputString);
478 nErrCode = RtlUnicodeStringToAnsiString(&strOut, &wstrOut, TRUE);
480 if(!NT_SUCCESS(nErrCode))
483 Microsoft's kernel32.dll always prints something, even in case the conversion
486 OutputDebugStringA("");
490 /* output the converted string */
491 OutputDebugStringA(strOut.Buffer);
493 /* free the converted string */
494 RtlFreeAnsiString(&strOut);