Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendebugger.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Win32 Base API 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: dll/win32/kernel32/debug/debugger.c 00005 * PURPOSE: Wrappers for the NT Debug Implementation 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES *****************************************************************/ 00010 00011 #include <k32.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 typedef struct _DBGSS_THREAD_DATA 00016 { 00017 struct _DBGSS_THREAD_DATA *Next; 00018 HANDLE ThreadHandle; 00019 HANDLE ProcessHandle; 00020 DWORD ProcessId; 00021 DWORD ThreadId; 00022 BOOLEAN HandleMarked; 00023 } DBGSS_THREAD_DATA, *PDBGSS_THREAD_DATA; 00024 00025 #define DbgSsSetThreadData(d) \ 00026 NtCurrentTeb()->DbgSsReserved[0] = d 00027 00028 #define DbgSsGetThreadData() \ 00029 ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0]) 00030 00031 /* PRIVATE FUNCTIONS *********************************************************/ 00032 00033 static 00034 HANDLE 00035 K32CreateDBMonMutex(void) 00036 { 00037 static SID_IDENTIFIER_AUTHORITY siaNTAuth = {SECURITY_NT_AUTHORITY}; 00038 static SID_IDENTIFIER_AUTHORITY siaWorldAuth = {SECURITY_WORLD_SID_AUTHORITY}; 00039 HANDLE hMutex; 00040 00041 /* SIDs to be used in the DACL */ 00042 PSID psidSystem = NULL; 00043 PSID psidAdministrators = NULL; 00044 PSID psidEveryone = NULL; 00045 00046 /* buffer for the DACL */ 00047 PVOID pDaclBuf = NULL; 00048 00049 /* minimum size of the DACL: an ACL descriptor and three ACCESS_ALLOWED_ACE 00050 headers. We'll add the size of SIDs when we'll know it 00051 */ 00052 SIZE_T nDaclBufSize = 00053 sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - 00054 sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart)) * 3; 00055 00056 /* security descriptor of the mutex */ 00057 SECURITY_DESCRIPTOR sdMutexSecurity; 00058 00059 /* attributes of the mutex object we'll create */ 00060 SECURITY_ATTRIBUTES saMutexAttribs = {sizeof(saMutexAttribs), 00061 &sdMutexSecurity, 00062 TRUE}; 00063 00064 NTSTATUS nErrCode; 00065 00066 /* first, try to open the mutex */ 00067 hMutex = OpenMutexW (SYNCHRONIZE | READ_CONTROL | MUTANT_QUERY_STATE, 00068 TRUE, 00069 L"DBWinMutex"); 00070 00071 if(hMutex != NULL) 00072 { 00073 /* success */ 00074 return hMutex; 00075 } 00076 /* error other than the mutex not being found */ 00077 else if(GetLastError() != ERROR_FILE_NOT_FOUND) 00078 { 00079 /* failure */ 00080 return NULL; 00081 } 00082 00083 /* if the mutex doesn't exist, create it */ 00084 00085 /* first, set up the mutex security */ 00086 /* allocate the NT AUTHORITY\SYSTEM SID */ 00087 nErrCode = RtlAllocateAndInitializeSid(&siaNTAuth, 00088 1, 00089 SECURITY_LOCAL_SYSTEM_RID, 00090 0, 00091 0, 00092 0, 00093 0, 00094 0, 00095 0, 00096 0, 00097 &psidSystem); 00098 00099 /* failure */ 00100 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00101 00102 /* allocate the BUILTIN\Administrators SID */ 00103 nErrCode = RtlAllocateAndInitializeSid(&siaNTAuth, 00104 2, 00105 SECURITY_BUILTIN_DOMAIN_RID, 00106 DOMAIN_ALIAS_RID_ADMINS, 00107 0, 00108 0, 00109 0, 00110 0, 00111 0, 00112 0, 00113 &psidAdministrators); 00114 00115 /* failure */ 00116 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00117 00118 /* allocate the Everyone SID */ 00119 nErrCode = RtlAllocateAndInitializeSid(&siaWorldAuth, 00120 1, 00121 0, 00122 0, 00123 0, 00124 0, 00125 0, 00126 0, 00127 0, 00128 0, 00129 &psidEveryone); 00130 00131 /* failure */ 00132 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00133 00134 /* allocate space for the SIDs too */ 00135 nDaclBufSize += RtlLengthSid(psidSystem); 00136 nDaclBufSize += RtlLengthSid(psidAdministrators); 00137 nDaclBufSize += RtlLengthSid(psidEveryone); 00138 00139 /* allocate the buffer for the DACL */ 00140 pDaclBuf = GlobalAlloc(GMEM_FIXED, nDaclBufSize); 00141 00142 /* failure */ 00143 if(pDaclBuf == NULL) goto l_Cleanup; 00144 00145 /* create the DACL */ 00146 nErrCode = RtlCreateAcl(pDaclBuf, nDaclBufSize, ACL_REVISION); 00147 00148 /* failure */ 00149 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00150 00151 /* grant the minimum required access to Everyone */ 00152 nErrCode = RtlAddAccessAllowedAce(pDaclBuf, 00153 ACL_REVISION, 00154 SYNCHRONIZE | 00155 READ_CONTROL | 00156 MUTANT_QUERY_STATE, 00157 psidEveryone); 00158 00159 /* failure */ 00160 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00161 00162 /* grant full access to BUILTIN\Administrators */ 00163 nErrCode = RtlAddAccessAllowedAce(pDaclBuf, 00164 ACL_REVISION, 00165 MUTANT_ALL_ACCESS, 00166 psidAdministrators); 00167 00168 /* failure */ 00169 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00170 00171 /* grant full access to NT AUTHORITY\SYSTEM */ 00172 nErrCode = RtlAddAccessAllowedAce(pDaclBuf, 00173 ACL_REVISION, 00174 MUTANT_ALL_ACCESS, 00175 psidSystem); 00176 00177 /* failure */ 00178 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00179 00180 /* create the security descriptor */ 00181 nErrCode = RtlCreateSecurityDescriptor(&sdMutexSecurity, 00182 SECURITY_DESCRIPTOR_REVISION); 00183 00184 /* failure */ 00185 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00186 00187 /* set the descriptor's DACL to the ACL we created */ 00188 nErrCode = RtlSetDaclSecurityDescriptor(&sdMutexSecurity, 00189 TRUE, 00190 pDaclBuf, 00191 FALSE); 00192 00193 /* failure */ 00194 if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; 00195 00196 /* create the mutex */ 00197 hMutex = CreateMutexW(&saMutexAttribs, FALSE, L"DBWinMutex"); 00198 00199 l_Cleanup: 00200 /* free the buffers */ 00201 if(pDaclBuf) GlobalFree(pDaclBuf); 00202 if(psidEveryone) RtlFreeSid(psidEveryone); 00203 if(psidAdministrators) RtlFreeSid(psidAdministrators); 00204 if(psidSystem) RtlFreeSid(psidSystem); 00205 00206 return hMutex; 00207 } 00208 00209 VOID 00210 WINAPI 00211 SaveThreadHandle(IN DWORD dwProcessId, 00212 IN DWORD dwThreadId, 00213 IN HANDLE hThread) 00214 { 00215 PDBGSS_THREAD_DATA ThreadData; 00216 00217 /* Allocate a thread structure */ 00218 ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 00219 0, 00220 sizeof(DBGSS_THREAD_DATA)); 00221 if (!ThreadData) return; 00222 00223 /* Fill it out */ 00224 ThreadData->ThreadHandle = hThread; 00225 ThreadData->ProcessId = dwProcessId; 00226 ThreadData->ThreadId = dwThreadId; 00227 ThreadData->ProcessHandle = NULL; 00228 ThreadData->HandleMarked = FALSE; 00229 00230 /* Link it */ 00231 ThreadData->Next = DbgSsGetThreadData(); 00232 DbgSsSetThreadData(ThreadData); 00233 } 00234 00235 VOID 00236 WINAPI 00237 SaveProcessHandle(IN DWORD dwProcessId, 00238 IN HANDLE hProcess) 00239 { 00240 PDBGSS_THREAD_DATA ThreadData; 00241 00242 /* Allocate a thread structure */ 00243 ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 00244 0, 00245 sizeof(DBGSS_THREAD_DATA)); 00246 if (!ThreadData) return; 00247 00248 /* Fill it out */ 00249 ThreadData->ProcessHandle = hProcess; 00250 ThreadData->ProcessId = dwProcessId; 00251 ThreadData->ThreadId = 0; 00252 ThreadData->ThreadHandle = NULL; 00253 ThreadData->HandleMarked = FALSE; 00254 00255 /* Link it */ 00256 ThreadData->Next = DbgSsGetThreadData(); 00257 DbgSsSetThreadData(ThreadData); 00258 } 00259 00260 VOID 00261 WINAPI 00262 MarkThreadHandle(IN DWORD dwThreadId) 00263 { 00264 PDBGSS_THREAD_DATA ThreadData; 00265 00266 /* Loop all thread data events */ 00267 for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next) 00268 { 00269 /* Check if this one matches */ 00270 if (ThreadData->ThreadId == dwThreadId) 00271 { 00272 /* Mark the structure and break out */ 00273 ThreadData->HandleMarked = TRUE; 00274 break; 00275 } 00276 } 00277 } 00278 00279 VOID 00280 WINAPI 00281 MarkProcessHandle(IN DWORD dwProcessId) 00282 { 00283 PDBGSS_THREAD_DATA ThreadData; 00284 00285 /* Loop all thread data events */ 00286 for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next) 00287 { 00288 /* Check if this one matches */ 00289 if ((ThreadData->ProcessId == dwProcessId) && !(ThreadData->ThreadId)) 00290 { 00291 /* Mark the structure and break out */ 00292 ThreadData->HandleMarked = TRUE; 00293 break; 00294 } 00295 } 00296 } 00297 00298 VOID 00299 WINAPI 00300 RemoveHandles(IN DWORD dwProcessId, 00301 IN DWORD dwThreadId) 00302 { 00303 PDBGSS_THREAD_DATA *ThreadData; 00304 PDBGSS_THREAD_DATA ThisData; 00305 00306 /* Loop all thread data events */ 00307 ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved; 00308 ThisData = *ThreadData; 00309 while(ThisData) 00310 { 00311 /* Check if this one matches */ 00312 if ((ThisData->HandleMarked) && 00313 ((ThisData->ProcessId == dwProcessId) || (ThisData->ThreadId == dwThreadId))) 00314 { 00315 /* Close open handles */ 00316 if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle); 00317 if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle); 00318 00319 /* Unlink the thread data */ 00320 *ThreadData = ThisData->Next; 00321 00322 /* Free it*/ 00323 RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData); 00324 } 00325 else 00326 { 00327 /* Move to the next one */ 00328 ThreadData = &ThisData->Next; 00329 } 00330 ThisData = *ThreadData; 00331 } 00332 } 00333 00334 VOID 00335 WINAPI 00336 CloseAllProcessHandles(IN DWORD dwProcessId) 00337 { 00338 PDBGSS_THREAD_DATA *ThreadData; 00339 PDBGSS_THREAD_DATA ThisData; 00340 00341 /* Loop all thread data events */ 00342 ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved; 00343 ThisData = *ThreadData; 00344 while(ThisData) 00345 { 00346 /* Check if this one matches */ 00347 if (ThisData->ProcessId == dwProcessId) 00348 { 00349 /* Close open handles */ 00350 if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle); 00351 if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle); 00352 00353 /* Unlink the thread data */ 00354 *ThreadData = ThisData->Next; 00355 00356 /* Free it*/ 00357 RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData); 00358 } 00359 else 00360 { 00361 /* Move to the next one */ 00362 ThreadData = &ThisData->Next; 00363 } 00364 ThisData = *ThreadData; 00365 } 00366 } 00367 00368 HANDLE 00369 WINAPI 00370 ProcessIdToHandle(IN DWORD dwProcessId) 00371 { 00372 NTSTATUS Status; 00373 OBJECT_ATTRIBUTES ObjectAttributes; 00374 HANDLE Handle; 00375 CLIENT_ID ClientId; 00376 00377 /* If we don't have a PID, look it up */ 00378 if (dwProcessId == MAXDWORD) dwProcessId = (DWORD_PTR)CsrGetProcessId(); 00379 00380 /* Open a handle to the process */ 00381 ClientId.UniqueThread = NULL; 00382 ClientId.UniqueProcess = UlongToHandle(dwProcessId); 00383 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 00384 Status = NtOpenProcess(&Handle, 00385 PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | 00386 PROCESS_VM_WRITE | PROCESS_VM_READ | 00387 PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION, 00388 &ObjectAttributes, 00389 &ClientId); 00390 if (!NT_SUCCESS(Status)) 00391 { 00392 /* Fail */ 00393 BaseSetLastNTError(Status); 00394 return 0; 00395 } 00396 00397 /* Return the handle */ 00398 return Handle; 00399 } 00400 00401 /* PUBLIC FUNCTIONS **********************************************************/ 00402 00403 /* 00404 * @implemented 00405 */ 00406 BOOL 00407 WINAPI 00408 CheckRemoteDebuggerPresent(IN HANDLE hProcess, 00409 OUT PBOOL pbDebuggerPresent) 00410 { 00411 HANDLE DebugPort; 00412 NTSTATUS Status; 00413 00414 /* Make sure we have an output and process*/ 00415 if (!(pbDebuggerPresent) || !(hProcess)) 00416 { 00417 /* Fail */ 00418 SetLastError(ERROR_INVALID_PARAMETER); 00419 return FALSE; 00420 } 00421 00422 /* Check if the process has a debug object/port */ 00423 Status = NtQueryInformationProcess(hProcess, 00424 ProcessDebugPort, 00425 (PVOID)&DebugPort, 00426 sizeof(HANDLE), 00427 NULL); 00428 if (NT_SUCCESS(Status)) 00429 { 00430 /* Return the current state */ 00431 *pbDebuggerPresent = DebugPort != NULL; 00432 return TRUE; 00433 } 00434 00435 /* Otherwise, fail */ 00436 BaseSetLastNTError(Status); 00437 return FALSE; 00438 } 00439 00440 /* 00441 * @implemented 00442 */ 00443 BOOL 00444 WINAPI 00445 ContinueDebugEvent(IN DWORD dwProcessId, 00446 IN DWORD dwThreadId, 00447 IN DWORD dwContinueStatus) 00448 { 00449 CLIENT_ID ClientId; 00450 NTSTATUS Status; 00451 00452 /* Set the Client ID */ 00453 ClientId.UniqueProcess = (HANDLE)dwProcessId; 00454 ClientId.UniqueThread = (HANDLE)dwThreadId; 00455 00456 /* Continue debugging */ 00457 Status = DbgUiContinue(&ClientId, dwContinueStatus); 00458 if (!NT_SUCCESS(Status)) 00459 { 00460 /* Fail */ 00461 BaseSetLastNTError(Status); 00462 return FALSE; 00463 } 00464 00465 /* Remove the process/thread handles */ 00466 RemoveHandles(dwProcessId, dwThreadId); 00467 00468 /* Success */ 00469 return TRUE; 00470 } 00471 00472 /* 00473 * @implemented 00474 */ 00475 BOOL 00476 WINAPI 00477 DebugActiveProcess(IN DWORD dwProcessId) 00478 { 00479 NTSTATUS Status, Status1; 00480 HANDLE Handle; 00481 00482 /* Connect to the debugger */ 00483 Status = DbgUiConnectToDbg(); 00484 if (!NT_SUCCESS(Status)) 00485 { 00486 BaseSetLastNTError(Status); 00487 return FALSE; 00488 } 00489 00490 /* Get the process handle */ 00491 Handle = ProcessIdToHandle(dwProcessId); 00492 if (!Handle) return FALSE; 00493 00494 /* Now debug the process */ 00495 Status = DbgUiDebugActiveProcess(Handle); 00496 00497 /* Close the handle since we're done */ 00498 Status1 = NtClose(Handle); 00499 ASSERT(NT_SUCCESS(Status1)); 00500 00501 /* Check if debugging worked */ 00502 if (!NT_SUCCESS(Status)) 00503 { 00504 /* Fail */ 00505 BaseSetLastNTError(Status); 00506 return FALSE; 00507 } 00508 00509 /* Success */ 00510 return TRUE; 00511 } 00512 00513 /* 00514 * @implemented 00515 */ 00516 BOOL 00517 WINAPI 00518 DebugActiveProcessStop(IN DWORD dwProcessId) 00519 { 00520 NTSTATUS Status, Status1; 00521 HANDLE Handle; 00522 00523 /* Get the process handle */ 00524 Handle = ProcessIdToHandle(dwProcessId); 00525 if (!Handle) return FALSE; 00526 00527 /* Close all the process handles */ 00528 CloseAllProcessHandles(dwProcessId); 00529 00530 /* Now stop debgging the process */ 00531 Status = DbgUiStopDebugging(Handle); 00532 Status1 = NtClose(Handle); 00533 ASSERT(NT_SUCCESS(Status1)); 00534 00535 /* Check for failure */ 00536 if (!NT_SUCCESS(Status)) 00537 { 00538 /* Fail */ 00539 SetLastError(ERROR_ACCESS_DENIED); 00540 return FALSE; 00541 } 00542 00543 /* Success */ 00544 return TRUE; 00545 } 00546 00547 /* 00548 * @implemented 00549 */ 00550 BOOL 00551 WINAPI 00552 DebugBreakProcess(IN HANDLE Process) 00553 { 00554 NTSTATUS Status; 00555 00556 /* Send the breakin request */ 00557 Status = DbgUiIssueRemoteBreakin(Process); 00558 if(!NT_SUCCESS(Status)) 00559 { 00560 /* Failure */ 00561 BaseSetLastNTError(Status); 00562 return FALSE; 00563 } 00564 00565 /* Success */ 00566 return TRUE; 00567 } 00568 00569 /* 00570 * @implemented 00571 */ 00572 BOOL 00573 WINAPI 00574 DebugSetProcessKillOnExit(IN BOOL KillOnExit) 00575 { 00576 HANDLE Handle; 00577 NTSTATUS Status; 00578 ULONG State; 00579 00580 /* Get the debug object */ 00581 Handle = DbgUiGetThreadDebugObject(); 00582 if (!Handle) 00583 { 00584 /* Fail */ 00585 BaseSetLastNTError(STATUS_INVALID_HANDLE); 00586 return FALSE; 00587 } 00588 00589 /* Now set the kill-on-exit state */ 00590 State = KillOnExit != 0; 00591 Status = NtSetInformationDebugObject(Handle, 00592 DebugObjectKillProcessOnExitInformation, 00593 &State, 00594 sizeof(State), 00595 NULL); 00596 if (!NT_SUCCESS(Status)) 00597 { 00598 /* Fail */ 00599 BaseSetLastNTError(Status); 00600 return FALSE; 00601 } 00602 00603 /* Success */ 00604 return TRUE; 00605 } 00606 00607 /* 00608 * @implemented 00609 */ 00610 BOOL 00611 WINAPI 00612 IsDebuggerPresent(VOID) 00613 { 00614 return (BOOL)NtCurrentPeb()->BeingDebugged; 00615 } 00616 00617 /* 00618 * @implemented 00619 */ 00620 BOOL 00621 WINAPI 00622 WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent, 00623 IN DWORD dwMilliseconds) 00624 { 00625 LARGE_INTEGER WaitTime; 00626 PLARGE_INTEGER Timeout; 00627 DBGUI_WAIT_STATE_CHANGE WaitStateChange; 00628 NTSTATUS Status; 00629 00630 /* Convert to NT Timeout */ 00631 Timeout = BaseFormatTimeOut(&WaitTime, dwMilliseconds); 00632 00633 /* Loop while we keep getting interrupted */ 00634 do 00635 { 00636 /* Call the native API */ 00637 Status = DbgUiWaitStateChange(&WaitStateChange, Timeout); 00638 } while ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC)); 00639 00640 /* Check if the wait failed */ 00641 if (!(NT_SUCCESS(Status)) || (Status == DBG_UNABLE_TO_PROVIDE_HANDLE)) 00642 { 00643 /* Set the error code and quit */ 00644 BaseSetLastNTError(Status); 00645 return FALSE; 00646 } 00647 00648 /* Check if we timed out */ 00649 if (Status == STATUS_TIMEOUT) 00650 { 00651 /* Fail with a timeout error */ 00652 SetLastError(ERROR_SEM_TIMEOUT); 00653 return FALSE; 00654 } 00655 00656 /* Convert the structure */ 00657 Status = DbgUiConvertStateChangeStructure(&WaitStateChange, lpDebugEvent); 00658 if (!NT_SUCCESS(Status)) 00659 { 00660 /* Set the error code and quit */ 00661 BaseSetLastNTError(Status); 00662 return FALSE; 00663 } 00664 00665 /* Check what kind of event this was */ 00666 switch (lpDebugEvent->dwDebugEventCode) 00667 { 00668 /* New thread was created */ 00669 case CREATE_THREAD_DEBUG_EVENT: 00670 00671 /* Setup the thread data */ 00672 SaveThreadHandle(lpDebugEvent->dwProcessId, 00673 lpDebugEvent->dwThreadId, 00674 lpDebugEvent->u.CreateThread.hThread); 00675 break; 00676 00677 /* New process was created */ 00678 case CREATE_PROCESS_DEBUG_EVENT: 00679 00680 /* Setup the process data */ 00681 SaveProcessHandle(lpDebugEvent->dwProcessId, 00682 lpDebugEvent->u.CreateProcessInfo.hProcess); 00683 00684 /* Setup the thread data */ 00685 SaveThreadHandle(lpDebugEvent->dwProcessId, 00686 lpDebugEvent->dwThreadId, 00687 lpDebugEvent->u.CreateProcessInfo.hThread); 00688 break; 00689 00690 /* Process was exited */ 00691 case EXIT_PROCESS_DEBUG_EVENT: 00692 00693 /* Mark the thread data as such and fall through */ 00694 MarkProcessHandle(lpDebugEvent->dwProcessId); 00695 00696 /* Thread was exited */ 00697 case EXIT_THREAD_DEBUG_EVENT: 00698 00699 /* Mark the thread data */ 00700 MarkThreadHandle(lpDebugEvent->dwThreadId); 00701 break; 00702 00703 /* Nothing to do */ 00704 case EXCEPTION_DEBUG_EVENT: 00705 case LOAD_DLL_DEBUG_EVENT: 00706 case UNLOAD_DLL_DEBUG_EVENT: 00707 case OUTPUT_DEBUG_STRING_EVENT: 00708 case RIP_EVENT: 00709 break; 00710 00711 /* Fail anything else */ 00712 default: 00713 return FALSE; 00714 } 00715 00716 /* Return success */ 00717 return TRUE; 00718 } 00719 00720 /* 00721 * @implemented 00722 */ 00723 VOID 00724 WINAPI 00725 OutputDebugStringA(IN LPCSTR _OutputString) 00726 { 00727 _SEH2_TRY 00728 { 00729 ULONG_PTR a_nArgs[2]; 00730 00731 a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1); 00732 a_nArgs[1] = (ULONG_PTR)_OutputString; 00733 00734 /* send the string to the user-mode debugger */ 00735 RaiseException(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs); 00736 } 00737 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00738 { 00739 /* no user-mode debugger: try the systemwide debug message monitor, or the 00740 kernel debugger as a last resort */ 00741 00742 /* mutex used to synchronize invocations of OutputDebugString */ 00743 static HANDLE s_hDBMonMutex = NULL; 00744 /* true if we already attempted to open/create the mutex */ 00745 static BOOL s_bDBMonMutexTriedOpen = FALSE; 00746 00747 /* local copy of the mutex handle */ 00748 volatile HANDLE hDBMonMutex = s_hDBMonMutex; 00749 /* handle to the Section of the shared buffer */ 00750 volatile HANDLE hDBMonBuffer = NULL; 00751 00752 /* pointer to the mapped view of the shared buffer. It consist of the current 00753 process id followed by the message string */ 00754 struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL; 00755 00756 /* event: signaled by the debug message monitor when OutputDebugString can write 00757 to the shared buffer */ 00758 volatile HANDLE hDBMonBufferReady = NULL; 00759 00760 /* event: to be signaled by OutputDebugString when it's done writing to the 00761 shared buffer */ 00762 volatile HANDLE hDBMonDataReady = NULL; 00763 00764 /* mutex not opened, and no previous attempts to open/create it */ 00765 if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen) 00766 { 00767 /* open/create the mutex */ 00768 hDBMonMutex = K32CreateDBMonMutex(); 00769 /* store the handle */ 00770 s_hDBMonMutex = hDBMonMutex; 00771 } 00772 00773 _SEH2_TRY 00774 { 00775 volatile PCHAR a_cBuffer = NULL; 00776 00777 /* opening the mutex failed */ 00778 if(hDBMonMutex == NULL) 00779 { 00780 /* remember next time */ 00781 s_bDBMonMutexTriedOpen = TRUE; 00782 } 00783 /* opening the mutex succeeded */ 00784 else 00785 { 00786 do 00787 { 00788 /* synchronize with other invocations of OutputDebugString */ 00789 WaitForSingleObject(hDBMonMutex, INFINITE); 00790 00791 /* buffer of the system-wide debug message monitor */ 00792 hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER"); 00793 00794 /* couldn't open the buffer: send the string to the kernel debugger */ 00795 if(hDBMonBuffer == NULL) break; 00796 00797 /* map the buffer */ 00798 pDBMonBuffer = MapViewOfFile(hDBMonBuffer, 00799 SECTION_MAP_READ | SECTION_MAP_WRITE, 00800 0, 00801 0, 00802 0); 00803 00804 /* couldn't map the buffer: send the string to the kernel debugger */ 00805 if(pDBMonBuffer == NULL) break; 00806 00807 /* open the event signaling that the buffer can be accessed */ 00808 hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY"); 00809 00810 /* couldn't open the event: send the string to the kernel debugger */ 00811 if(hDBMonBufferReady == NULL) break; 00812 00813 /* open the event to be signaled when the buffer has been filled */ 00814 hDBMonDataReady = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY"); 00815 } 00816 while(0); 00817 00818 /* we couldn't connect to the system-wide debug message monitor: send the 00819 string to the kernel debugger */ 00820 if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex); 00821 } 00822 00823 _SEH2_TRY 00824 { 00825 /* size of the current output block */ 00826 volatile SIZE_T nRoundLen; 00827 00828 /* size of the remainder of the string */ 00829 volatile SIZE_T nOutputStringLen; 00830 00831 /* output the whole string */ 00832 nOutputStringLen = strlen(_OutputString); 00833 00834 do 00835 { 00836 /* we're connected to the debug monitor: 00837 write the current block to the shared buffer */ 00838 if(hDBMonDataReady) 00839 { 00840 /* wait a maximum of 10 seconds for the debug monitor 00841 to finish processing the shared buffer */ 00842 if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0) 00843 { 00844 /* timeout or failure: give up */ 00845 break; 00846 } 00847 00848 /* write the process id into the buffer */ 00849 pDBMonBuffer->ProcessId = GetCurrentProcessId(); 00850 00851 /* write only as many bytes as they fit in the buffer */ 00852 if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1)) 00853 nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1; 00854 else 00855 nRoundLen = nOutputStringLen; 00856 00857 /* copy the current block into the buffer */ 00858 memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen); 00859 00860 /* null-terminate the current block */ 00861 pDBMonBuffer->Buffer[nRoundLen] = 0; 00862 00863 /* signal that the data contains meaningful data and can be read */ 00864 SetEvent(hDBMonDataReady); 00865 } 00866 /* else, send the current block to the kernel debugger */ 00867 else 00868 { 00869 /* output in blocks of 512 characters */ 00870 a_cBuffer = (CHAR*)HeapAlloc(GetProcessHeap(), 0, 512); 00871 00872 if (!a_cBuffer) 00873 { 00874 DbgPrint("OutputDebugStringA: Failed\n"); 00875 break; 00876 } 00877 00878 /* write a maximum of 511 bytes */ 00879 if(nOutputStringLen > 510) 00880 nRoundLen = 510; 00881 else 00882 nRoundLen = nOutputStringLen; 00883 00884 /* copy the current block */ 00885 memcpy(a_cBuffer, _OutputString, nRoundLen); 00886 00887 /* null-terminate the current block */ 00888 a_cBuffer[nRoundLen] = 0; 00889 00890 /* send the current block to the kernel debugger */ 00891 DbgPrint("%s", a_cBuffer); 00892 00893 if (a_cBuffer) 00894 { 00895 HeapFree(GetProcessHeap(), 0, a_cBuffer); 00896 a_cBuffer = NULL; 00897 } 00898 } 00899 00900 /* move to the next block */ 00901 _OutputString += nRoundLen; 00902 nOutputStringLen -= nRoundLen; 00903 } 00904 /* repeat until the string has been fully output */ 00905 while (nOutputStringLen > 0); 00906 } 00907 /* ignore access violations and let other exceptions fall through */ 00908 _SEH2_EXCEPT((_SEH2_GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 00909 { 00910 if (a_cBuffer) 00911 HeapFree(GetProcessHeap(), 0, a_cBuffer); 00912 00913 /* string copied verbatim from Microsoft's kernel32.dll */ 00914 DbgPrint("\nOutputDebugString faulted during output\n"); 00915 } 00916 _SEH2_END; 00917 } 00918 _SEH2_FINALLY 00919 { 00920 /* close all the still open resources */ 00921 if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady); 00922 if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer); 00923 if(hDBMonBuffer) CloseHandle(hDBMonBuffer); 00924 if(hDBMonDataReady) CloseHandle(hDBMonDataReady); 00925 00926 /* leave the critical section */ 00927 if(hDBMonDataReady != NULL) 00928 ReleaseMutex(hDBMonMutex); 00929 } 00930 _SEH2_END; 00931 } 00932 _SEH2_END; 00933 } 00934 00935 /* 00936 * @implemented 00937 */ 00938 VOID 00939 WINAPI 00940 OutputDebugStringW(IN LPCWSTR OutputString) 00941 { 00942 UNICODE_STRING UnicodeString; 00943 ANSI_STRING AnsiString; 00944 NTSTATUS Status; 00945 00946 /* convert the string in ANSI */ 00947 RtlInitUnicodeString(&UnicodeString, OutputString); 00948 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE); 00949 00950 /* OutputDebugStringW always prints something, even if conversion fails */ 00951 if (!NT_SUCCESS(Status)) AnsiString.Buffer = ""; 00952 00953 /* Output the converted string */ 00954 OutputDebugStringA(AnsiString.Buffer); 00955 00956 /* free the converted string */ 00957 if (NT_SUCCESS(Status)) RtlFreeAnsiString(&AnsiString); 00958 } 00959 00960 /* EOF */ Generated on Sat May 26 2012 04:22:56 for ReactOS by
1.7.6.1
|