Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929/* * PROJECT: ReactOS Win32 Base API * LICENSE: GPL - See COPYING in the top level directory * FILE: dll/win32/kernel32/client/debugger.c * PURPOSE: Wrappers for the NT Debug Implementation * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES *****************************************************************/
#include <k32.h>
#include <ndk/dbgkfuncs.h>
#define NDEBUG#include <debug.h>
typedef struct _DBGSS_THREAD_DATA{ struct _DBGSS_THREAD_DATA *Next; HANDLE ThreadHandle; HANDLE ProcessHandle; DWORD ProcessId; DWORD ThreadId; BOOLEAN HandleMarked;} DBGSS_THREAD_DATA, *PDBGSS_THREAD_DATA;
#define DbgSsSetThreadData(d) \ NtCurrentTeb()->DbgSsReserved[0] = d
#define DbgSsGetThreadData() \ ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0])
/* PRIVATE FUNCTIONS *********************************************************/
static HANDLEK32CreateDBMonMutex(VOID){ static SID_IDENTIFIER_AUTHORITY siaNTAuth = {SECURITY_NT_AUTHORITY}; static SID_IDENTIFIER_AUTHORITY siaWorldAuth = {SECURITY_WORLD_SID_AUTHORITY}; HANDLE hMutex; NTSTATUS Status;
/* 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 will add the size of SIDs when they are known. */ SIZE_T nDaclBufSize = sizeof(ACL) + 3 * FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);
/* Security descriptor and attributes of the mutex */ SECURITY_DESCRIPTOR sdMutexSecurity; SECURITY_ATTRIBUTES saMutexAttribs = {sizeof(saMutexAttribs), &sdMutexSecurity, TRUE};
/* 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 does not exist, set up its security, then create it */
/* Allocate the NT AUTHORITY\SYSTEM SID */ Status = RtlAllocateAndInitializeSid(&siaNTAuth, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Allocate the BUILTIN\Administrators SID */ Status = RtlAllocateAndInitializeSid(&siaNTAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Allocate the Everyone SID */ Status = RtlAllocateAndInitializeSid(&siaWorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone); if (!NT_SUCCESS(Status)) goto Cleanup;
/* 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); if (pDaclBuf == NULL) goto Cleanup;
/* Create the DACL */ Status = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Grant the minimum required access to Everyone */ Status = RtlAddAccessAllowedAce(pDaclBuf, ACL_REVISION, SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE, psidEveryone); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Grant full access to BUILTIN\Administrators */ Status = RtlAddAccessAllowedAce(pDaclBuf, ACL_REVISION, MUTANT_ALL_ACCESS, psidAdministrators); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Grant full access to NT AUTHORITY\SYSTEM */ Status = RtlAddAccessAllowedAce(pDaclBuf, ACL_REVISION, MUTANT_ALL_ACCESS, psidSystem); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Create the security descriptor */ Status = RtlCreateSecurityDescriptor(&sdMutexSecurity, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Set the descriptor's DACL to the created ACL */ Status = RtlSetDaclSecurityDescriptor(&sdMutexSecurity, TRUE, pDaclBuf, FALSE); if (!NT_SUCCESS(Status)) goto Cleanup;
/* Create the mutex */ hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex");
Cleanup: /* Free the buffers */ if (pDaclBuf) GlobalFree(pDaclBuf); if (psidEveryone) RtlFreeSid(psidEveryone); if (psidAdministrators) RtlFreeSid(psidAdministrators); if (psidSystem) RtlFreeSid(psidSystem);
return hMutex;}
VOIDWINAPISaveThreadHandle(IN DWORD dwProcessId, IN DWORD dwThreadId, IN HANDLE hThread){ PDBGSS_THREAD_DATA ThreadData;
/* Allocate a thread structure */ ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DBGSS_THREAD_DATA)); if (!ThreadData) return;
/* Fill it out */ ThreadData->ThreadHandle = hThread; ThreadData->ProcessId = dwProcessId; ThreadData->ThreadId = dwThreadId; ThreadData->ProcessHandle = NULL; ThreadData->HandleMarked = FALSE;
/* Link it */ ThreadData->Next = DbgSsGetThreadData(); DbgSsSetThreadData(ThreadData);}
VOIDWINAPISaveProcessHandle(IN DWORD dwProcessId, IN HANDLE hProcess){ PDBGSS_THREAD_DATA ThreadData;
/* Allocate a thread structure */ ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DBGSS_THREAD_DATA)); if (!ThreadData) return;
/* Fill it out */ ThreadData->ProcessHandle = hProcess; ThreadData->ProcessId = dwProcessId; ThreadData->ThreadId = 0; ThreadData->ThreadHandle = NULL; ThreadData->HandleMarked = FALSE;
/* Link it */ ThreadData->Next = DbgSsGetThreadData(); DbgSsSetThreadData(ThreadData);}
VOIDWINAPIMarkThreadHandle(IN DWORD dwThreadId){ PDBGSS_THREAD_DATA ThreadData;
/* Loop all thread data events */ for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next) { /* Check if this one matches */ if (ThreadData->ThreadId == dwThreadId) { /* Mark the structure and break out */ ThreadData->HandleMarked = TRUE; break; } }}
VOIDWINAPIMarkProcessHandle(IN DWORD dwProcessId){ PDBGSS_THREAD_DATA ThreadData;
/* Loop all thread data events */ for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next) { /* Check if this one matches */ if ((ThreadData->ProcessId == dwProcessId) && !(ThreadData->ThreadId)) { /* Mark the structure and break out */ ThreadData->HandleMarked = TRUE; break; } }}
VOIDWINAPIRemoveHandles(IN DWORD dwProcessId, IN DWORD dwThreadId){ PDBGSS_THREAD_DATA *ThreadData; PDBGSS_THREAD_DATA ThisData;
/* Loop all thread data events */ ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved; ThisData = *ThreadData; while(ThisData) { /* Check if this one matches */ if ((ThisData->HandleMarked) && ((ThisData->ProcessId == dwProcessId) || (ThisData->ThreadId == dwThreadId))) { /* Close open handles */ if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle); if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle);
/* Unlink the thread data */ *ThreadData = ThisData->Next;
/* Free it*/ RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData); } else { /* Move to the next one */ ThreadData = &ThisData->Next; } ThisData = *ThreadData; }}
VOIDWINAPICloseAllProcessHandles(IN DWORD dwProcessId){ PDBGSS_THREAD_DATA *ThreadData; PDBGSS_THREAD_DATA ThisData;
/* Loop all thread data events */ ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved; ThisData = *ThreadData; while(ThisData) { /* Check if this one matches */ if (ThisData->ProcessId == dwProcessId) { /* Close open handles */ if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle); if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle);
/* Unlink the thread data */ *ThreadData = ThisData->Next;
/* Free it*/ RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData); } else { /* Move to the next one */ ThreadData = &ThisData->Next; } ThisData = *ThreadData; }}
HANDLEWINAPIProcessIdToHandle(IN DWORD dwProcessId){ NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Handle; CLIENT_ID ClientId;
/* If we don't have a PID, look it up */ if (dwProcessId == MAXDWORD) dwProcessId = (DWORD_PTR)CsrGetProcessId();
/* Open a handle to the process */ ClientId.UniqueThread = NULL; ClientId.UniqueProcess = UlongToHandle(dwProcessId); InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); Status = NtOpenProcess(&Handle, PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION, &ObjectAttributes, &ClientId); if (!NT_SUCCESS(Status)) { /* Fail */ BaseSetLastNTError(Status); return 0; }
/* Return the handle */ return Handle;}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */BOOLWINAPICheckRemoteDebuggerPresent(IN HANDLE hProcess, OUT PBOOL pbDebuggerPresent){ HANDLE DebugPort; NTSTATUS Status;
/* Make sure we have an output and process*/ if (!(pbDebuggerPresent) || !(hProcess)) { /* Fail */ SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
/* Check if the process has a debug object/port */ Status = NtQueryInformationProcess(hProcess, ProcessDebugPort, &DebugPort, sizeof(DebugPort), NULL); if (NT_SUCCESS(Status)) { /* Return the current state */ *pbDebuggerPresent = DebugPort != NULL; return TRUE; }
/* Otherwise, fail */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */BOOLWINAPIContinueDebugEvent(IN DWORD dwProcessId, IN DWORD dwThreadId, IN DWORD dwContinueStatus){ CLIENT_ID ClientId; NTSTATUS Status;
/* Set the Client ID */ ClientId.UniqueProcess = UlongToHandle(dwProcessId); ClientId.UniqueThread = UlongToHandle(dwThreadId);
/* Continue debugging */ Status = DbgUiContinue(&ClientId, dwContinueStatus); if (!NT_SUCCESS(Status)) { /* Fail */ BaseSetLastNTError(Status); return FALSE; }
/* Remove the process/thread handles */ RemoveHandles(dwProcessId, dwThreadId);
/* Success */ return TRUE;}
/* * @implemented */BOOLWINAPIDebugActiveProcess(IN DWORD dwProcessId){ NTSTATUS Status, Status1; HANDLE Handle;
/* Connect to the debugger */ Status = DbgUiConnectToDbg(); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return FALSE; }
/* Get the process handle */ Handle = ProcessIdToHandle(dwProcessId); if (!Handle) return FALSE;
/* Now debug the process */ Status = DbgUiDebugActiveProcess(Handle);
/* Close the handle since we're done */ Status1 = NtClose(Handle); ASSERT(NT_SUCCESS(Status1));
/* Check if debugging worked */ if (!NT_SUCCESS(Status)) { /* Fail */ BaseSetLastNTError(Status); return FALSE; }
/* Success */ return TRUE;}
/* * @implemented */BOOLWINAPIDebugActiveProcessStop(IN DWORD dwProcessId){ NTSTATUS Status, Status1; HANDLE Handle;
/* Get the process handle */ Handle = ProcessIdToHandle(dwProcessId); if (!Handle) return FALSE;
/* Close all the process handles */ CloseAllProcessHandles(dwProcessId);
/* Now stop debugging the process */ Status = DbgUiStopDebugging(Handle); Status1 = NtClose(Handle); ASSERT(NT_SUCCESS(Status1));
/* Check for failure */ if (!NT_SUCCESS(Status)) { /* Fail */ SetLastError(ERROR_ACCESS_DENIED); return FALSE; }
/* Success */ return TRUE;}
/* * @implemented */BOOLWINAPIDebugBreakProcess(IN HANDLE Process){ NTSTATUS Status;
/* Send the breakin request */ Status = DbgUiIssueRemoteBreakin(Process); if (!NT_SUCCESS(Status)) { /* Failure */ BaseSetLastNTError(Status); return FALSE; }
/* Success */ return TRUE;}
/* * @implemented */BOOLWINAPIDebugSetProcessKillOnExit(IN BOOL KillOnExit){ HANDLE Handle; NTSTATUS Status; ULONG State;
/* Get the debug object */ Handle = DbgUiGetThreadDebugObject(); if (!Handle) { /* Fail */ BaseSetLastNTError(STATUS_INVALID_HANDLE); return FALSE; }
/* Now set the kill-on-exit state */ State = KillOnExit != 0; Status = NtSetInformationDebugObject(Handle, DebugObjectKillProcessOnExitInformation, &State, sizeof(State), NULL); if (!NT_SUCCESS(Status)) { /* Fail */ BaseSetLastNTError(Status); return FALSE; }
/* Success */ return TRUE;}
/* * @implemented */BOOLWINAPIIsDebuggerPresent(VOID){ return (BOOL)NtCurrentPeb()->BeingDebugged;}
/* * @implemented */BOOLWINAPIWaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent, IN DWORD dwMilliseconds){ LARGE_INTEGER WaitTime; PLARGE_INTEGER Timeout; DBGUI_WAIT_STATE_CHANGE WaitStateChange; NTSTATUS Status;
/* Convert to NT Timeout */ Timeout = BaseFormatTimeOut(&WaitTime, dwMilliseconds);
/* Loop while we keep getting interrupted */ do { /* Call the native API */ Status = DbgUiWaitStateChange(&WaitStateChange, Timeout); } while ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC));
/* Check if the wait failed */ if (!(NT_SUCCESS(Status)) || (Status == DBG_UNABLE_TO_PROVIDE_HANDLE)) { /* Set the error code and quit */ BaseSetLastNTError(Status); return FALSE; }
/* Check if we timed out */ if (Status == STATUS_TIMEOUT) { /* Fail with a timeout error */ SetLastError(ERROR_SEM_TIMEOUT); return FALSE; }
/* Convert the structure */ Status = DbgUiConvertStateChangeStructure(&WaitStateChange, lpDebugEvent); if (!NT_SUCCESS(Status)) { /* Set the error code and quit */ BaseSetLastNTError(Status); return FALSE; }
/* Check what kind of event this was */ switch (lpDebugEvent->dwDebugEventCode) { /* New thread was created */ case CREATE_THREAD_DEBUG_EVENT:
/* Setup the thread data */ SaveThreadHandle(lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId, lpDebugEvent->u.CreateThread.hThread); break;
/* New process was created */ case CREATE_PROCESS_DEBUG_EVENT:
/* Setup the process data */ SaveProcessHandle(lpDebugEvent->dwProcessId, lpDebugEvent->u.CreateProcessInfo.hProcess);
/* Setup the thread data */ SaveThreadHandle(lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId, lpDebugEvent->u.CreateProcessInfo.hThread); break;
/* Process was exited */ case EXIT_PROCESS_DEBUG_EVENT:
/* Mark the thread data as such and fall through */ MarkProcessHandle(lpDebugEvent->dwProcessId);
/* Thread was exited */ case EXIT_THREAD_DEBUG_EVENT:
/* Mark the thread data */ MarkThreadHandle(lpDebugEvent->dwThreadId); break;
/* Nothing to do */ case EXCEPTION_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT: case OUTPUT_DEBUG_STRING_EVENT: case RIP_EVENT: break;
/* Fail anything else */ default: return FALSE; }
/* Return success */ return TRUE;}
/* * @implemented */VOIDWINAPIOutputDebugStringA(IN LPCSTR _OutputString){ _SEH2_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(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* 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 */ volatile HANDLE hDBMonMutex = s_hDBMonMutex; /* handle to the Section of the shared buffer */ volatile 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 */ volatile HANDLE hDBMonBufferReady = NULL;
/* event: to be signaled by OutputDebugString when it's done writing to the shared buffer */ volatile 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; }
_SEH2_TRY { volatile PCHAR a_cBuffer = NULL;
/* 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); }
_SEH2_TRY { /* size of the current output block */ volatile SIZE_T nRoundLen;
/* size of the remainder of the string */ volatile SIZE_T nOutputStringLen;
/* output the whole string */ nOutputStringLen = strlen(_OutputString);
do { /* 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, nRoundLen);
/* null-terminate the current block */ pDBMonBuffer->Buffer[nRoundLen] = 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 */ a_cBuffer = (CHAR*)HeapAlloc(GetProcessHeap(), 0, 512);
if (!a_cBuffer) { DbgPrint("OutputDebugStringA: Failed\n"); break; }
/* write a maximum of 511 bytes */ if (nOutputStringLen > 510) nRoundLen = 510; 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 (a_cBuffer) { HeapFree(GetProcessHeap(), 0, a_cBuffer); a_cBuffer = NULL; } }
/* move to the next block */ _OutputString += nRoundLen; nOutputStringLen -= nRoundLen; } /* repeat until the string has been fully output */ while (nOutputStringLen > 0); } /* ignore access violations and let other exceptions fall through */ _SEH2_EXCEPT((_SEH2_GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { if (a_cBuffer) HeapFree(GetProcessHeap(), 0, a_cBuffer);
/* string copied verbatim from Microsoft's kernel32.dll */ DbgPrint("\nOutputDebugString faulted during output\n"); } _SEH2_END; } _SEH2_FINALLY { /* 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 */ if (hDBMonDataReady != NULL) ReleaseMutex(hDBMonMutex); } _SEH2_END; } _SEH2_END;}
/* * @implemented */VOIDWINAPIOutputDebugStringW(IN LPCWSTR OutputString){ UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; NTSTATUS Status;
/* convert the string in ANSI */ RtlInitUnicodeString(&UnicodeString, OutputString); Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
/* OutputDebugStringW always prints something, even if conversion fails */ if (!NT_SUCCESS(Status)) AnsiString.Buffer = "";
/* Output the converted string */ OutputDebugStringA(AnsiString.Buffer);
/* free the converted string */ if (NT_SUCCESS(Status)) RtlFreeAnsiString(&AnsiString);}
/* EOF */