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);
237 VOID WINAPI OutputDebugStringA(LPCSTR _OutputString)
240 /* FIXME: this will be pointless until GCC does SEH */
243 ULONG_PTR a_nArgs[2];
245 a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
246 a_nArgs[1] = (ULONG_PTR)_OutputString;
248 /* send the string to the user-mode debugger */
249 RaiseException(0x40010006, 0, 2, a_nArgs);
251 __except(EXCEPTION_EXECUTE_HANDLER)
255 no user-mode debugger: try the systemwide debug message monitor, or the
256 kernel debugger as a last resort
259 /* mutex used to synchronize invocations of OutputDebugString */
260 static HANDLE s_hDBMonMutex = NULL;
261 /* true if we already attempted to open/create the mutex */
262 static BOOL s_bDBMonMutexTriedOpen = FALSE;
264 /* local copy of the mutex handle */
265 HANDLE hDBMonMutex = s_hDBMonMutex;
266 /* handle to the Section of the shared buffer */
267 HANDLE hDBMonBuffer = NULL;
269 pointer to the mapped view of the shared buffer. It consist of the current
270 process id followed by the message string
272 struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
274 event: signaled by the debug message monitor when OutputDebugString can write
277 HANDLE hDBMonBufferReady = NULL;
279 event: to be signaled by OutputDebugString when it's done writing to the
282 HANDLE hDBMonDataReady = NULL;
284 /* mutex not opened, and no previous attempts to open/create it */
285 if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
287 /* open/create the mutex */
288 hDBMonMutex = K32CreateDBMonMutex();
289 /* store the handle */
290 s_hDBMonMutex = hDBMonMutex;
297 /* opening the mutex failed */
298 if(hDBMonMutex == NULL)
300 /* remember next time */
301 s_bDBMonMutexTriedOpen = TRUE;
303 /* opening the mutex succeeded */
308 /* synchronize with other invocations of OutputDebugString */
309 WaitForSingleObject(hDBMonMutex, INFINITE);
311 /* buffer of the system-wide debug message monitor */
312 hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
314 /* couldn't open the buffer: send the string to the kernel debugger */
315 if(hDBMonBuffer == NULL) break;
318 pDBMonBuffer = MapViewOfFile
321 SECTION_MAP_READ | SECTION_MAP_WRITE,
327 /* couldn't map the buffer: send the string to the kernel debugger */
328 if(pDBMonBuffer == NULL) break;
330 /* open the event signaling that the buffer can be accessed */
331 hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
333 /* couldn't open the event: send the string to the kernel debugger */
334 if(hDBMonBufferReady == NULL) break;
336 /* open the event to be signaled when the buffer has been filled */
338 OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
343 we couldn't connect to the system-wide debug message monitor: send the
344 string to the kernel debugger
346 if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
355 /* size of the current output block */
357 /* size of the remainder of the string */
358 SIZE_T nOutputStringLen;
362 /* output the whole string */
363 nOutputStringLen = strlen(_OutputString);
364 /* repeat until the string has been fully output */
365 nOutputStringLen > 0;
366 /* move to the next block */
367 _OutputString += nRoundLen, nOutputStringLen -= nRoundLen
371 we're connected to the debug monitor: write the current block to the
377 wait a maximum of 10 seconds for the debug monitor to finish processing
380 if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)
382 /* timeout or failure: give up */
386 /* write the process id into the buffer */
387 pDBMonBuffer->ProcessId = GetCurrentProcessId();
389 /* write only as many bytes as they fit in the buffer */
390 if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))
391 nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
393 nRoundLen = nOutputStringLen;
395 /* copy the current block into the buffer */
396 memcpy(pDBMonBuffer->Buffer, _OutputString, nOutputStringLen);
398 /* null-terminate the current block */
399 pDBMonBuffer->Buffer[nOutputStringLen] = 0;
401 /* signal that the data contains meaningful data and can be read */
402 SetEvent(hDBMonDataReady);
404 /* else, send the current block to the kernel debugger */
407 /* output in blocks of 512 characters */
410 /* write a maximum of 511 bytes */
411 if(nOutputStringLen > (sizeof(a_cBuffer) - 1))
412 nRoundLen = sizeof(a_cBuffer) - 1;
414 nRoundLen = nOutputStringLen;
416 /* copy the current block */
417 memcpy(a_cBuffer, _OutputString, nRoundLen);
419 /* null-terminate the current block */
420 a_cBuffer[nRoundLen] = 0;
422 /* send the current block to the kernel debugger */
423 DbgPrint("%s", a_cBuffer);
428 /* ignore access violations and let other exceptions fall through */
431 (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ?
432 EXCEPTION_EXECUTE_HANDLER :
433 EXCEPTION_CONTINUE_SEARCH
436 /* string copied verbatim from Microsoft's kernel32.dll */
437 DbgPrint("\nOutputDebugString faulted during output\n");
448 /* close all the still open resources */
449 if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady);
450 if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer);
451 if(hDBMonBuffer) CloseHandle(hDBMonBuffer);
452 if(hDBMonDataReady) CloseHandle(hDBMonDataReady);
454 /* leave the critical section */
455 ReleaseMutex(hDBMonMutex);
462 VOID WINAPI OutputDebugStringW(LPCWSTR _OutputString)
464 UNICODE_STRING wstrOut;
468 /* convert the string in ANSI */
469 RtlInitUnicodeString(&wstrOut, _OutputString);
470 nErrCode = RtlUnicodeStringToAnsiString(&strOut, &wstrOut, TRUE);
472 if(!NT_SUCCESS(nErrCode))
475 Microsoft's kernel32.dll always prints something, even in case the conversion
478 OutputDebugStringA("");
482 /* output the converted string */
483 OutputDebugStringA(strOut.Buffer);
485 /* free the converted string */
486 RtlFreeAnsiString(&strOut);