- debugging support APIs moved into their own directory
authorKJK::Hyperion <hackbunny@reactos.org>
Mon, 31 Mar 2003 22:28:59 +0000 (22:28 +0000)
committerKJK::Hyperion <hackbunny@reactos.org>
Mon, 31 Mar 2003 22:28:59 +0000 (22:28 +0000)
 - reversed the Debug Monitor protocol, implemented OutputDebugString accordingly
 - added a handful of new functions introduced in NT 5.1, either stubbed out or implemented

svn path=/trunk/; revision=4461

reactos/lib/kernel32/debug/break.c [new file with mode: 0644]
reactos/lib/kernel32/debug/debugger.c [new file with mode: 0644]
reactos/lib/kernel32/debug/output.c [new file with mode: 0644]

diff --git a/reactos/lib/kernel32/debug/break.c b/reactos/lib/kernel32/debug/break.c
new file mode 100644 (file)
index 0000000..1417ca7
--- /dev/null
@@ -0,0 +1,29 @@
+/* $Id: break.c,v 1.1 2003/03/31 22:28:59 hyperion Exp $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
+ * FILE:            lib/kernel32/debug/debugger.c
+ * PURPOSE:         DebugBreakProcess()
+ * PROGRAMMER:      KJK::Hyperion <noog@libero.it>
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <k32.h>
+
+/* FUNCTIONS *****************************************************************/
+
+BOOL WINAPI DebugBreakProcess(HANDLE Process)
+{
+ NTSTATUS nErrCode = DbgUiIssueRemoteBreakin(Process);
+ if(!NT_SUCCESS(nErrCode))
+ {
+  SetLastErrorByStatus(nErrCode);
+  return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* EOF */
diff --git a/reactos/lib/kernel32/debug/debugger.c b/reactos/lib/kernel32/debug/debugger.c
new file mode 100644 (file)
index 0000000..0640c97
--- /dev/null
@@ -0,0 +1,73 @@
+/* $Id: debugger.c,v 1.1 2003/03/31 22:28:59 hyperion Exp $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
+ * FILE:            lib/kernel32/debug/debugger.c
+ * PURPOSE:         Win32 Debugger API
+ * PROGRAMMER:      ???
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <k32.h>
+
+/* FUNCTIONS *****************************************************************/
+
+BOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess, PBOOL pbDebuggerPresent)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI ContinueDebugEvent
+(
+ DWORD dwProcessId,
+ DWORD dwThreadId,
+ DWORD dwContinueStatus
+)
+{
+ CLIENT_ID ClientId;
+ NTSTATUS Status;
+
+ ClientId.UniqueProcess = (HANDLE)dwProcessId;
+ ClientId.UniqueThread = (HANDLE)dwThreadId;
+
+ Status = DbgUiContinue(&ClientId, dwContinueStatus);
+
+ if(!NT_SUCCESS(Status))
+ {
+  SetLastErrorByStatus(Status);
+  return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI DebugActiveProcess(DWORD dwProcessId)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI DebugSetProcessKillOnExit(BOOL KillOnExit)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL WINAPI IsDebuggerPresent(VOID)
+{
+ return (WINBOOL)NtCurrentPeb()->BeingDebugged;
+}
+
+BOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds)
+{
+}
+
+/* EOF */
diff --git a/reactos/lib/kernel32/debug/output.c b/reactos/lib/kernel32/debug/output.c
new file mode 100644 (file)
index 0000000..1ce6056
--- /dev/null
@@ -0,0 +1,490 @@
+/* $Id: output.c,v 1.1 2003/03/31 22:28:59 hyperion Exp $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
+ * FILE:            lib/kernel32/debug/debugger.c
+ * PURPOSE:         OutputDebugString()
+ * PROGRAMMER:      KJK::Hyperion <noog@libero.it>
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <k32.h>
+
+/* FUNCTIONS *****************************************************************/
+
+/* Open or create the mutex used to communicate with the debug monitor */
+HANDLE K32CreateDBMonMutex(void)
+{
+ static SID_IDENTIFIER_AUTHORITY siaNTAuth = SECURITY_NT_AUTHORITY;
+ static SID_IDENTIFIER_AUTHORITY siaWorldAuth = SECURITY_WORLD_SID_AUTHORITY;
+
+ HANDLE hMutex;
+
+ /* SIDs to be used in the DACL */
+ PSID psidSystem = NULL;
+ PSID psidAdministrators = NULL;
+ PSID psidEveryone = NULL;
+ /* buffer for the DACL */
+ PVOID pDaclBuf = NULL;
+
+ /*
+  minimum size of the DACL: an ACL descriptor and three ACCESS_ALLOWED_ACE
+  headers. We'll add the size of SIDs when we'll know it
+ */
+ SIZE_T nDaclBufSize =
+  sizeof(ACL) +
+  (
+   sizeof(ACCESS_ALLOWED_ACE) -
+   sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart)
+  ) * 3;
+
+ /* security descriptor of the mutex */
+ SECURITY_DESCRIPTOR sdMutexSecurity;
+ /* attributes of the mutex object we'll create */
+ SECURITY_ATTRIBUTES saMutexAttribs =
+ {
+  sizeof(saMutexAttribs),
+  &sdMutexSecurity,
+  TRUE
+ };
+
+ NTSTATUS nErrCode;
+
+ /* first, try to open the mutex */
+ hMutex = OpenMutexW
+ (
+  SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
+  TRUE,
+  L"DBWinMutex"
+ );
+
+ if(hMutex != NULL)
+ {
+  /* success */
+  return hMutex;
+ }
+ /* error other than the mutex not being found */
+ else if(GetLastError() != ERROR_FILE_NOT_FOUND)
+ {
+  /* failure */
+  return NULL;
+ }
+
+ /* if the mutex doesn't exist, create it */
+#if 0 /* please uncomment when GCC supports SEH */
+ __try
+ {
+#else
+#define __leave goto l_Cleanup
+#endif
+  /* first, set up the mutex security */
+  /* allocate the NT AUTHORITY\SYSTEM SID */
+  nErrCode = RtlAllocateAndInitializeSid
+  (
+   &siaNTAuth,
+   1,
+   SECURITY_LOCAL_SYSTEM_RID,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   &psidSystem
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* allocate the BUILTIN\Administrators SID */
+  nErrCode = RtlAllocateAndInitializeSid
+  (
+   &siaNTAuth,
+   2,
+   SECURITY_BUILTIN_DOMAIN_RID,
+   DOMAIN_ALIAS_RID_ADMINS,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   &psidAdministrators
+  );
+  
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* allocate the Everyone SID */
+  nErrCode = RtlAllocateAndInitializeSid
+  (
+   &siaWorldAuth,
+   1,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   0,
+   &psidEveryone
+  );
+  
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* allocate space for the SIDs too */
+  nDaclBufSize += RtlLengthSid(psidSystem);
+  nDaclBufSize += RtlLengthSid(psidAdministrators);
+  nDaclBufSize += RtlLengthSid(psidEveryone);
+
+  /* allocate the buffer for the DACL */
+  pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize);
+
+  /* failure */
+  if(pDaclBuf == NULL) __leave;
+
+  /* create the DACL */
+  nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION);
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* grant the minimum required access to Everyone */
+  nErrCode = RtlAddAccessAllowedAce
+  (
+   pDaclBuf,
+   ACL_REVISION,
+   SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE,
+   psidEveryone
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* grant full access to BUILTIN\Administrators */
+  nErrCode = RtlAddAccessAllowedAce
+  (
+   pDaclBuf,
+   ACL_REVISION,
+   MUTANT_ALL_ACCESS,
+   psidAdministrators
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* grant full access to NT AUTHORITY\SYSTEM */
+  nErrCode = RtlAddAccessAllowedAce
+  (
+   pDaclBuf,
+   ACL_REVISION,
+   MUTANT_ALL_ACCESS,
+   psidSystem
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* create the security descriptor */
+  nErrCode = RtlCreateSecurityDescriptor
+  (     
+   &sdMutexSecurity,
+   SECURITY_DESCRIPTOR_REVISION
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* set the descriptor's DACL to the ACL we created */
+  nErrCode = RtlSetDaclSecurityDescriptor
+  (
+   &sdMutexSecurity,
+   TRUE,
+   pDaclBuf,
+   FALSE
+  );
+
+  /* failure */
+  if(!NT_SUCCESS(nErrCode)) __leave;
+
+  /* create the mutex */
+  hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex");
+#if 0
+ }
+ __finally
+ {
+#else
+l_Cleanup:
+#endif
+  /* free the buffers */
+  if(pDaclBuf) GlobalFree(pDaclBuf);
+  if(psidEveryone) RtlFreeSid(psidEveryone);
+  if(psidAdministrators) RtlFreeSid(psidAdministrators);
+  if(psidSystem) RtlFreeSid(psidSystem);
+#if 0
+ }
+#endif
+ return hMutex;
+}
+
+VOID WINAPI OutputDebugStringA(LPCSTR _OutputString)
+{
+#if 0
+/* FIXME: this will be pointless until GCC does SEH */
+ __try
+ {
+  ULONG_PTR a_nArgs[2];
+
+  a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
+  a_nArgs[1] = (ULONG_PTR)_OutputString;
+
+  /* send the string to the user-mode debugger */
+  RaiseException(0x40010006, 0, 2, a_nArgs);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+#endif
+  /*
+   no user-mode debugger: try the systemwide debug message monitor, or the
+   kernel debugger as a last resort
+  */
+
+  /* mutex used to synchronize invocations of OutputDebugString */
+  static HANDLE s_hDBMonMutex = NULL;
+  /* true if we already attempted to open/create the mutex */
+  static BOOL s_bDBMonMutexTriedOpen = FALSE;
+
+  /* local copy of the mutex handle */
+  HANDLE hDBMonMutex = s_hDBMonMutex;
+  /* handle to the Section of the shared buffer */
+  HANDLE hDBMonBuffer = NULL;
+  /*
+   pointer to the mapped view of the shared buffer. It consist of the current
+   process id followed by the message string
+  */
+  struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
+  /*
+   event: signaled by the debug message monitor when OutputDebugString can write
+   to the shared buffer
+  */
+  HANDLE hDBMonBufferReady = NULL;
+  /*
+   event: to be signaled by OutputDebugString when it's done writing to the
+   shared buffer
+  */
+  HANDLE hDBMonDataReady = NULL;
+
+  /* mutex not opened, and no previous attempts to open/create it */
+  if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
+  {
+   /* open/create the mutex */
+   hDBMonMutex = K32CreateDBMonMutex();
+   /* store the handle */
+   s_hDBMonMutex = hDBMonMutex;
+  }
+
+#if 0
+  __try
+  {
+#endif
+   /* opening the mutex failed */
+   if(hDBMonMutex == NULL)
+   {
+    /* remember next time */
+    s_bDBMonMutexTriedOpen = TRUE;
+   }
+   /* opening the mutex succeeded */
+   else
+   {
+    do
+    {
+     /* synchronize with other invocations of OutputDebugString */
+     WaitForSingleObject(hDBMonMutex, INFINITE);
+  
+     /* buffer of the system-wide debug message monitor */
+     hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
+  
+     /* couldn't open the buffer: send the string to the kernel debugger */
+     if(hDBMonBuffer == NULL) break;
+  
+     /* map the buffer */
+     pDBMonBuffer = MapViewOfFile
+     (
+      hDBMonBuffer,
+      SECTION_MAP_READ | SECTION_MAP_WRITE,
+      0,
+      0,
+      0
+     );
+  
+     /* couldn't map the buffer: send the string to the kernel debugger */
+     if(pDBMonBuffer == NULL) break;
+  
+     /* open the event signaling that the buffer can be accessed */
+     hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
+  
+     /* couldn't open the event: send the string to the kernel debugger */
+     if(hDBMonBufferReady == NULL) break;
+  
+     /* open the event to be signaled when the buffer has been filled */
+     hDBMonDataReady =
+      OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
+    }
+    while(0);
+
+    /*
+     we couldn't connect to the system-wide debug message monitor: send the
+     string to the kernel debugger
+    */
+    if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
+   }
+
+#if 0
+   __try
+#else
+   do
+#endif
+   {
+    /* size of the current output block */
+    SIZE_T nRoundLen;
+    /* size of the remainder of the string */
+    SIZE_T nOutputStringLen;
+
+    for
+    (
+     /* output the whole string */
+     nOutputStringLen = strlen(_OutputString);
+     /* repeat until the string has been fully output */
+     nOutputStringLen > 0;
+     /* move to the next block */
+     _OutputString += nRoundLen, nOutputStringLen -= nRoundLen
+    )
+    {
+     /*
+      we're connected to the debug monitor: write the current block to the
+      shared buffer
+     */
+     if(hDBMonDataReady)
+     {
+      /*
+       wait a maximum of 10 seconds for the debug monitor to finish processing
+       the shared buffer
+      */
+      if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)
+      {
+       /* timeout or failure: give up */
+       break;
+      }
+
+      /* write the process id into the buffer */
+      pDBMonBuffer->ProcessId = GetCurrentProcessId();
+
+      /* write only as many bytes as they fit in the buffer */
+      if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))
+       nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
+      else
+       nRoundLen = nOutputStringLen;
+      /* copy the current block into the buffer */
+      memcpy(pDBMonBuffer->Buffer, _OutputString, nOutputStringLen);
+      /* null-terminate the current block */
+      pDBMonBuffer->Buffer[nOutputStringLen] = 0;
+      /* signal that the data contains meaningful data and can be read */
+      SetEvent(hDBMonDataReady);
+     }
+     /* else, send the current block to the kernel debugger */
+     else
+     {
+      /* output in blocks of 512 characters */
+      CHAR a_cBuffer[512];
+      /* write a maximum of 511 bytes */
+      if(nOutputStringLen > (sizeof(a_cBuffer) - 1))
+       nRoundLen = sizeof(a_cBuffer) - 1;
+      else
+       nRoundLen = nOutputStringLen;
+      /* copy the current block */
+      memcpy(a_cBuffer, _OutputString, nRoundLen);
+      /* null-terminate the current block */
+      a_cBuffer[nRoundLen] = 0;
+      /* send the current block to the kernel debugger */
+      DbgPrint("%s", a_cBuffer);
+     }
+    }
+   }
+#if 0
+   /* ignore access violations and let other exceptions fall through */
+   __except
+   (
+    (GetExceptionCode() == STATUS_ACCESS_VIOLATION) ?
+    EXCEPTION_EXECUTE_HANDLER :
+    EXCEPTION_CONTINUE_SEARCH
+   )
+   {
+    /* string copied verbatim from Microsoft's kernel32.dll */
+    DbgPrint("\nOutputDebugString faulted during output\n");
+   }
+#else
+   while(0);
+#endif
+
+#if 0
+  }
+  __finally
+  {
+#endif
+   /* close all the still open resources */
+   if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady);
+   if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer);
+   if(hDBMonBuffer) CloseHandle(hDBMonBuffer);
+   if(hDBMonDataReady) CloseHandle(hDBMonDataReady);
+
+   /* leave the critical section */
+   ReleaseMutex(hDBMonMutex);
+#if 0
+  }
+ }
+#endif
+}
+
+VOID WINAPI OutputDebugStringW(LPCWSTR _OutputString)
+{
+ UNICODE_STRING wstrOut;
+ ANSI_STRING strOut;
+ NTSTATUS nErrCode;
+
+ /* convert the string in ANSI */
+ RtlInitUnicodeString(&wstrOut, _OutputString);
+ nErrCode = RtlUnicodeStringToAnsiString(&strOut, &wstrOut, TRUE);
+
+ if(!NT_SUCCESS(nErrCode))
+ {
+  /*
+   Microsoft's kernel32.dll always prints something, even in case the conversion
+   fails
+  */
+  OutputDebugStringA("");
+ }
+ else
+ {
+  /* output the converted string */
+  OutputDebugStringA(strOut.Buffer);
+  
+  /* free the converted string */
+  RtlFreeAnsiString(&strOut);
+ }
+}
+
+/* EOF */