1 /* $Id: output.c,v 1.2 2003/07/10 18:50:50 chorns Exp $
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
);