update for HEAD-2003050101
[reactos.git] / lib / kernel32 / debug / output.c
1 /* $Id$
2  *
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>
8  */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <k32.h>
13
14 /* FUNCTIONS *****************************************************************/
15
16 /* Open or create the mutex used to communicate with the debug monitor */
17 HANDLE K32CreateDBMonMutex(void)
18 {
19  static SID_IDENTIFIER_AUTHORITY siaNTAuth = SECURITY_NT_AUTHORITY;
20  static SID_IDENTIFIER_AUTHORITY siaWorldAuth = SECURITY_WORLD_SID_AUTHORITY;
21
22  HANDLE hMutex;
23
24  /* SIDs to be used in the DACL */
25  PSID psidSystem = NULL;
26  PSID psidAdministrators = NULL;
27  PSID psidEveryone = NULL;
28  
29  /* buffer for the DACL */
30  PVOID pDaclBuf = NULL;
31
32  /*
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
35  */
36  SIZE_T nDaclBufSize =
37   sizeof(ACL) +
38   (
39    sizeof(ACCESS_ALLOWED_ACE) -
40    sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart)
41   ) * 3;
42
43  /* security descriptor of the mutex */
44  SECURITY_DESCRIPTOR sdMutexSecurity;
45  
46  /* attributes of the mutex object we'll create */
47  SECURITY_ATTRIBUTES saMutexAttribs =
48  {
49   sizeof(saMutexAttribs),
50   &sdMutexSecurity,
51   TRUE
52  };
53
54  NTSTATUS nErrCode;
55
56  /* first, try to open the mutex */
57  hMutex = OpenMutexW
58  (
59   SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
60   TRUE,
61   L"DBWinMutex"
62  );
63
64  if(hMutex != NULL)
65  {
66   /* success */
67   return hMutex;
68  }
69  /* error other than the mutex not being found */
70  else if(GetLastError() != ERROR_FILE_NOT_FOUND)
71  {
72   /* failure */
73   return NULL;
74  }
75
76  /* if the mutex doesn't exist, create it */
77 #if 0 /* please uncomment when GCC supports SEH */
78  __try
79  {
80 #else
81 #define __leave goto l_Cleanup
82 #endif
83   /* first, set up the mutex security */
84   /* allocate the NT AUTHORITY\SYSTEM SID */
85   nErrCode = RtlAllocateAndInitializeSid
86   (
87    &siaNTAuth,
88    1,
89    SECURITY_LOCAL_SYSTEM_RID,
90    0,
91    0,
92    0,
93    0,
94    0,
95    0,
96    0,
97    &psidSystem
98   );
99
100   /* failure */
101   if(!NT_SUCCESS(nErrCode)) __leave;
102
103   /* allocate the BUILTIN\Administrators SID */
104   nErrCode = RtlAllocateAndInitializeSid
105   (
106    &siaNTAuth,
107    2,
108    SECURITY_BUILTIN_DOMAIN_RID,
109    DOMAIN_ALIAS_RID_ADMINS,
110    0,
111    0,
112    0,
113    0,
114    0,
115    0,
116    &psidAdministrators
117   );
118   
119   /* failure */
120   if(!NT_SUCCESS(nErrCode)) __leave;
121
122   /* allocate the Everyone SID */
123   nErrCode = RtlAllocateAndInitializeSid
124   (
125    &siaWorldAuth,
126    1,
127    0,
128    0,
129    0,
130    0,
131    0,
132    0,
133    0,
134    0,
135    &psidEveryone
136   );
137   
138   /* failure */
139   if(!NT_SUCCESS(nErrCode)) __leave;
140
141   /* allocate space for the SIDs too */
142   nDaclBufSize += RtlLengthSid(psidSystem);
143   nDaclBufSize += RtlLengthSid(psidAdministrators);
144   nDaclBufSize += RtlLengthSid(psidEveryone);
145
146   /* allocate the buffer for the DACL */
147   pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize);
148
149   /* failure */
150   if(pDaclBuf == NULL) __leave;
151
152   /* create the DACL */
153   nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION);
154
155   /* failure */
156   if(!NT_SUCCESS(nErrCode)) __leave;
157
158   /* grant the minimum required access to Everyone */
159   nErrCode = RtlAddAccessAllowedAce
160   (
161    pDaclBuf,
162    ACL_REVISION,
163    SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
164    psidEveryone
165   );
166
167   /* failure */
168   if(!NT_SUCCESS(nErrCode)) __leave;
169
170   /* grant full access to BUILTIN\Administrators */
171   nErrCode = RtlAddAccessAllowedAce
172   (
173    pDaclBuf,
174    ACL_REVISION,
175    MUTANT_ALL_ACCESS,
176    psidAdministrators
177   );
178
179   /* failure */
180   if(!NT_SUCCESS(nErrCode)) __leave;
181
182   /* grant full access to NT AUTHORITY\SYSTEM */
183   nErrCode = RtlAddAccessAllowedAce
184   (
185    pDaclBuf,
186    ACL_REVISION,
187    MUTANT_ALL_ACCESS,
188    psidSystem
189   );
190
191   /* failure */
192   if(!NT_SUCCESS(nErrCode)) __leave;
193
194   /* create the security descriptor */
195   nErrCode = RtlCreateSecurityDescriptor
196   (     
197    &sdMutexSecurity,
198    SECURITY_DESCRIPTOR_REVISION
199   );
200
201   /* failure */
202   if(!NT_SUCCESS(nErrCode)) __leave;
203
204   /* set the descriptor's DACL to the ACL we created */
205   nErrCode = RtlSetDaclSecurityDescriptor
206   (
207    &sdMutexSecurity,
208    TRUE,
209    pDaclBuf,
210    FALSE
211   );
212
213   /* failure */
214   if(!NT_SUCCESS(nErrCode)) __leave;
215
216   /* create the mutex */
217   hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex");
218 #if 0
219  }
220  __finally
221  {
222 #else
223 l_Cleanup:
224 #endif
225   /* free the buffers */
226   if(pDaclBuf) GlobalFree(pDaclBuf);
227   if(psidEveryone) RtlFreeSid(psidEveryone);
228   if(psidAdministrators) RtlFreeSid(psidAdministrators);
229   if(psidSystem) RtlFreeSid(psidSystem);
230 #if 0
231  }
232 #endif
233  
234  return hMutex;
235 }
236
237 VOID WINAPI OutputDebugStringA(LPCSTR _OutputString)
238 {
239 #if 0
240 /* FIXME: this will be pointless until GCC does SEH */
241  __try
242  {
243   ULONG_PTR a_nArgs[2];
244
245   a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
246   a_nArgs[1] = (ULONG_PTR)_OutputString;
247
248   /* send the string to the user-mode debugger */
249   RaiseException(0x40010006, 0, 2, a_nArgs);
250  }
251  __except(EXCEPTION_EXECUTE_HANDLER)
252  {
253 #endif
254   /*
255    no user-mode debugger: try the systemwide debug message monitor, or the
256    kernel debugger as a last resort
257   */
258
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;
263
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;
268   /*
269    pointer to the mapped view of the shared buffer. It consist of the current
270    process id followed by the message string
271   */
272   struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
273   /*
274    event: signaled by the debug message monitor when OutputDebugString can write
275    to the shared buffer
276   */
277   HANDLE hDBMonBufferReady = NULL;
278   /*
279    event: to be signaled by OutputDebugString when it's done writing to the
280    shared buffer
281   */
282   HANDLE hDBMonDataReady = NULL;
283
284   /* mutex not opened, and no previous attempts to open/create it */
285   if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
286   {
287    /* open/create the mutex */
288    hDBMonMutex = K32CreateDBMonMutex();
289    /* store the handle */
290    s_hDBMonMutex = hDBMonMutex;
291   }
292
293 #if 0
294   __try
295   {
296 #endif
297    /* opening the mutex failed */
298    if(hDBMonMutex == NULL)
299    {
300     /* remember next time */
301     s_bDBMonMutexTriedOpen = TRUE;
302    }
303    /* opening the mutex succeeded */
304    else
305    {
306     do
307     {
308      /* synchronize with other invocations of OutputDebugString */
309      WaitForSingleObject(hDBMonMutex, INFINITE);
310   
311      /* buffer of the system-wide debug message monitor */
312      hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
313   
314      /* couldn't open the buffer: send the string to the kernel debugger */
315      if(hDBMonBuffer == NULL) break;
316   
317      /* map the buffer */
318      pDBMonBuffer = MapViewOfFile
319      (
320       hDBMonBuffer,
321       SECTION_MAP_READ | SECTION_MAP_WRITE,
322       0,
323       0,
324       0
325      );
326   
327      /* couldn't map the buffer: send the string to the kernel debugger */
328      if(pDBMonBuffer == NULL) break;
329   
330      /* open the event signaling that the buffer can be accessed */
331      hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
332   
333      /* couldn't open the event: send the string to the kernel debugger */
334      if(hDBMonBufferReady == NULL) break;
335   
336      /* open the event to be signaled when the buffer has been filled */
337      hDBMonDataReady =
338       OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
339     }
340     while(0);
341
342     /*
343      we couldn't connect to the system-wide debug message monitor: send the
344      string to the kernel debugger
345     */
346     if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
347    }
348
349 #if 0
350    __try
351 #else
352    do
353 #endif
354    {
355     /* size of the current output block */
356     SIZE_T nRoundLen;
357     /* size of the remainder of the string */
358     SIZE_T nOutputStringLen;
359
360     for
361     (
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
368     )
369     {
370      /*
371       we're connected to the debug monitor: write the current block to the
372       shared buffer
373      */
374      if(hDBMonDataReady)
375      {
376       /*
377        wait a maximum of 10 seconds for the debug monitor to finish processing
378        the shared buffer
379       */
380       if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)
381       {
382        /* timeout or failure: give up */
383        break;
384       }
385
386       /* write the process id into the buffer */
387       pDBMonBuffer->ProcessId = GetCurrentProcessId();
388
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;
392       else
393        nRoundLen = nOutputStringLen;
394  
395       /* copy the current block into the buffer */
396       memcpy(pDBMonBuffer->Buffer, _OutputString, nOutputStringLen);
397  
398       /* null-terminate the current block */
399       pDBMonBuffer->Buffer[nOutputStringLen] = 0;
400  
401       /* signal that the data contains meaningful data and can be read */
402       SetEvent(hDBMonDataReady);
403      }
404      /* else, send the current block to the kernel debugger */
405      else
406      {
407       /* output in blocks of 512 characters */
408       CHAR a_cBuffer[512];
409  
410       /* write a maximum of 511 bytes */
411       if(nOutputStringLen > (sizeof(a_cBuffer) - 1))
412        nRoundLen = sizeof(a_cBuffer) - 1;
413       else
414        nRoundLen = nOutputStringLen;
415  
416       /* copy the current block */
417       memcpy(a_cBuffer, _OutputString, nRoundLen);
418  
419       /* null-terminate the current block */
420       a_cBuffer[nRoundLen] = 0;
421  
422       /* send the current block to the kernel debugger */
423       DbgPrint("%s", a_cBuffer);
424      }
425     }
426    }
427 #if 0
428    /* ignore access violations and let other exceptions fall through */
429    __except
430    (
431     (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ?
432     EXCEPTION_EXECUTE_HANDLER :
433     EXCEPTION_CONTINUE_SEARCH
434    )
435    {
436     /* string copied verbatim from Microsoft's kernel32.dll */
437     DbgPrint("\nOutputDebugString faulted during output\n");
438    }
439 #else
440    while(0);
441 #endif
442
443 #if 0
444   }
445   __finally
446   {
447 #endif
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);
453
454    /* leave the critical section */
455    ReleaseMutex(hDBMonMutex);
456 #if 0
457   }
458  }
459 #endif
460 }
461
462 VOID WINAPI OutputDebugStringW(LPCWSTR _OutputString)
463 {
464  UNICODE_STRING wstrOut;
465  ANSI_STRING strOut;
466  NTSTATUS nErrCode;
467
468  /* convert the string in ANSI */
469  RtlInitUnicodeString(&wstrOut, _OutputString);
470  nErrCode = RtlUnicodeStringToAnsiString(&strOut, &wstrOut, TRUE);
471
472  if(!NT_SUCCESS(nErrCode))
473  {
474   /*
475    Microsoft's kernel32.dll always prints something, even in case the conversion
476    fails
477   */
478   OutputDebugStringA("");
479  }
480  else
481  {
482   /* output the converted string */
483   OutputDebugStringA(strOut.Buffer);
484   
485   /* free the converted string */
486   RtlFreeAnsiString(&strOut);
487  }
488 }
489
490 /* EOF */