update for HEAD-2003091401
[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
238 /*
239  * @implemented
240  */
241 VOID WINAPI OutputDebugStringA(LPCSTR _OutputString)
242 {
243 #if 0
244 /* FIXME: this will be pointless until GCC does SEH */
245  __try
246  {
247   ULONG_PTR a_nArgs[2];
248
249   a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
250   a_nArgs[1] = (ULONG_PTR)_OutputString;
251
252   /* send the string to the user-mode debugger */
253   RaiseException(0x40010006, 0, 2, a_nArgs);
254  }
255  __except(EXCEPTION_EXECUTE_HANDLER)
256  {
257 #endif
258   /*
259    no user-mode debugger: try the systemwide debug message monitor, or the
260    kernel debugger as a last resort
261   */
262
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;
267
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;
272   /*
273    pointer to the mapped view of the shared buffer. It consist of the current
274    process id followed by the message string
275   */
276   struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
277   /*
278    event: signaled by the debug message monitor when OutputDebugString can write
279    to the shared buffer
280   */
281   HANDLE hDBMonBufferReady = NULL;
282   /*
283    event: to be signaled by OutputDebugString when it's done writing to the
284    shared buffer
285   */
286   HANDLE hDBMonDataReady = NULL;
287
288   /* mutex not opened, and no previous attempts to open/create it */
289   if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
290   {
291    /* open/create the mutex */
292    hDBMonMutex = K32CreateDBMonMutex();
293    /* store the handle */
294    s_hDBMonMutex = hDBMonMutex;
295   }
296
297 #if 0
298   __try
299   {
300 #endif
301    /* opening the mutex failed */
302    if(hDBMonMutex == NULL)
303    {
304     /* remember next time */
305     s_bDBMonMutexTriedOpen = TRUE;
306    }
307    /* opening the mutex succeeded */
308    else
309    {
310     do
311     {
312      /* synchronize with other invocations of OutputDebugString */
313      WaitForSingleObject(hDBMonMutex, INFINITE);
314   
315      /* buffer of the system-wide debug message monitor */
316      hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
317   
318      /* couldn't open the buffer: send the string to the kernel debugger */
319      if(hDBMonBuffer == NULL) break;
320   
321      /* map the buffer */
322      pDBMonBuffer = MapViewOfFile
323      (
324       hDBMonBuffer,
325       SECTION_MAP_READ | SECTION_MAP_WRITE,
326       0,
327       0,
328       0
329      );
330   
331      /* couldn't map the buffer: send the string to the kernel debugger */
332      if(pDBMonBuffer == NULL) break;
333   
334      /* open the event signaling that the buffer can be accessed */
335      hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
336   
337      /* couldn't open the event: send the string to the kernel debugger */
338      if(hDBMonBufferReady == NULL) break;
339   
340      /* open the event to be signaled when the buffer has been filled */
341      hDBMonDataReady =
342       OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
343     }
344     while(0);
345
346     /*
347      we couldn't connect to the system-wide debug message monitor: send the
348      string to the kernel debugger
349     */
350     if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
351    }
352
353 #if 0
354    __try
355 #else
356    do
357 #endif
358    {
359     /* size of the current output block */
360     SIZE_T nRoundLen;
361     /* size of the remainder of the string */
362     SIZE_T nOutputStringLen;
363
364     for
365     (
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
372     )
373     {
374      /*
375       we're connected to the debug monitor: write the current block to the
376       shared buffer
377      */
378      if(hDBMonDataReady)
379      {
380       /*
381        wait a maximum of 10 seconds for the debug monitor to finish processing
382        the shared buffer
383       */
384       if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)
385       {
386        /* timeout or failure: give up */
387        break;
388       }
389
390       /* write the process id into the buffer */
391       pDBMonBuffer->ProcessId = GetCurrentProcessId();
392
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;
396       else
397        nRoundLen = nOutputStringLen;
398  
399       /* copy the current block into the buffer */
400       memcpy(pDBMonBuffer->Buffer, _OutputString, nOutputStringLen);
401  
402       /* null-terminate the current block */
403       pDBMonBuffer->Buffer[nOutputStringLen] = 0;
404  
405       /* signal that the data contains meaningful data and can be read */
406       SetEvent(hDBMonDataReady);
407      }
408      /* else, send the current block to the kernel debugger */
409      else
410      {
411       /* output in blocks of 512 characters */
412       CHAR a_cBuffer[512];
413  
414       /* write a maximum of 511 bytes */
415       if(nOutputStringLen > (sizeof(a_cBuffer) - 1))
416        nRoundLen = sizeof(a_cBuffer) - 1;
417       else
418        nRoundLen = nOutputStringLen;
419  
420       /* copy the current block */
421       memcpy(a_cBuffer, _OutputString, nRoundLen);
422  
423       /* null-terminate the current block */
424       a_cBuffer[nRoundLen] = 0;
425  
426       /* send the current block to the kernel debugger */
427       DbgPrint("%s", a_cBuffer);
428      }
429     }
430    }
431 #if 0
432    /* ignore access violations and let other exceptions fall through */
433    __except
434    (
435     (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ?
436     EXCEPTION_EXECUTE_HANDLER :
437     EXCEPTION_CONTINUE_SEARCH
438    )
439    {
440     /* string copied verbatim from Microsoft's kernel32.dll */
441     DbgPrint("\nOutputDebugString faulted during output\n");
442    }
443 #else
444    while(0);
445 #endif
446
447 #if 0
448   }
449   __finally
450   {
451 #endif
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);
457
458    /* leave the critical section */
459    ReleaseMutex(hDBMonMutex);
460 #if 0
461   }
462  }
463 #endif
464 }
465
466
467 /*
468  * @implemented
469  */
470 VOID WINAPI OutputDebugStringW(LPCWSTR _OutputString)
471 {
472  UNICODE_STRING wstrOut;
473  ANSI_STRING strOut;
474  NTSTATUS nErrCode;
475
476  /* convert the string in ANSI */
477  RtlInitUnicodeString(&wstrOut, _OutputString);
478  nErrCode = RtlUnicodeStringToAnsiString(&strOut, &wstrOut, TRUE);
479
480  if(!NT_SUCCESS(nErrCode))
481  {
482   /*
483    Microsoft's kernel32.dll always prints something, even in case the conversion
484    fails
485   */
486   OutputDebugStringA("");
487  }
488  else
489  {
490   /* output the converted string */
491   OutputDebugStringA(strOut.Buffer);
492   
493   /* free the converted string */
494   RtlFreeAnsiString(&strOut);
495  }
496 }
497
498 /* EOF */