Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendbgkobj.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/dbgk/dbgkobj.c 00005 * PURPOSE: User-Mode Debugging Support, Debug Object Management. 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 POBJECT_TYPE DbgkDebugObjectType; 00016 FAST_MUTEX DbgkpProcessDebugPortMutex; 00017 ULONG DbgkpTraceLevel = 0; 00018 00019 GENERIC_MAPPING DbgkDebugObjectMapping = 00020 { 00021 STANDARD_RIGHTS_READ | DEBUG_OBJECT_WAIT_STATE_CHANGE, 00022 STANDARD_RIGHTS_WRITE | DEBUG_OBJECT_ADD_REMOVE_PROCESS, 00023 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 00024 DEBUG_OBJECT_ALL_ACCESS 00025 }; 00026 00027 static const INFORMATION_CLASS_INFO DbgkpDebugObjectInfoClass[] = 00028 { 00029 /* DebugObjectUnusedInformation */ 00030 ICI_SQ_SAME(sizeof(ULONG), sizeof(ULONG), 0), 00031 /* DebugObjectKillProcessOnExitInformation */ 00032 ICI_SQ_SAME(sizeof(DEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION), sizeof(ULONG), ICIF_SET), 00033 }; 00034 00035 /* PRIVATE FUNCTIONS *********************************************************/ 00036 00037 NTSTATUS 00038 NTAPI 00039 DbgkpQueueMessage(IN PEPROCESS Process, 00040 IN PETHREAD Thread, 00041 IN PDBGKM_MSG Message, 00042 IN ULONG Flags, 00043 IN PDEBUG_OBJECT TargetObject OPTIONAL) 00044 { 00045 PDEBUG_EVENT DebugEvent; 00046 DEBUG_EVENT LocalDebugEvent; 00047 PDEBUG_OBJECT DebugObject; 00048 NTSTATUS Status; 00049 BOOLEAN NewEvent; 00050 PAGED_CODE(); 00051 DBGKTRACE(DBGK_MESSAGE_DEBUG, 00052 "Process: %p Thread: %p Message: %p Flags: %lx\n", 00053 Process, Thread, Message, Flags); 00054 00055 /* Check if we have to allocate a debug event */ 00056 NewEvent = (Flags & DEBUG_EVENT_NOWAIT) ? TRUE : FALSE; 00057 if (NewEvent) 00058 { 00059 /* Allocate it */ 00060 DebugEvent = ExAllocatePoolWithTag(NonPagedPool, 00061 sizeof(DEBUG_EVENT), 00062 'EgbD'); 00063 if (!DebugEvent) return STATUS_INSUFFICIENT_RESOURCES; 00064 00065 /* Set flags */ 00066 DebugEvent->Flags = Flags | DEBUG_EVENT_INACTIVE; 00067 00068 /* Reference the thread and process */ 00069 ObReferenceObject(Thread); 00070 ObReferenceObject(Process); 00071 00072 /* Set the current thread */ 00073 DebugEvent->BackoutThread = PsGetCurrentThread(); 00074 00075 /* Set the debug object */ 00076 DebugObject = TargetObject; 00077 } 00078 else 00079 { 00080 /* Use the debug event on the stack */ 00081 DebugEvent = &LocalDebugEvent; 00082 DebugEvent->Flags = Flags; 00083 00084 /* Acquire the port lock */ 00085 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 00086 00087 /* Get the debug object */ 00088 DebugObject = Process->DebugPort; 00089 00090 /* Check what kind of API message this is */ 00091 switch (Message->ApiNumber) 00092 { 00093 /* Process or thread creation */ 00094 case DbgKmCreateThreadApi: 00095 case DbgKmCreateProcessApi: 00096 00097 /* Make sure we're not skipping creation messages */ 00098 if (Thread->SkipCreationMsg) DebugObject = NULL; 00099 break; 00100 00101 /* Process or thread exit */ 00102 case DbgKmExitThreadApi: 00103 case DbgKmExitProcessApi: 00104 00105 /* Make sure we're not skipping exit messages */ 00106 if (Thread->SkipTerminationMsg) DebugObject = NULL; 00107 00108 /* No special handling for other messages */ 00109 default: 00110 break; 00111 } 00112 } 00113 00114 /* Setup the Debug Event */ 00115 KeInitializeEvent(&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE); 00116 DebugEvent->Process = Process; 00117 DebugEvent->Thread = Thread; 00118 DebugEvent->ApiMsg = *Message; 00119 DebugEvent->ClientId = Thread->Cid; 00120 00121 /* Check if we have a port object */ 00122 if (!DebugObject) 00123 { 00124 /* Fail */ 00125 Status = STATUS_PORT_NOT_SET; 00126 } 00127 else 00128 { 00129 /* Acquire the debug object mutex */ 00130 ExAcquireFastMutex(&DebugObject->Mutex); 00131 00132 /* Check if a debugger is active */ 00133 if (!DebugObject->DebuggerInactive) 00134 { 00135 /* Add the event into the object's list */ 00136 DBGKTRACE(DBGK_MESSAGE_DEBUG, "Inserting: %lx %p\n", 00137 DebugEvent, Message->ApiNumber); 00138 InsertTailList(&DebugObject->EventList, &DebugEvent->EventList); 00139 00140 /* Check if we have to signal it */ 00141 if (!NewEvent) 00142 { 00143 /* Signal it */ 00144 KeSetEvent(&DebugObject->EventsPresent, 00145 IO_NO_INCREMENT, 00146 FALSE); 00147 } 00148 00149 /* Set success */ 00150 Status = STATUS_SUCCESS; 00151 } 00152 else 00153 { 00154 /* No debugger */ 00155 Status = STATUS_DEBUGGER_INACTIVE; 00156 } 00157 00158 /* Release the object lock */ 00159 ExReleaseFastMutex(&DebugObject->Mutex); 00160 } 00161 00162 /* Check if we had acquired the port lock */ 00163 if (!NewEvent) 00164 { 00165 /* Release it */ 00166 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 00167 00168 /* Check if we got here through success */ 00169 if (NT_SUCCESS(Status)) 00170 { 00171 /* Wait on the continue event */ 00172 KeWaitForSingleObject(&DebugEvent->ContinueEvent, 00173 Executive, 00174 KernelMode, 00175 FALSE, 00176 NULL); 00177 00178 /* Copy API Message back */ 00179 *Message = DebugEvent->ApiMsg; 00180 00181 /* Set return status */ 00182 Status = DebugEvent->Status; 00183 } 00184 } 00185 else 00186 { 00187 /* Check if we failed */ 00188 if (!NT_SUCCESS(Status)) 00189 { 00190 /* Dereference the process and thread */ 00191 ObDereferenceObject(Thread); 00192 ObDereferenceObject(Process); 00193 00194 /* Free the debug event */ 00195 ExFreePool(DebugEvent); 00196 } 00197 } 00198 00199 /* Return status */ 00200 DBGKTRACE(DBGK_MESSAGE_DEBUG, "Status: %lx\n", Status); 00201 return Status; 00202 } 00203 00204 NTSTATUS 00205 NTAPI 00206 DbgkpSendApiMessageLpc(IN OUT PDBGKM_MSG Message, 00207 IN PVOID Port, 00208 IN BOOLEAN SuspendProcess) 00209 { 00210 NTSTATUS Status; 00211 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; 00212 BOOLEAN Suspended = FALSE; 00213 PAGED_CODE(); 00214 00215 /* Suspend process if required */ 00216 if (SuspendProcess) Suspended = DbgkpSuspendProcess(); 00217 00218 /* Set return status */ 00219 Message->ReturnedStatus = STATUS_PENDING; 00220 00221 /* Set create process reported state */ 00222 PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT); 00223 00224 /* Send the LPC command */ 00225 Status = LpcRequestWaitReplyPort(Port, 00226 (PPORT_MESSAGE)Message, 00227 (PPORT_MESSAGE)&Buffer[0]); 00228 00229 /* Flush the instruction cache */ 00230 ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); 00231 00232 /* Copy the buffer back */ 00233 if (NT_SUCCESS(Status)) RtlCopyMemory(Message, Buffer, sizeof(DBGKM_MSG)); 00234 00235 /* Resume the process if it was suspended */ 00236 if (Suspended) DbgkpResumeProcess(); 00237 return Status; 00238 } 00239 00240 NTSTATUS 00241 NTAPI 00242 DbgkpSendApiMessage(IN OUT PDBGKM_MSG ApiMsg, 00243 IN BOOLEAN SuspendProcess) 00244 { 00245 NTSTATUS Status; 00246 BOOLEAN Suspended = FALSE; 00247 PAGED_CODE(); 00248 DBGKTRACE(DBGK_MESSAGE_DEBUG, "ApiMsg: %p SuspendProcess: %lx\n", ApiMsg, SuspendProcess); 00249 00250 /* Suspend process if required */ 00251 if (SuspendProcess) Suspended = DbgkpSuspendProcess(); 00252 00253 /* Set return status */ 00254 ApiMsg->ReturnedStatus = STATUS_PENDING; 00255 00256 /* Set create process reported state */ 00257 PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT); 00258 00259 /* Send the LPC command */ 00260 Status = DbgkpQueueMessage(PsGetCurrentProcess(), 00261 PsGetCurrentThread(), 00262 ApiMsg, 00263 0, 00264 NULL); 00265 00266 /* Flush the instruction cache */ 00267 ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); 00268 00269 /* Resume the process if it was suspended */ 00270 if (Suspended) DbgkpResumeProcess(); 00271 return Status; 00272 } 00273 00274 VOID 00275 NTAPI 00276 DbgkCopyProcessDebugPort(IN PEPROCESS Process, 00277 IN PEPROCESS Parent) 00278 { 00279 PDEBUG_OBJECT DebugObject; 00280 PAGED_CODE(); 00281 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Parent: %p\n", Process, Parent); 00282 00283 /* Clear this process's port */ 00284 Process->DebugPort = NULL; 00285 00286 /* Check if the parent has one */ 00287 if (!Parent->DebugPort) return; 00288 00289 /* It does, acquire the mutex */ 00290 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 00291 00292 /* Make sure it still has one, and that we should inherit */ 00293 DebugObject = Parent->DebugPort; 00294 if ((DebugObject) && !(Process->NoDebugInherit)) 00295 { 00296 /* Acquire the debug object's lock */ 00297 ExAcquireFastMutex(&DebugObject->Mutex); 00298 00299 /* Make sure the debugger is active */ 00300 if (!DebugObject->DebuggerInactive) 00301 { 00302 /* Reference the object and set it */ 00303 ObReferenceObject(DebugObject); 00304 Process->DebugPort = DebugObject; 00305 } 00306 00307 /* Release the debug object */ 00308 ExReleaseFastMutex(&DebugObject->Mutex); 00309 } 00310 00311 /* Release the port mutex */ 00312 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 00313 } 00314 00315 BOOLEAN 00316 NTAPI 00317 DbgkForwardException(IN PEXCEPTION_RECORD ExceptionRecord, 00318 IN BOOLEAN DebugPort, 00319 IN BOOLEAN SecondChance) 00320 { 00321 DBGKM_MSG ApiMessage; 00322 PDBGKM_EXCEPTION DbgKmException = &ApiMessage.Exception; 00323 NTSTATUS Status; 00324 PEPROCESS Process = PsGetCurrentProcess(); 00325 PVOID Port; 00326 BOOLEAN UseLpc = FALSE; 00327 PAGED_CODE(); 00328 DBGKTRACE(DBGK_EXCEPTION_DEBUG, 00329 "ExceptionRecord: %p Port: %p\n", ExceptionRecord, DebugPort); 00330 00331 /* Setup the API Message */ 00332 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | 00333 (8 + sizeof(DBGKM_EXCEPTION)); 00334 ApiMessage.h.u2.ZeroInit = 0; 00335 ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; 00336 ApiMessage.ApiNumber = DbgKmExceptionApi; 00337 00338 /* Check if this is to be sent on the debug port */ 00339 if (DebugPort) 00340 { 00341 /* Use the debug port, unless the thread is being hidden */ 00342 Port = PsGetCurrentThread()->HideFromDebugger ? 00343 NULL : Process->DebugPort; 00344 } 00345 else 00346 { 00347 /* Otherwise, use the exception port */ 00348 Port = Process->ExceptionPort; 00349 ApiMessage.h.u2.ZeroInit = 0; 00350 ApiMessage.h.u2.s2.Type = LPC_EXCEPTION; 00351 UseLpc = TRUE; 00352 } 00353 00354 /* Break out if there's no port */ 00355 if (!Port) return FALSE; 00356 00357 /* Fill out the exception information */ 00358 DbgKmException->ExceptionRecord = *ExceptionRecord; 00359 DbgKmException->FirstChance = !SecondChance; 00360 00361 /* Check if we should use LPC */ 00362 if (UseLpc) 00363 { 00364 /* Send the message on the LPC Port */ 00365 Status = DbgkpSendApiMessageLpc(&ApiMessage, Port, DebugPort); 00366 } 00367 else 00368 { 00369 /* Use native debug object */ 00370 Status = DbgkpSendApiMessage(&ApiMessage, DebugPort); 00371 } 00372 00373 /* Check if we failed, and for a debug port, also check the return status */ 00374 if (!(NT_SUCCESS(Status)) || 00375 ((DebugPort) && 00376 (!(NT_SUCCESS(ApiMessage.ReturnedStatus)) || 00377 (ApiMessage.ReturnedStatus == DBG_EXCEPTION_NOT_HANDLED)))) 00378 { 00379 /* Fail */ 00380 return FALSE; 00381 } 00382 00383 /* Otherwise, we're ok */ 00384 return TRUE; 00385 } 00386 00387 VOID 00388 NTAPI 00389 DbgkpFreeDebugEvent(IN PDEBUG_EVENT DebugEvent) 00390 { 00391 PHANDLE Handle = NULL; 00392 PAGED_CODE(); 00393 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 00394 00395 /* Check if this event had a file handle */ 00396 switch (DebugEvent->ApiMsg.ApiNumber) 00397 { 00398 /* Create process has a handle */ 00399 case DbgKmCreateProcessApi: 00400 00401 /* Get the pointer */ 00402 Handle = &DebugEvent->ApiMsg.CreateProcess.FileHandle; 00403 break; 00404 00405 /* As does DLL load */ 00406 case DbgKmLoadDllApi: 00407 00408 /* Get the pointer */ 00409 Handle = &DebugEvent->ApiMsg.LoadDll.FileHandle; 00410 00411 default: 00412 break; 00413 } 00414 00415 /* Close the handle if it exsts */ 00416 if ((Handle) && (*Handle)) ObCloseHandle(*Handle, KernelMode); 00417 00418 /* Dereference process and thread and free the event */ 00419 ObDereferenceObject(DebugEvent->Process); 00420 ObDereferenceObject(DebugEvent->Thread); 00421 ExFreePool(DebugEvent); 00422 } 00423 00424 VOID 00425 NTAPI 00426 DbgkpWakeTarget(IN PDEBUG_EVENT DebugEvent) 00427 { 00428 PETHREAD Thread = DebugEvent->Thread; 00429 PAGED_CODE(); 00430 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 00431 00432 /* Check if we have to wake the thread */ 00433 if (DebugEvent->Flags & DEBUG_EVENT_SUSPEND) PsResumeThread(Thread, NULL); 00434 00435 /* Check if we had locked the thread */ 00436 if (DebugEvent->Flags & DEBUG_EVENT_RELEASE) 00437 { 00438 /* Unlock it */ 00439 ExReleaseRundownProtection(&Thread->RundownProtect); 00440 } 00441 00442 /* Check if we have to wake up the event */ 00443 if (DebugEvent->Flags & DEBUG_EVENT_NOWAIT) 00444 { 00445 /* Otherwise, free the debug event */ 00446 DbgkpFreeDebugEvent(DebugEvent); 00447 } 00448 else 00449 { 00450 /* Signal the continue event */ 00451 KeSetEvent(&DebugEvent->ContinueEvent, IO_NO_INCREMENT, FALSE); 00452 } 00453 } 00454 00455 NTSTATUS 00456 NTAPI 00457 DbgkpPostFakeModuleMessages(IN PEPROCESS Process, 00458 IN PETHREAD Thread, 00459 IN PDEBUG_OBJECT DebugObject) 00460 { 00461 PPEB Peb = Process->Peb; 00462 PPEB_LDR_DATA LdrData; 00463 PLDR_DATA_TABLE_ENTRY LdrEntry; 00464 PLIST_ENTRY ListHead, NextEntry; 00465 DBGKM_MSG ApiMessage; 00466 PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll; 00467 ULONG i; 00468 PIMAGE_NT_HEADERS NtHeader; 00469 UNICODE_STRING ModuleName; 00470 OBJECT_ATTRIBUTES ObjectAttributes; 00471 IO_STATUS_BLOCK IoStatusBlock; 00472 NTSTATUS Status; 00473 PAGED_CODE(); 00474 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Thread: %p DebugObject: %p\n", 00475 Process, Thread, DebugObject); 00476 00477 /* Quit if there's no PEB */ 00478 if (!Peb) return STATUS_SUCCESS; 00479 00480 /* Get the Loader Data List */ 00481 LdrData = Peb->Ldr; 00482 ListHead = &LdrData->InLoadOrderModuleList; 00483 NextEntry = ListHead->Flink; 00484 00485 /* Loop the modules */ 00486 i = 0; 00487 while ((NextEntry != ListHead) && (i < 500)) 00488 { 00489 /* Skip the first entry */ 00490 if (!i) 00491 { 00492 /* Go to the next module */ 00493 NextEntry = NextEntry->Flink; 00494 i++; 00495 continue; 00496 } 00497 00498 /* Get the entry */ 00499 LdrEntry = CONTAINING_RECORD(NextEntry, 00500 LDR_DATA_TABLE_ENTRY, 00501 InLoadOrderLinks); 00502 00503 /* Setup the API Message */ 00504 RtlZeroMemory(&ApiMessage, sizeof(DBGKM_MSG)); 00505 ApiMessage.ApiNumber = DbgKmLoadDllApi; 00506 00507 /* Set base and clear the name */ 00508 LoadDll->BaseOfDll = LdrEntry->DllBase; 00509 LoadDll->NamePointer = NULL; 00510 00511 /* Get the NT Headers */ 00512 NtHeader = RtlImageNtHeader(LoadDll->BaseOfDll); 00513 if (NtHeader) 00514 { 00515 /* Save debug data */ 00516 LoadDll->DebugInfoFileOffset = NtHeader->FileHeader. 00517 PointerToSymbolTable; 00518 LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols; 00519 } 00520 00521 /* Trace */ 00522 DBGKTRACE(DBGK_PROCESS_DEBUG, "Name: %wZ. Base: %p\n", 00523 &LdrEntry->FullDllName, LdrEntry->DllBase); 00524 00525 /* Get the name of the DLL */ 00526 Status = MmGetFileNameForAddress(NtHeader, &ModuleName); 00527 if (NT_SUCCESS(Status)) 00528 { 00529 /* Setup the object attributes */ 00530 InitializeObjectAttributes(&ObjectAttributes, 00531 &ModuleName, 00532 OBJ_FORCE_ACCESS_CHECK | 00533 OBJ_KERNEL_HANDLE | 00534 OBJ_CASE_INSENSITIVE, 00535 NULL, 00536 NULL); 00537 00538 /* Open the file to get a handle to it */ 00539 Status = ZwOpenFile(&LoadDll->FileHandle, 00540 GENERIC_READ | SYNCHRONIZE, 00541 &ObjectAttributes, 00542 &IoStatusBlock, 00543 FILE_SHARE_READ | 00544 FILE_SHARE_WRITE | 00545 FILE_SHARE_DELETE, 00546 FILE_SYNCHRONOUS_IO_NONALERT); 00547 if (!NT_SUCCESS(Status)) LoadDll->FileHandle = NULL; 00548 00549 /* Free the name now */ 00550 ExFreePool(ModuleName.Buffer); 00551 } 00552 00553 /* Send the fake module load message */ 00554 Status = DbgkpQueueMessage(Process, 00555 Thread, 00556 &ApiMessage, 00557 DEBUG_EVENT_NOWAIT, 00558 DebugObject); 00559 if (!NT_SUCCESS(Status)) 00560 { 00561 /* Message send failed, close the file handle if we had one */ 00562 if (LoadDll->FileHandle) ObCloseHandle(LoadDll->FileHandle, 00563 KernelMode); 00564 } 00565 00566 /* Go to the next module */ 00567 NextEntry = NextEntry->Flink; 00568 i++; 00569 } 00570 00571 /* Return success */ 00572 return STATUS_SUCCESS; 00573 } 00574 00575 NTSTATUS 00576 NTAPI 00577 DbgkpPostFakeThreadMessages(IN PEPROCESS Process, 00578 IN PDEBUG_OBJECT DebugObject, 00579 IN PETHREAD StartThread, 00580 OUT PETHREAD *FirstThread, 00581 OUT PETHREAD *LastThread) 00582 { 00583 PETHREAD pFirstThread = NULL, ThisThread, OldThread = NULL, pLastThread; 00584 NTSTATUS Status = STATUS_UNSUCCESSFUL; 00585 BOOLEAN IsFirstThread; 00586 ULONG Flags; 00587 DBGKM_MSG ApiMessage; 00588 PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread; 00589 PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess; 00590 BOOLEAN First; 00591 PIMAGE_NT_HEADERS NtHeader; 00592 PAGED_CODE(); 00593 DBGKTRACE(DBGK_THREAD_DEBUG, "Process: %p StartThread: %p Object: %p\n", 00594 Process, StartThread, DebugObject); 00595 00596 /* Check if we have a start thread */ 00597 if (StartThread) 00598 { 00599 /* Then the one we'll find won't be the first one */ 00600 IsFirstThread = FALSE; 00601 pFirstThread = StartThread; 00602 ThisThread = StartThread; 00603 00604 /* Reference it */ 00605 ObReferenceObject(StartThread); 00606 } 00607 else 00608 { 00609 /* Get the first thread ourselves */ 00610 ThisThread = PsGetNextProcessThread(Process, NULL); 00611 IsFirstThread = TRUE; 00612 } 00613 00614 /* Start thread loop */ 00615 do 00616 { 00617 /* Dereference the previous thread if we had one */ 00618 if (OldThread) ObDereferenceObject(OldThread); 00619 00620 /* Set this as the last thread and lock it */ 00621 pLastThread = ThisThread; 00622 ObReferenceObject(ThisThread); 00623 if (ExAcquireRundownProtection(&ThisThread->RundownProtect)) 00624 { 00625 /* Acquire worked, set flags */ 00626 Flags = DEBUG_EVENT_RELEASE | DEBUG_EVENT_NOWAIT; 00627 00628 /* Check if this is a user thread */ 00629 if (!ThisThread->SystemThread) 00630 { 00631 /* Suspend it */ 00632 if (NT_SUCCESS(PsSuspendThread(ThisThread, NULL))) 00633 { 00634 /* Remember this */ 00635 Flags |= DEBUG_EVENT_SUSPEND; 00636 } 00637 } 00638 } 00639 else 00640 { 00641 /* Couldn't acquire rundown */ 00642 Flags = DEBUG_EVENT_PROTECT_FAILED | DEBUG_EVENT_NOWAIT; 00643 } 00644 00645 /* Clear the API Message */ 00646 RtlZeroMemory(&ApiMessage, sizeof(ApiMessage)); 00647 00648 /* Check if this is the first thread */ 00649 if ((IsFirstThread) && 00650 !(Flags & DEBUG_EVENT_PROTECT_FAILED) && 00651 !(ThisThread->SystemThread) && 00652 (ThisThread->GrantedAccess)) 00653 { 00654 /* It is, save the flag */ 00655 First = TRUE; 00656 } 00657 else 00658 { 00659 /* It isn't, save the flag */ 00660 First = FALSE; 00661 } 00662 00663 /* Check if this is the first */ 00664 if (First) 00665 { 00666 /* So we'll start with the create process message */ 00667 ApiMessage.ApiNumber = DbgKmCreateProcessApi; 00668 00669 /* Get the file handle */ 00670 if (Process->SectionObject) 00671 { 00672 /* Use the section object */ 00673 CreateProcess->FileHandle = 00674 DbgkpSectionToFileHandle(Process->SectionObject); 00675 } 00676 else 00677 { 00678 /* Don't return any handle */ 00679 CreateProcess->FileHandle = NULL; 00680 } 00681 00682 /* Set the base address */ 00683 CreateProcess->BaseOfImage = Process->SectionBaseAddress; 00684 00685 /* Get the NT Header */ 00686 NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); 00687 if (NtHeader) 00688 { 00689 /* Fill out data from the header */ 00690 CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader. 00691 PointerToSymbolTable; 00692 CreateProcess->DebugInfoSize = NtHeader->FileHeader. 00693 NumberOfSymbols; 00694 } 00695 } 00696 else 00697 { 00698 /* Otherwise it's a thread message */ 00699 ApiMessage.ApiNumber = DbgKmCreateThreadApi; 00700 CreateThread->StartAddress = ThisThread->StartAddress; 00701 } 00702 00703 /* Trace */ 00704 DBGKTRACE(DBGK_THREAD_DEBUG, "Thread: %p. First: %lx, OldThread: %p\n", 00705 ThisThread, First, OldThread); 00706 DBGKTRACE(DBGK_THREAD_DEBUG, "Start Address: %p\n", 00707 ThisThread->StartAddress); 00708 00709 /* Queue the message */ 00710 Status = DbgkpQueueMessage(Process, 00711 ThisThread, 00712 &ApiMessage, 00713 Flags, 00714 DebugObject); 00715 if (!NT_SUCCESS(Status)) 00716 { 00717 /* Resume the thread if it was suspended */ 00718 if (Flags & DEBUG_EVENT_SUSPEND) PsResumeThread(ThisThread, NULL); 00719 00720 /* Check if we acquired rundown */ 00721 if (Flags & DEBUG_EVENT_RELEASE) 00722 { 00723 /* Release it */ 00724 ExReleaseRundownProtection(&ThisThread->RundownProtect); 00725 } 00726 00727 /* If this was a process create, check if we got a handle */ 00728 if ((ApiMessage.ApiNumber == DbgKmCreateProcessApi) && 00729 (CreateProcess->FileHandle)) 00730 { 00731 /* Close it */ 00732 ObCloseHandle(CreateProcess->FileHandle, KernelMode); 00733 } 00734 00735 /* Release our reference and break out */ 00736 ObDereferenceObject(ThisThread); 00737 break; 00738 } 00739 00740 /* Check if this was the first message */ 00741 if (First) 00742 { 00743 /* It isn't the first thread anymore */ 00744 IsFirstThread = FALSE; 00745 00746 /* Reference this thread and set it as first */ 00747 ObReferenceObject(ThisThread); 00748 pFirstThread = ThisThread; 00749 } 00750 00751 /* Get the next thread */ 00752 ThisThread = PsGetNextProcessThread(Process, ThisThread); 00753 OldThread = pLastThread; 00754 } while (ThisThread); 00755 00756 /* Check the API status */ 00757 if (!NT_SUCCESS(Status)) 00758 { 00759 /* Dereference and fail */ 00760 if (pFirstThread) ObDereferenceObject(pFirstThread); 00761 if (pLastThread) ObDereferenceObject(pLastThread); 00762 return Status; 00763 } 00764 00765 /* Make sure we have a first thread */ 00766 if (!pFirstThread) return STATUS_UNSUCCESSFUL; 00767 00768 /* Return thread pointers */ 00769 *FirstThread = pFirstThread; 00770 *LastThread = pLastThread; 00771 return Status; 00772 } 00773 00774 NTSTATUS 00775 NTAPI 00776 DbgkpPostFakeProcessCreateMessages(IN PEPROCESS Process, 00777 IN PDEBUG_OBJECT DebugObject, 00778 OUT PETHREAD *LastThread) 00779 { 00780 KAPC_STATE ApcState; 00781 PETHREAD FirstThread, FinalThread; 00782 PETHREAD ReturnThread = NULL; 00783 NTSTATUS Status; 00784 PAGED_CODE(); 00785 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p DebugObject: %p\n", 00786 Process, DebugObject); 00787 00788 /* Attach to the process */ 00789 KeStackAttachProcess(&Process->Pcb, &ApcState); 00790 00791 /* Post the fake thread messages */ 00792 Status = DbgkpPostFakeThreadMessages(Process, 00793 DebugObject, 00794 NULL, 00795 &FirstThread, 00796 &FinalThread); 00797 if (NT_SUCCESS(Status)) 00798 { 00799 /* Send the fake module messages too */ 00800 Status = DbgkpPostFakeModuleMessages(Process, 00801 FirstThread, 00802 DebugObject); 00803 if (!NT_SUCCESS(Status)) 00804 { 00805 /* We failed, dereference the final thread */ 00806 ObDereferenceObject(FinalThread); 00807 } 00808 else 00809 { 00810 /* Set the final thread */ 00811 ReturnThread = FinalThread; 00812 } 00813 00814 /* Dereference the first thread */ 00815 ObDereferenceObject(FirstThread); 00816 } 00817 00818 /* Detach from the process */ 00819 KeUnstackDetachProcess(&ApcState); 00820 00821 /* Return the last thread */ 00822 *LastThread = ReturnThread; 00823 return Status; 00824 } 00825 00826 VOID 00827 NTAPI 00828 DbgkpConvertKernelToUserStateChange(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 00829 IN PDEBUG_EVENT DebugEvent) 00830 { 00831 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 00832 00833 /* Start by copying the client ID */ 00834 WaitStateChange->AppClientId = DebugEvent->ClientId; 00835 00836 /* Now check which kind of event this was */ 00837 switch (DebugEvent->ApiMsg.ApiNumber) 00838 { 00839 /* New process */ 00840 case DbgKmCreateProcessApi: 00841 00842 /* Set the right native code */ 00843 WaitStateChange->NewState = DbgCreateProcessStateChange; 00844 00845 /* Copy the information */ 00846 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess = 00847 DebugEvent->ApiMsg.CreateProcess; 00848 00849 /* Clear the file handle for us */ 00850 DebugEvent->ApiMsg.CreateProcess.FileHandle = NULL; 00851 break; 00852 00853 /* New thread */ 00854 case DbgKmCreateThreadApi: 00855 00856 /* Set the right native code */ 00857 WaitStateChange->NewState = DbgCreateThreadStateChange; 00858 00859 /* Copy information */ 00860 WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress = 00861 DebugEvent->ApiMsg.CreateThread.StartAddress; 00862 WaitStateChange->StateInfo.CreateThread.NewThread.SubSystemKey = 00863 DebugEvent->ApiMsg.CreateThread.SubSystemKey; 00864 break; 00865 00866 /* Exception (or breakpoint/step) */ 00867 case DbgKmExceptionApi: 00868 00869 /* Look at the exception code */ 00870 if ((NTSTATUS)DebugEvent->ApiMsg.Exception.ExceptionRecord.ExceptionCode == 00871 STATUS_BREAKPOINT) 00872 { 00873 /* Update this as a breakpoint exception */ 00874 WaitStateChange->NewState = DbgBreakpointStateChange; 00875 } 00876 else if ((NTSTATUS)DebugEvent->ApiMsg.Exception.ExceptionRecord.ExceptionCode == 00877 STATUS_SINGLE_STEP) 00878 { 00879 /* Update this as a single step exception */ 00880 WaitStateChange->NewState = DbgSingleStepStateChange; 00881 } 00882 else 00883 { 00884 /* Otherwise, set default exception */ 00885 WaitStateChange->NewState = DbgExceptionStateChange; 00886 } 00887 00888 /* Copy the exception record */ 00889 WaitStateChange->StateInfo.Exception.ExceptionRecord = 00890 DebugEvent->ApiMsg.Exception.ExceptionRecord; 00891 /* Copy FirstChance flag */ 00892 WaitStateChange->StateInfo.Exception.FirstChance = 00893 DebugEvent->ApiMsg.Exception.FirstChance; 00894 break; 00895 00896 /* Process exited */ 00897 case DbgKmExitProcessApi: 00898 00899 /* Set the right native code and copy the exit code */ 00900 WaitStateChange->NewState = DbgExitProcessStateChange; 00901 WaitStateChange->StateInfo.ExitProcess.ExitStatus = 00902 DebugEvent->ApiMsg.ExitProcess.ExitStatus; 00903 break; 00904 00905 /* Thread exited */ 00906 case DbgKmExitThreadApi: 00907 00908 /* Set the right native code */ 00909 WaitStateChange->NewState = DbgExitThreadStateChange; 00910 WaitStateChange->StateInfo.ExitThread.ExitStatus = 00911 DebugEvent->ApiMsg.ExitThread.ExitStatus; 00912 break; 00913 00914 /* DLL Load */ 00915 case DbgKmLoadDllApi: 00916 00917 /* Set the native code */ 00918 WaitStateChange->NewState = DbgLoadDllStateChange; 00919 00920 /* Copy the data */ 00921 WaitStateChange->StateInfo.LoadDll = DebugEvent->ApiMsg.LoadDll; 00922 00923 /* Clear the file handle for us */ 00924 DebugEvent->ApiMsg.LoadDll.FileHandle = NULL; 00925 break; 00926 00927 /* DLL Unload */ 00928 case DbgKmUnloadDllApi: 00929 00930 /* Set the native code and copy the address */ 00931 WaitStateChange->NewState = DbgUnloadDllStateChange; 00932 WaitStateChange->StateInfo.UnloadDll.BaseAddress = 00933 DebugEvent->ApiMsg.UnloadDll.BaseAddress; 00934 break; 00935 00936 default: 00937 00938 /* Shouldn't happen */ 00939 ASSERT(FALSE); 00940 } 00941 } 00942 00943 VOID 00944 NTAPI 00945 DbgkpMarkProcessPeb(IN PEPROCESS Process) 00946 { 00947 KAPC_STATE ApcState; 00948 PAGED_CODE(); 00949 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p\n", Process); 00950 00951 /* Acquire process rundown */ 00952 if (!ExAcquireRundownProtection(&Process->RundownProtect)) return; 00953 00954 /* Make sure we have a PEB */ 00955 if (Process->Peb) 00956 { 00957 /* Attach to the process */ 00958 KeStackAttachProcess(&Process->Pcb, &ApcState); 00959 00960 /* Acquire the debug port mutex */ 00961 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 00962 00963 /* Set the IsBeingDebugged member of the PEB */ 00964 Process->Peb->BeingDebugged = (Process->DebugPort) ? TRUE: FALSE; 00965 00966 /* Release lock */ 00967 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 00968 00969 /* Detach from the process */ 00970 KeUnstackDetachProcess(&ApcState); 00971 } 00972 00973 /* Release rundown protection */ 00974 ExReleaseRundownProtection(&Process->RundownProtect); 00975 } 00976 00977 VOID 00978 NTAPI 00979 DbgkpOpenHandles(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 00980 IN PEPROCESS Process, 00981 IN PETHREAD Thread) 00982 { 00983 NTSTATUS Status; 00984 HANDLE Handle; 00985 PHANDLE DupHandle; 00986 PAGED_CODE(); 00987 DBGKTRACE(DBGK_OBJECT_DEBUG, "Process: %p Thread: %p State: %lx\n", 00988 Process, Thread, WaitStateChange->NewState); 00989 00990 /* Check which state this is */ 00991 switch (WaitStateChange->NewState) 00992 { 00993 /* New thread */ 00994 case DbgCreateThreadStateChange: 00995 00996 /* Get handle to thread */ 00997 Status = ObOpenObjectByPointer(Thread, 00998 0, 00999 NULL, 01000 THREAD_ALL_ACCESS, 01001 PsThreadType, 01002 KernelMode, 01003 &Handle); 01004 if (NT_SUCCESS(Status)) 01005 { 01006 /* Save the thread handle */ 01007 WaitStateChange-> 01008 StateInfo.CreateThread.HandleToThread = Handle; 01009 } 01010 return; 01011 01012 /* New process */ 01013 case DbgCreateProcessStateChange: 01014 01015 /* Get handle to thread */ 01016 Status = ObOpenObjectByPointer(Thread, 01017 0, 01018 NULL, 01019 THREAD_ALL_ACCESS, 01020 PsThreadType, 01021 KernelMode, 01022 &Handle); 01023 if (NT_SUCCESS(Status)) 01024 { 01025 /* Save the thread handle */ 01026 WaitStateChange-> 01027 StateInfo.CreateProcessInfo.HandleToThread = Handle; 01028 } 01029 01030 /* Get handle to process */ 01031 Status = ObOpenObjectByPointer(Process, 01032 0, 01033 NULL, 01034 PROCESS_ALL_ACCESS, 01035 PsProcessType, 01036 KernelMode, 01037 &Handle); 01038 if (NT_SUCCESS(Status)) 01039 { 01040 /* Save the process handle */ 01041 WaitStateChange-> 01042 StateInfo.CreateProcessInfo.HandleToProcess = Handle; 01043 } 01044 01045 /* Fall through to duplicate file handle */ 01046 DupHandle = &WaitStateChange-> 01047 StateInfo.CreateProcessInfo.NewProcess.FileHandle; 01048 break; 01049 01050 /* DLL Load */ 01051 case DbgLoadDllStateChange: 01052 01053 /* Fall through to duplicate file handle */ 01054 DupHandle = &WaitStateChange->StateInfo.LoadDll.FileHandle; 01055 break; 01056 01057 /* Anything else has no handles */ 01058 default: 01059 return; 01060 } 01061 01062 /* If we got here, then we have to duplicate a handle, possibly */ 01063 Handle = *DupHandle; 01064 if (Handle) 01065 { 01066 /* Duplicate it */ 01067 Status = ObDuplicateObject(PsGetCurrentProcess(), 01068 Handle, 01069 PsGetCurrentProcess(), 01070 DupHandle, 01071 0, 01072 0, 01073 DUPLICATE_SAME_ACCESS, 01074 KernelMode); 01075 if (!NT_SUCCESS(Status)) *DupHandle = NULL; 01076 01077 /* Close the original handle */ 01078 ObCloseHandle(Handle, KernelMode); 01079 } 01080 } 01081 01082 VOID 01083 NTAPI 01084 DbgkpDeleteObject(IN PVOID DebugObject) 01085 { 01086 PAGED_CODE(); 01087 01088 /* Sanity check */ 01089 ASSERT(IsListEmpty(&((PDEBUG_OBJECT)DebugObject)->EventList)); 01090 } 01091 01092 VOID 01093 NTAPI 01094 DbgkpCloseObject(IN PEPROCESS OwnerProcess OPTIONAL, 01095 IN PVOID ObjectBody, 01096 IN ACCESS_MASK GrantedAccess, 01097 IN ULONG HandleCount, 01098 IN ULONG SystemHandleCount) 01099 { 01100 PDEBUG_OBJECT DebugObject = ObjectBody; 01101 PEPROCESS Process = NULL; 01102 BOOLEAN DebugPortCleared = FALSE; 01103 PLIST_ENTRY DebugEventList; 01104 PDEBUG_EVENT DebugEvent; 01105 PAGED_CODE(); 01106 DBGKTRACE(DBGK_OBJECT_DEBUG, "OwnerProcess: %p DebugObject: %p\n", 01107 OwnerProcess, DebugObject); 01108 01109 /* If this isn't the last handle, do nothing */ 01110 if (SystemHandleCount > 1) return; 01111 01112 /* Otherwise, lock the debug object */ 01113 ExAcquireFastMutex(&DebugObject->Mutex); 01114 01115 /* Set it as inactive */ 01116 DebugObject->DebuggerInactive = TRUE; 01117 01118 /* Remove it from the debug event list */ 01119 DebugEventList = DebugObject->EventList.Flink; 01120 InitializeListHead(&DebugObject->EventList); 01121 01122 /* Release the lock */ 01123 ExReleaseFastMutex(&DebugObject->Mutex); 01124 01125 /* Signal the wait event */ 01126 KeSetEvent(&DebugObject->EventsPresent, IO_NO_INCREMENT, FALSE); 01127 01128 /* Start looping each process */ 01129 while ((Process = PsGetNextProcess(Process))) 01130 { 01131 /* Check if the process has us as their debug port */ 01132 if (Process->DebugPort == DebugObject) 01133 { 01134 /* Acquire the process debug port lock */ 01135 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 01136 01137 /* Check if it's still us */ 01138 if (Process->DebugPort == DebugObject) 01139 { 01140 /* Clear it and remember */ 01141 Process->DebugPort = NULL; 01142 DebugPortCleared = TRUE; 01143 } 01144 01145 /* Release the port lock */ 01146 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01147 01148 /* Check if we cleared the debug port */ 01149 if (DebugPortCleared) 01150 { 01151 /* Mark this in the PEB */ 01152 DbgkpMarkProcessPeb(Process); 01153 01154 /* Check if we terminate on exit */ 01155 if (DebugObject->KillProcessOnExit) 01156 { 01157 /* Terminate the process */ 01158 PsTerminateProcess(Process, STATUS_DEBUGGER_INACTIVE); 01159 } 01160 01161 /* Dereference the debug object */ 01162 ObDereferenceObject(DebugObject); 01163 } 01164 } 01165 } 01166 01167 /* Loop debug events */ 01168 while (DebugEventList != &DebugObject->EventList) 01169 { 01170 /* Get the debug event */ 01171 DebugEvent = CONTAINING_RECORD(DebugEventList, DEBUG_EVENT, EventList); 01172 01173 /* Go to the next entry */ 01174 DebugEventList = DebugEventList->Flink; 01175 01176 /* Wake it up */ 01177 DebugEvent->Status = STATUS_DEBUGGER_INACTIVE; 01178 DbgkpWakeTarget(DebugEvent); 01179 } 01180 } 01181 01182 NTSTATUS 01183 NTAPI 01184 DbgkpSetProcessDebugObject(IN PEPROCESS Process, 01185 IN PDEBUG_OBJECT DebugObject, 01186 IN NTSTATUS MsgStatus, 01187 IN PETHREAD LastThread) 01188 { 01189 NTSTATUS Status; 01190 LIST_ENTRY TempList; 01191 BOOLEAN GlobalHeld = FALSE, DoSetEvent = TRUE; 01192 PETHREAD ThisThread, FirstThread; 01193 PLIST_ENTRY NextEntry; 01194 PDEBUG_EVENT DebugEvent; 01195 PETHREAD EventThread; 01196 PAGED_CODE(); 01197 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p DebugObject: %p\n", 01198 Process, DebugObject); 01199 01200 /* Initialize the temporary list */ 01201 InitializeListHead(&TempList); 01202 01203 /* Check if we have a success message */ 01204 if (NT_SUCCESS(MsgStatus)) 01205 { 01206 /* Then default to STATUS_SUCCESS */ 01207 Status = STATUS_SUCCESS; 01208 } 01209 else 01210 { 01211 /* No last thread, and set the failure code */ 01212 LastThread = NULL; 01213 Status = MsgStatus; 01214 } 01215 01216 /* Now check what status we have here */ 01217 if (NT_SUCCESS(Status)) 01218 { 01219 /* Acquire the global lock */ 01220 ThreadScan: 01221 GlobalHeld = TRUE; 01222 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 01223 01224 /* Check if we already have a port */ 01225 if (Process->DebugPort) 01226 { 01227 /* Set failure */ 01228 Status = STATUS_PORT_ALREADY_SET; 01229 } 01230 else 01231 { 01232 /* Otherwise, set the port and reference the thread */ 01233 Process->DebugPort = DebugObject; 01234 ObReferenceObject(LastThread); 01235 01236 /* Get the next thread */ 01237 ThisThread = PsGetNextProcessThread(Process, LastThread); 01238 if (ThisThread) 01239 { 01240 /* Clear the debug port and release the lock */ 01241 Process->DebugPort = NULL; 01242 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01243 GlobalHeld = FALSE; 01244 01245 /* Dereference the thread */ 01246 ObDereferenceObject(LastThread); 01247 01248 /* Post fake messages */ 01249 Status = DbgkpPostFakeThreadMessages(Process, 01250 DebugObject, 01251 ThisThread, 01252 &FirstThread, 01253 &LastThread); 01254 if (!NT_SUCCESS(Status)) 01255 { 01256 /* Clear the last thread */ 01257 LastThread = NULL; 01258 } 01259 else 01260 { 01261 /* Dereference the first thread and re-acquire the lock */ 01262 ObDereferenceObject(FirstThread); 01263 goto ThreadScan; 01264 } 01265 } 01266 } 01267 } 01268 01269 /* Acquire the debug object's lock */ 01270 ExAcquireFastMutex(&DebugObject->Mutex); 01271 01272 /* Check our status here */ 01273 if (NT_SUCCESS(Status)) 01274 { 01275 /* Check if we're disconnected */ 01276 if (DebugObject->DebuggerInactive) 01277 { 01278 /* Set status */ 01279 Process->DebugPort = NULL; 01280 Status = STATUS_DEBUGGER_INACTIVE; 01281 } 01282 else 01283 { 01284 /* Set the process flags */ 01285 PspSetProcessFlag(Process, 01286 PSF_NO_DEBUG_INHERIT_BIT | 01287 PSF_CREATE_REPORTED_BIT); 01288 01289 /* Reference the debug object */ 01290 ObReferenceObject(DebugObject); 01291 } 01292 } 01293 01294 /* Loop the events list */ 01295 NextEntry = DebugObject->EventList.Flink; 01296 while (NextEntry != &DebugObject->EventList) 01297 { 01298 /* Get the debug event and go to the next entry */ 01299 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 01300 NextEntry = NextEntry->Flink; 01301 DBGKTRACE(DBGK_PROCESS_DEBUG, "DebugEvent: %p Flags: %lx TH: %p/%p\n", 01302 DebugEvent, DebugEvent->Flags, 01303 DebugEvent->BackoutThread, PsGetCurrentThread()); 01304 01305 /* Check for if the debug event queue needs flushing */ 01306 if ((DebugEvent->Flags & DEBUG_EVENT_INACTIVE) && 01307 (DebugEvent->BackoutThread == PsGetCurrentThread())) 01308 { 01309 /* Get the event's thread */ 01310 EventThread = DebugEvent->Thread; 01311 DBGKTRACE(DBGK_PROCESS_DEBUG, "EventThread: %p MsgStatus: %lx\n", 01312 EventThread, MsgStatus); 01313 01314 /* Check if the status is success */ 01315 if ((MsgStatus == STATUS_SUCCESS) && 01316 (EventThread->GrantedAccess) && 01317 (!EventThread->SystemThread)) 01318 { 01319 /* Check if we couldn't acquire rundown for it */ 01320 if (DebugEvent->Flags & DEBUG_EVENT_PROTECT_FAILED) 01321 { 01322 /* Set the skip termination flag */ 01323 PspSetCrossThreadFlag(EventThread, CT_SKIP_CREATION_MSG_BIT); 01324 01325 /* Insert it into the temp list */ 01326 RemoveEntryList(&DebugEvent->EventList); 01327 InsertTailList(&TempList, &DebugEvent->EventList); 01328 } 01329 else 01330 { 01331 /* Do we need to signal the event */ 01332 if (DoSetEvent) 01333 { 01334 /* Do it */ 01335 DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE; 01336 KeSetEvent(&DebugObject->EventsPresent, 01337 IO_NO_INCREMENT, 01338 FALSE); 01339 DoSetEvent = FALSE; 01340 } 01341 01342 /* Clear the backout thread */ 01343 DebugEvent->BackoutThread = NULL; 01344 01345 /* Set skip flag */ 01346 PspSetCrossThreadFlag(EventThread, CT_SKIP_CREATION_MSG_BIT); 01347 } 01348 } 01349 else 01350 { 01351 /* Insert it into the temp list */ 01352 RemoveEntryList(&DebugEvent->EventList); 01353 InsertTailList(&TempList, &DebugEvent->EventList); 01354 } 01355 01356 /* Check if the lock is held */ 01357 if (DebugEvent->Flags & DEBUG_EVENT_RELEASE) 01358 { 01359 /* Release it */ 01360 DebugEvent->Flags &= ~DEBUG_EVENT_RELEASE; 01361 ExReleaseRundownProtection(&EventThread->RundownProtect); 01362 } 01363 } 01364 } 01365 01366 /* Release the debug object */ 01367 ExReleaseFastMutex(&DebugObject->Mutex); 01368 01369 /* Release the global lock if acquired */ 01370 if (GlobalHeld) ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01371 01372 /* Check if there's a thread to dereference */ 01373 if (LastThread) ObDereferenceObject(LastThread); 01374 01375 /* Loop our temporary list */ 01376 while (!IsListEmpty(&TempList)) 01377 { 01378 /* Remove the event */ 01379 NextEntry = RemoveHeadList(&TempList); 01380 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 01381 01382 /* Wake it */ 01383 DbgkpWakeTarget(DebugEvent); 01384 } 01385 01386 /* Check if we got here through success and mark the PEB, then return */ 01387 if (NT_SUCCESS(Status)) DbgkpMarkProcessPeb(Process); 01388 return Status; 01389 } 01390 01391 NTSTATUS 01392 NTAPI 01393 DbgkClearProcessDebugObject(IN PEPROCESS Process, 01394 IN PDEBUG_OBJECT SourceDebugObject OPTIONAL) 01395 { 01396 PDEBUG_OBJECT DebugObject; 01397 PDEBUG_EVENT DebugEvent; 01398 LIST_ENTRY TempList; 01399 PLIST_ENTRY NextEntry; 01400 PAGED_CODE(); 01401 DBGKTRACE(DBGK_OBJECT_DEBUG, "Process: %p DebugObject: %p\n", 01402 Process, SourceDebugObject); 01403 01404 /* Acquire the port lock */ 01405 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 01406 01407 /* Get the Process Debug Object */ 01408 DebugObject = Process->DebugPort; 01409 01410 /* 01411 * Check if the process had an object and it matches, 01412 * or if the process had an object but none was specified 01413 * (in which we are called from NtTerminateProcess) 01414 */ 01415 if ((DebugObject) && 01416 ((DebugObject == SourceDebugObject) || 01417 (SourceDebugObject == NULL))) 01418 { 01419 /* Clear the debug port */ 01420 Process->DebugPort = NULL; 01421 01422 /* Release the port lock and remove the PEB flag */ 01423 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01424 DbgkpMarkProcessPeb(Process); 01425 } 01426 else 01427 { 01428 /* Release the port lock and fail */ 01429 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01430 return STATUS_PORT_NOT_SET; 01431 } 01432 01433 /* Initialize the temporary list */ 01434 InitializeListHead(&TempList); 01435 01436 /* Acquire the Object */ 01437 ExAcquireFastMutex(&DebugObject->Mutex); 01438 01439 /* Loop the events */ 01440 NextEntry = DebugObject->EventList.Flink; 01441 while (NextEntry != &DebugObject->EventList) 01442 { 01443 /* Get the Event and go to the next entry */ 01444 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 01445 NextEntry = NextEntry->Flink; 01446 01447 /* Check that it belongs to the specified process */ 01448 if (DebugEvent->Process == Process) 01449 { 01450 /* Insert it into the temporary list */ 01451 RemoveEntryList(&DebugEvent->EventList); 01452 InsertTailList(&TempList, &DebugEvent->EventList); 01453 } 01454 } 01455 01456 /* Release the Object */ 01457 ExReleaseFastMutex(&DebugObject->Mutex); 01458 01459 /* Release the initial reference */ 01460 ObDereferenceObject(DebugObject); 01461 01462 /* Loop our temporary list */ 01463 while (!IsListEmpty(&TempList)) 01464 { 01465 /* Remove the event */ 01466 NextEntry = RemoveHeadList(&TempList); 01467 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 01468 01469 /* Wake it up */ 01470 DebugEvent->Status = STATUS_DEBUGGER_INACTIVE; 01471 DbgkpWakeTarget(DebugEvent); 01472 } 01473 01474 /* Return Success */ 01475 return STATUS_SUCCESS; 01476 } 01477 01478 VOID 01479 INIT_FUNCTION 01480 NTAPI 01481 DbgkInitialize(VOID) 01482 { 01483 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 01484 UNICODE_STRING Name; 01485 PAGED_CODE(); 01486 01487 /* Initialize the process debug port mutex */ 01488 ExInitializeFastMutex(&DbgkpProcessDebugPortMutex); 01489 01490 /* Create the Debug Object Type */ 01491 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 01492 RtlInitUnicodeString(&Name, L"DebugObject"); 01493 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 01494 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DEBUG_OBJECT); 01495 ObjectTypeInitializer.GenericMapping = DbgkDebugObjectMapping; 01496 ObjectTypeInitializer.PoolType = NonPagedPool; 01497 ObjectTypeInitializer.ValidAccessMask = DEBUG_OBJECT_ALL_ACCESS; 01498 ObjectTypeInitializer.UseDefaultObject = TRUE; 01499 ObjectTypeInitializer.CloseProcedure = DbgkpCloseObject; 01500 ObjectTypeInitializer.DeleteProcedure = DbgkpDeleteObject; 01501 ObCreateObjectType(&Name, 01502 &ObjectTypeInitializer, 01503 NULL, 01504 &DbgkDebugObjectType); 01505 } 01506 01507 NTSTATUS 01508 NTAPI 01509 DbgkOpenProcessDebugPort(IN PEPROCESS Process, 01510 IN KPROCESSOR_MODE PreviousMode, 01511 OUT HANDLE *DebugHandle) 01512 { 01513 PDEBUG_OBJECT DebugObject; 01514 NTSTATUS Status; 01515 PAGED_CODE(); 01516 01517 /* If there's no debug port, just exit */ 01518 if (!Process->DebugPort) return STATUS_PORT_NOT_SET; 01519 01520 /* Otherwise, acquire the lock while we grab the port */ 01521 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 01522 01523 /* Grab it and reference it if it exists */ 01524 DebugObject = Process->DebugPort; 01525 if (DebugObject) ObReferenceObject(DebugObject); 01526 01527 /* Release the lock now */ 01528 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 01529 01530 /* Bail out if it doesn't exist */ 01531 if (!DebugObject) return STATUS_PORT_NOT_SET; 01532 01533 /* Now get a handle to it */ 01534 Status = ObOpenObjectByPointer(DebugObject, 01535 0, 01536 NULL, 01537 MAXIMUM_ALLOWED, 01538 DbgkDebugObjectType, 01539 PreviousMode, 01540 DebugHandle); 01541 if (!NT_SUCCESS(Status)) ObDereferenceObject(DebugObject); 01542 01543 /* Return status */ 01544 return Status; 01545 } 01546 01547 /* PUBLIC FUNCTIONS **********************************************************/ 01548 01549 /* 01550 * @implemented 01551 */ 01552 NTSTATUS 01553 NTAPI 01554 NtCreateDebugObject(OUT PHANDLE DebugHandle, 01555 IN ACCESS_MASK DesiredAccess, 01556 IN POBJECT_ATTRIBUTES ObjectAttributes, 01557 IN ULONG Flags) 01558 { 01559 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01560 PDEBUG_OBJECT DebugObject; 01561 HANDLE hDebug; 01562 NTSTATUS Status; 01563 PAGED_CODE(); 01564 01565 /* Check if we were called from user mode*/ 01566 if (PreviousMode != KernelMode) 01567 { 01568 /* Enter SEH for probing */ 01569 _SEH2_TRY 01570 { 01571 /* Probe the handle */ 01572 ProbeForWriteHandle(DebugHandle); 01573 } 01574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01575 { 01576 /* Return the exception code */ 01577 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 01578 } _SEH2_END; 01579 } 01580 01581 /* Check for invalid flags */ 01582 if (Flags & ~DBGK_ALL_FLAGS) return STATUS_INVALID_PARAMETER; 01583 01584 /* Create the Object */ 01585 Status = ObCreateObject(PreviousMode, 01586 DbgkDebugObjectType, 01587 ObjectAttributes, 01588 PreviousMode, 01589 NULL, 01590 sizeof(DEBUG_OBJECT), 01591 0, 01592 0, 01593 (PVOID*)&DebugObject); 01594 if (NT_SUCCESS(Status)) 01595 { 01596 /* Initialize the Debug Object's Fast Mutex */ 01597 ExInitializeFastMutex(&DebugObject->Mutex); 01598 01599 /* Initialize the State Event List */ 01600 InitializeListHead(&DebugObject->EventList); 01601 01602 /* Initialize the Debug Object's Wait Event */ 01603 KeInitializeEvent(&DebugObject->EventsPresent, 01604 NotificationEvent, 01605 FALSE); 01606 01607 /* Set the Flags */ 01608 DebugObject->Flags = 0; 01609 if (Flags & DBGK_KILL_PROCESS_ON_EXIT) 01610 { 01611 DebugObject->KillProcessOnExit = TRUE; 01612 } 01613 01614 /* Insert it */ 01615 Status = ObInsertObject((PVOID)DebugObject, 01616 NULL, 01617 DesiredAccess, 01618 0, 01619 NULL, 01620 &hDebug); 01621 if (NT_SUCCESS(Status)) 01622 { 01623 /* Enter SEH to protect the write */ 01624 _SEH2_TRY 01625 { 01626 /* Return the handle */ 01627 *DebugHandle = hDebug; 01628 } 01629 _SEH2_EXCEPT(ExSystemExceptionFilter()) 01630 { 01631 /* Get the exception code */ 01632 Status = _SEH2_GetExceptionCode(); 01633 } _SEH2_END; 01634 } 01635 } 01636 01637 /* Return Status */ 01638 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p DebugObject: %p\n", 01639 hDebug, DebugObject); 01640 return Status; 01641 } 01642 01643 /* 01644 * @implemented 01645 */ 01646 NTSTATUS 01647 NTAPI 01648 NtDebugContinue(IN HANDLE DebugHandle, 01649 IN PCLIENT_ID AppClientId, 01650 IN NTSTATUS ContinueStatus) 01651 { 01652 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01653 PDEBUG_OBJECT DebugObject; 01654 NTSTATUS Status; 01655 PDEBUG_EVENT DebugEvent = NULL, DebugEventToWake = NULL; 01656 PLIST_ENTRY ListHead, NextEntry; 01657 BOOLEAN NeedsWake = FALSE; 01658 CLIENT_ID ClientId; 01659 PAGED_CODE(); 01660 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p Status: %p\n", 01661 DebugHandle, ContinueStatus); 01662 01663 /* Check if we were called from user mode*/ 01664 if (PreviousMode != KernelMode) 01665 { 01666 /* Enter SEH for probing */ 01667 _SEH2_TRY 01668 { 01669 /* Probe the handle */ 01670 ProbeForRead(AppClientId, sizeof(CLIENT_ID), sizeof(ULONG)); 01671 ClientId = *AppClientId; 01672 AppClientId = &ClientId; 01673 } 01674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01675 { 01676 /* Return the exception code */ 01677 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 01678 } _SEH2_END; 01679 } 01680 01681 /* Make sure that the status is valid */ 01682 if ((ContinueStatus != DBG_CONTINUE) && 01683 (ContinueStatus != DBG_EXCEPTION_HANDLED) && 01684 (ContinueStatus != DBG_EXCEPTION_NOT_HANDLED) && 01685 (ContinueStatus != DBG_TERMINATE_THREAD) && 01686 (ContinueStatus != DBG_TERMINATE_PROCESS)) 01687 { 01688 /* Invalid status */ 01689 Status = STATUS_INVALID_PARAMETER; 01690 } 01691 else 01692 { 01693 /* Get the debug object */ 01694 Status = ObReferenceObjectByHandle(DebugHandle, 01695 DEBUG_OBJECT_WAIT_STATE_CHANGE, 01696 DbgkDebugObjectType, 01697 PreviousMode, 01698 (PVOID*)&DebugObject, 01699 NULL); 01700 if (NT_SUCCESS(Status)) 01701 { 01702 /* Acquire the mutex */ 01703 ExAcquireFastMutex(&DebugObject->Mutex); 01704 01705 /* Loop the state list */ 01706 ListHead = &DebugObject->EventList; 01707 NextEntry = ListHead->Flink; 01708 while (ListHead != NextEntry) 01709 { 01710 /* Get the current debug event */ 01711 DebugEvent = CONTAINING_RECORD(NextEntry, 01712 DEBUG_EVENT, 01713 EventList); 01714 01715 /* Compare process ID */ 01716 if (DebugEvent->ClientId.UniqueProcess == 01717 AppClientId->UniqueProcess) 01718 { 01719 /* Check if we already found a match */ 01720 if (NeedsWake) 01721 { 01722 /* Wake it up and break out */ 01723 DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE; 01724 KeSetEvent(&DebugObject->EventsPresent, 01725 IO_NO_INCREMENT, 01726 FALSE); 01727 break; 01728 } 01729 01730 /* Compare thread ID and flag */ 01731 if ((DebugEvent->ClientId.UniqueThread == 01732 AppClientId->UniqueThread) && (DebugEvent->Flags & DEBUG_EVENT_READ)) 01733 { 01734 /* Remove the event from the list */ 01735 RemoveEntryList(NextEntry); 01736 01737 /* Remember who to wake */ 01738 NeedsWake = TRUE; 01739 DebugEventToWake = DebugEvent; 01740 } 01741 } 01742 01743 /* Go to the next entry */ 01744 NextEntry = NextEntry->Flink; 01745 } 01746 01747 /* Release the mutex */ 01748 ExReleaseFastMutex(&DebugObject->Mutex); 01749 01750 /* Dereference the object */ 01751 ObDereferenceObject(DebugObject); 01752 01753 /* Check if need a wait */ 01754 if (NeedsWake) 01755 { 01756 /* Set the continue status */ 01757 DebugEventToWake->ApiMsg.ReturnedStatus = ContinueStatus; 01758 DebugEventToWake->Status = STATUS_SUCCESS; 01759 01760 /* Wake the target */ 01761 DbgkpWakeTarget(DebugEventToWake); 01762 } 01763 else 01764 { 01765 /* Fail */ 01766 Status = STATUS_INVALID_PARAMETER; 01767 } 01768 } 01769 } 01770 01771 /* Return status */ 01772 return Status; 01773 } 01774 01775 /* 01776 * @implemented 01777 */ 01778 NTSTATUS 01779 NTAPI 01780 NtDebugActiveProcess(IN HANDLE ProcessHandle, 01781 IN HANDLE DebugHandle) 01782 { 01783 PEPROCESS Process; 01784 PDEBUG_OBJECT DebugObject; 01785 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01786 PETHREAD LastThread; 01787 NTSTATUS Status; 01788 PAGED_CODE(); 01789 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Handle: %p\n", 01790 ProcessHandle, DebugHandle); 01791 01792 /* Reference the process */ 01793 Status = ObReferenceObjectByHandle(ProcessHandle, 01794 PROCESS_SUSPEND_RESUME, 01795 PsProcessType, 01796 PreviousMode, 01797 (PVOID*)&Process, 01798 NULL); 01799 if (!NT_SUCCESS(Status)) return Status; 01800 01801 /* Don't allow debugging the current process or the system process */ 01802 if ((Process == PsGetCurrentProcess()) || 01803 (Process == PsInitialSystemProcess)) 01804 { 01805 /* Dereference and fail */ 01806 ObDereferenceObject(Process); 01807 return STATUS_ACCESS_DENIED; 01808 } 01809 01810 /* Reference the debug object */ 01811 Status = ObReferenceObjectByHandle(DebugHandle, 01812 DEBUG_OBJECT_ADD_REMOVE_PROCESS, 01813 DbgkDebugObjectType, 01814 PreviousMode, 01815 (PVOID*)&DebugObject, 01816 NULL); 01817 if (!NT_SUCCESS(Status)) 01818 { 01819 /* Dereference the process and exit */ 01820 ObDereferenceObject(Process); 01821 return Status; 01822 } 01823 01824 /* Acquire process rundown protection */ 01825 if (!ExAcquireRundownProtection(&Process->RundownProtect)) 01826 { 01827 /* Dereference the process and debug object and exit */ 01828 ObDereferenceObject(Process); 01829 ObDereferenceObject(DebugObject); 01830 return STATUS_PROCESS_IS_TERMINATING; 01831 } 01832 01833 /* Send fake create messages for debuggers to have a consistent state */ 01834 Status = DbgkpPostFakeProcessCreateMessages(Process, 01835 DebugObject, 01836 &LastThread); 01837 Status = DbgkpSetProcessDebugObject(Process, 01838 DebugObject, 01839 Status, 01840 LastThread); 01841 01842 /* Release rundown protection */ 01843 ExReleaseRundownProtection(&Process->RundownProtect); 01844 01845 /* Dereference the process and debug object and return status */ 01846 ObDereferenceObject(Process); 01847 ObDereferenceObject(DebugObject); 01848 return Status; 01849 } 01850 01851 /* 01852 * @implemented 01853 */ 01854 NTSTATUS 01855 NTAPI 01856 NtRemoveProcessDebug(IN HANDLE ProcessHandle, 01857 IN HANDLE DebugHandle) 01858 { 01859 PEPROCESS Process; 01860 PDEBUG_OBJECT DebugObject; 01861 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01862 NTSTATUS Status; 01863 PAGED_CODE(); 01864 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Handle: %p\n", 01865 ProcessHandle, DebugHandle); 01866 01867 /* Reference the process */ 01868 Status = ObReferenceObjectByHandle(ProcessHandle, 01869 PROCESS_SUSPEND_RESUME, 01870 PsProcessType, 01871 PreviousMode, 01872 (PVOID*)&Process, 01873 NULL); 01874 if (!NT_SUCCESS(Status)) return Status; 01875 01876 /* Reference the debug object */ 01877 Status = ObReferenceObjectByHandle(DebugHandle, 01878 DEBUG_OBJECT_ADD_REMOVE_PROCESS, 01879 DbgkDebugObjectType, 01880 PreviousMode, 01881 (PVOID*)&DebugObject, 01882 NULL); 01883 if (!NT_SUCCESS(Status)) 01884 { 01885 /* Dereference the process and exit */ 01886 ObDereferenceObject(Process); 01887 return Status; 01888 } 01889 01890 /* Remove the debug object */ 01891 Status = DbgkClearProcessDebugObject(Process, DebugObject); 01892 01893 /* Dereference the process and debug object and return status */ 01894 ObDereferenceObject(Process); 01895 ObDereferenceObject(DebugObject); 01896 return Status; 01897 } 01898 01899 /* 01900 * @implemented 01901 */ 01902 NTSTATUS 01903 NTAPI 01904 NtSetInformationDebugObject(IN HANDLE DebugHandle, 01905 IN DEBUGOBJECTINFOCLASS DebugObjectInformationClass, 01906 IN PVOID DebugInformation, 01907 IN ULONG DebugInformationLength, 01908 OUT PULONG ReturnLength OPTIONAL) 01909 { 01910 PDEBUG_OBJECT DebugObject; 01911 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01912 NTSTATUS Status; 01913 PDEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION DebugInfo = DebugInformation; 01914 PAGED_CODE(); 01915 01916 /* Check buffers and parameters */ 01917 Status = DefaultSetInfoBufferCheck(DebugObjectInformationClass, 01918 DbgkpDebugObjectInfoClass, 01919 sizeof(DbgkpDebugObjectInfoClass) / 01920 sizeof(DbgkpDebugObjectInfoClass[0]), 01921 DebugInformation, 01922 DebugInformationLength, 01923 PreviousMode); 01924 if (!NT_SUCCESS(Status)) return Status; 01925 01926 /* Check if the caller wanted the return length */ 01927 if (ReturnLength) 01928 { 01929 /* Enter SEH for probe */ 01930 _SEH2_TRY 01931 { 01932 /* Return required length to user-mode */ 01933 ProbeForWriteUlong(ReturnLength); 01934 *ReturnLength = sizeof(*DebugInfo); 01935 } 01936 _SEH2_EXCEPT(ExSystemExceptionFilter()) 01937 { 01938 /* Return the exception code */ 01939 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 01940 } 01941 _SEH2_END; 01942 } 01943 01944 /* Open the Object */ 01945 Status = ObReferenceObjectByHandle(DebugHandle, 01946 DEBUG_OBJECT_WAIT_STATE_CHANGE, 01947 DbgkDebugObjectType, 01948 PreviousMode, 01949 (PVOID*)&DebugObject, 01950 NULL); 01951 if (NT_SUCCESS(Status)) 01952 { 01953 /* Acquire the object */ 01954 ExAcquireFastMutex(&DebugObject->Mutex); 01955 01956 /* Set the proper flag */ 01957 if (DebugInfo->KillProcessOnExit) 01958 { 01959 /* Enable killing the process */ 01960 DebugObject->KillProcessOnExit = TRUE; 01961 } 01962 else 01963 { 01964 /* Disable */ 01965 DebugObject->KillProcessOnExit = FALSE; 01966 } 01967 01968 /* Release the mutex */ 01969 ExReleaseFastMutex(&DebugObject->Mutex); 01970 01971 /* Release the Object */ 01972 ObDereferenceObject(DebugObject); 01973 } 01974 01975 /* Return Status */ 01976 return Status; 01977 } 01978 01979 /* 01980 * @implemented 01981 */ 01982 NTSTATUS 01983 NTAPI 01984 NtWaitForDebugEvent(IN HANDLE DebugHandle, 01985 IN BOOLEAN Alertable, 01986 IN PLARGE_INTEGER Timeout OPTIONAL, 01987 OUT PDBGUI_WAIT_STATE_CHANGE StateChange) 01988 { 01989 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01990 LARGE_INTEGER LocalTimeOut; 01991 PEPROCESS Process; 01992 LARGE_INTEGER StartTime; 01993 PETHREAD Thread; 01994 BOOLEAN GotEvent; 01995 LARGE_INTEGER NewTime; 01996 PDEBUG_OBJECT DebugObject; 01997 DBGUI_WAIT_STATE_CHANGE WaitStateChange; 01998 NTSTATUS Status; 01999 PDEBUG_EVENT DebugEvent = NULL, DebugEvent2; 02000 PLIST_ENTRY ListHead, NextEntry, NextEntry2; 02001 PAGED_CODE(); 02002 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p\n", DebugHandle); 02003 02004 /* Clear the initial wait state change structure and the timeout */ 02005 RtlZeroMemory(&WaitStateChange, sizeof(WaitStateChange)); 02006 LocalTimeOut.QuadPart = 0; 02007 02008 /* Check if we were called from user mode */ 02009 if (PreviousMode != KernelMode) 02010 { 02011 /* Protect probe in SEH */ 02012 _SEH2_TRY 02013 { 02014 /* Check if we came with a timeout */ 02015 if (Timeout) 02016 { 02017 /* Probe it */ 02018 ProbeForReadLargeInteger(Timeout); 02019 02020 /* Make a local copy */ 02021 LocalTimeOut = *Timeout; 02022 Timeout = &LocalTimeOut; 02023 } 02024 02025 /* Probe the state change structure */ 02026 ProbeForWrite(StateChange, sizeof(*StateChange), sizeof(ULONG)); 02027 } 02028 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02029 { 02030 /* Return the exception code */ 02031 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 02032 } 02033 _SEH2_END; 02034 } 02035 else 02036 { 02037 /* Copy directly */ 02038 if (Timeout) LocalTimeOut = *Timeout; 02039 } 02040 02041 /* If we were passed a timeout, query the current time */ 02042 if (Timeout) KeQuerySystemTime(&StartTime); 02043 02044 /* Get the debug object */ 02045 Status = ObReferenceObjectByHandle(DebugHandle, 02046 DEBUG_OBJECT_WAIT_STATE_CHANGE, 02047 DbgkDebugObjectType, 02048 PreviousMode, 02049 (PVOID*)&DebugObject, 02050 NULL); 02051 if (!NT_SUCCESS(Status)) return Status; 02052 02053 /* Clear process and thread */ 02054 Process = NULL; 02055 Thread = NULL; 02056 02057 /* Wait on the debug object given to us */ 02058 while (TRUE) 02059 { 02060 Status = KeWaitForSingleObject(&DebugObject->EventsPresent, 02061 Executive, 02062 PreviousMode, 02063 Alertable, 02064 Timeout); 02065 if (!NT_SUCCESS(Status) || 02066 (Status == STATUS_TIMEOUT) || 02067 (Status == STATUS_ALERTED) || 02068 (Status == STATUS_USER_APC)) 02069 { 02070 /* Break out the wait */ 02071 break; 02072 } 02073 02074 /* Lock the object */ 02075 GotEvent = FALSE; 02076 ExAcquireFastMutex(&DebugObject->Mutex); 02077 02078 /* Check if a debugger is connected */ 02079 if (DebugObject->DebuggerInactive) 02080 { 02081 /* Not connected */ 02082 Status = STATUS_DEBUGGER_INACTIVE; 02083 } 02084 else 02085 { 02086 /* Loop the events */ 02087 ListHead = &DebugObject->EventList; 02088 NextEntry = ListHead->Flink; 02089 while (ListHead != NextEntry) 02090 { 02091 /* Get the debug event */ 02092 DebugEvent = CONTAINING_RECORD(NextEntry, 02093 DEBUG_EVENT, 02094 EventList); 02095 DBGKTRACE(DBGK_PROCESS_DEBUG, "DebugEvent: %p Flags: %lx\n", 02096 DebugEvent, DebugEvent->Flags); 02097 02098 /* Check flags */ 02099 if (!(DebugEvent->Flags & (DEBUG_EVENT_INACTIVE | DEBUG_EVENT_READ))) 02100 { 02101 /* We got an event */ 02102 GotEvent = TRUE; 02103 02104 /* Loop the list internally */ 02105 NextEntry2 = DebugObject->EventList.Flink; 02106 while (NextEntry2 != NextEntry) 02107 { 02108 /* Get the debug event */ 02109 DebugEvent2 = CONTAINING_RECORD(NextEntry2, 02110 DEBUG_EVENT, 02111 EventList); 02112 02113 /* Try to match process IDs */ 02114 if (DebugEvent2->ClientId.UniqueProcess == 02115 DebugEvent->ClientId.UniqueProcess) 02116 { 02117 /* Found it, break out */ 02118 DebugEvent->Flags |= DEBUG_EVENT_INACTIVE; 02119 DebugEvent->BackoutThread = NULL; 02120 GotEvent = FALSE; 02121 break; 02122 } 02123 02124 /* Move to the next entry */ 02125 NextEntry2 = NextEntry2->Flink; 02126 } 02127 02128 /* Check if we still have a valid event */ 02129 if (GotEvent) break; 02130 } 02131 02132 /* Move to the next entry */ 02133 NextEntry = NextEntry->Flink; 02134 } 02135 02136 /* Check if we have an event */ 02137 if (GotEvent) 02138 { 02139 /* Save and reference the process and thread */ 02140 Process = DebugEvent->Process; 02141 Thread = DebugEvent->Thread; 02142 ObReferenceObject(Process); 02143 ObReferenceObject(Thread); 02144 02145 /* Convert to user-mode structure */ 02146 DbgkpConvertKernelToUserStateChange(&WaitStateChange, 02147 DebugEvent); 02148 02149 /* Set flag */ 02150 DebugEvent->Flags |= DEBUG_EVENT_READ; 02151 } 02152 else 02153 { 02154 /* Unsignal the event */ 02155 KeClearEvent(&DebugObject->EventsPresent); 02156 } 02157 02158 /* Set success */ 02159 Status = STATUS_SUCCESS; 02160 } 02161 02162 /* Release the mutex */ 02163 ExReleaseFastMutex(&DebugObject->Mutex); 02164 if (!NT_SUCCESS(Status)) break; 02165 02166 /* Check if we got an event */ 02167 if (!GotEvent) 02168 { 02169 /* Check if we can wait again */ 02170 if (LocalTimeOut.QuadPart < 0) 02171 { 02172 /* Query the new time */ 02173 KeQuerySystemTime(&NewTime); 02174 02175 /* Substract times */ 02176 LocalTimeOut.QuadPart += (NewTime.QuadPart - StartTime.QuadPart); 02177 StartTime = NewTime; 02178 02179 /* Check if we've timed out */ 02180 if (LocalTimeOut.QuadPart >= 0) 02181 { 02182 /* We have, break out of the loop */ 02183 Status = STATUS_TIMEOUT; 02184 break; 02185 } 02186 } 02187 } 02188 else 02189 { 02190 /* Open the handles and dereference the objects */ 02191 DbgkpOpenHandles(&WaitStateChange, Process, Thread); 02192 ObDereferenceObject(Process); 02193 ObDereferenceObject(Thread); 02194 break; 02195 } 02196 } 02197 02198 /* We're done, dereference the object */ 02199 ObDereferenceObject(DebugObject); 02200 02201 /* Protect write with SEH */ 02202 _SEH2_TRY 02203 { 02204 /* Return our wait state change structure */ 02205 *StateChange = WaitStateChange; 02206 } 02207 _SEH2_EXCEPT(ExSystemExceptionFilter()) 02208 { 02209 /* Get SEH Exception code */ 02210 Status = _SEH2_GetExceptionCode(); 02211 } 02212 _SEH2_END; 02213 02214 /* Return status */ 02215 return Status; 02216 } Generated on Sun May 27 2012 04:37:09 for ReactOS by
1.7.6.1
|