1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/dbgk/dbgkobj.c 5 * PURPOSE: User-Mode Debugging Support, Debug Object Management. 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 POBJECT_TYPE DbgkDebugObjectType; 16 FAST_MUTEX DbgkpProcessDebugPortMutex; 17 ULONG DbgkpTraceLevel = 0; 18 19 GENERIC_MAPPING DbgkDebugObjectMapping = 20 { 21 STANDARD_RIGHTS_READ | DEBUG_OBJECT_WAIT_STATE_CHANGE, 22 STANDARD_RIGHTS_WRITE | DEBUG_OBJECT_ADD_REMOVE_PROCESS, 23 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 24 DEBUG_OBJECT_ALL_ACCESS 25 }; 26 27 static const INFORMATION_CLASS_INFO DbgkpDebugObjectInfoClass[] = 28 { 29 /* DebugObjectUnusedInformation */ 30 ICI_SQ_SAME(sizeof(ULONG), sizeof(ULONG), 0), 31 /* DebugObjectKillProcessOnExitInformation */ 32 ICI_SQ_SAME(sizeof(DEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION), sizeof(ULONG), ICIF_SET), 33 }; 34 35 /* PRIVATE FUNCTIONS *********************************************************/ 36 37 NTSTATUS 38 NTAPI 39 DbgkpQueueMessage(IN PEPROCESS Process, 40 IN PETHREAD Thread, 41 IN PDBGKM_MSG Message, 42 IN ULONG Flags, 43 IN PDEBUG_OBJECT TargetObject OPTIONAL) 44 { 45 PDEBUG_EVENT DebugEvent; 46 DEBUG_EVENT LocalDebugEvent; 47 PDEBUG_OBJECT DebugObject; 48 NTSTATUS Status; 49 BOOLEAN NewEvent; 50 PAGED_CODE(); 51 DBGKTRACE(DBGK_MESSAGE_DEBUG, 52 "Process: %p Thread: %p Message: %p Flags: %lx\n", 53 Process, Thread, Message, Flags); 54 55 /* Check if we have to allocate a debug event */ 56 NewEvent = (Flags & DEBUG_EVENT_NOWAIT) ? TRUE : FALSE; 57 if (NewEvent) 58 { 59 /* Allocate it */ 60 DebugEvent = ExAllocatePoolWithTag(NonPagedPool, 61 sizeof(DEBUG_EVENT), 62 'EgbD'); 63 if (!DebugEvent) return STATUS_INSUFFICIENT_RESOURCES; 64 65 /* Set flags */ 66 DebugEvent->Flags = Flags | DEBUG_EVENT_INACTIVE; 67 68 /* Reference the thread and process */ 69 ObReferenceObject(Thread); 70 ObReferenceObject(Process); 71 72 /* Set the current thread */ 73 DebugEvent->BackoutThread = PsGetCurrentThread(); 74 75 /* Set the debug object */ 76 DebugObject = TargetObject; 77 } 78 else 79 { 80 /* Use the debug event on the stack */ 81 DebugEvent = &LocalDebugEvent; 82 DebugEvent->Flags = Flags; 83 84 /* Acquire the port lock */ 85 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 86 87 /* Get the debug object */ 88 DebugObject = Process->DebugPort; 89 90 /* Check what kind of API message this is */ 91 switch (Message->ApiNumber) 92 { 93 /* Process or thread creation */ 94 case DbgKmCreateThreadApi: 95 case DbgKmCreateProcessApi: 96 97 /* Make sure we're not skipping creation messages */ 98 if (Thread->SkipCreationMsg) DebugObject = NULL; 99 break; 100 101 /* Process or thread exit */ 102 case DbgKmExitThreadApi: 103 case DbgKmExitProcessApi: 104 105 /* Make sure we're not skipping exit messages */ 106 if (Thread->SkipTerminationMsg) DebugObject = NULL; 107 108 /* No special handling for other messages */ 109 default: 110 break; 111 } 112 } 113 114 /* Setup the Debug Event */ 115 KeInitializeEvent(&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE); 116 DebugEvent->Process = Process; 117 DebugEvent->Thread = Thread; 118 DebugEvent->ApiMsg = *Message; 119 DebugEvent->ClientId = Thread->Cid; 120 121 /* Check if we have a port object */ 122 if (!DebugObject) 123 { 124 /* Fail */ 125 Status = STATUS_PORT_NOT_SET; 126 } 127 else 128 { 129 /* Acquire the debug object mutex */ 130 ExAcquireFastMutex(&DebugObject->Mutex); 131 132 /* Check if a debugger is active */ 133 if (!DebugObject->DebuggerInactive) 134 { 135 /* Add the event into the object's list */ 136 DBGKTRACE(DBGK_MESSAGE_DEBUG, "Inserting: %p %d\n", 137 DebugEvent, Message->ApiNumber); 138 InsertTailList(&DebugObject->EventList, &DebugEvent->EventList); 139 140 /* Check if we have to signal it */ 141 if (!NewEvent) 142 { 143 /* Signal it */ 144 KeSetEvent(&DebugObject->EventsPresent, 145 IO_NO_INCREMENT, 146 FALSE); 147 } 148 149 /* Set success */ 150 Status = STATUS_SUCCESS; 151 } 152 else 153 { 154 /* No debugger */ 155 Status = STATUS_DEBUGGER_INACTIVE; 156 } 157 158 /* Release the object lock */ 159 ExReleaseFastMutex(&DebugObject->Mutex); 160 } 161 162 /* Check if we had acquired the port lock */ 163 if (!NewEvent) 164 { 165 /* Release it */ 166 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 167 168 /* Check if we got here through success */ 169 if (NT_SUCCESS(Status)) 170 { 171 /* Wait on the continue event */ 172 KeWaitForSingleObject(&DebugEvent->ContinueEvent, 173 Executive, 174 KernelMode, 175 FALSE, 176 NULL); 177 178 /* Copy API Message back */ 179 *Message = DebugEvent->ApiMsg; 180 181 /* Set return status */ 182 Status = DebugEvent->Status; 183 } 184 } 185 else 186 { 187 /* Check if we failed */ 188 if (!NT_SUCCESS(Status)) 189 { 190 /* Dereference the process and thread */ 191 ObDereferenceObject(Thread); 192 ObDereferenceObject(Process); 193 194 /* Free the debug event */ 195 ExFreePoolWithTag(DebugEvent, 'EgbD'); 196 } 197 } 198 199 /* Return status */ 200 DBGKTRACE(DBGK_MESSAGE_DEBUG, "Status: %lx\n", Status); 201 return Status; 202 } 203 204 NTSTATUS 205 NTAPI 206 DbgkpSendApiMessageLpc(IN OUT PDBGKM_MSG Message, 207 IN PVOID Port, 208 IN BOOLEAN SuspendProcess) 209 { 210 NTSTATUS Status; 211 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; 212 BOOLEAN Suspended = FALSE; 213 PAGED_CODE(); 214 215 /* Suspend process if required */ 216 if (SuspendProcess) Suspended = DbgkpSuspendProcess(); 217 218 /* Set return status */ 219 Message->ReturnedStatus = STATUS_PENDING; 220 221 /* Set create process reported state */ 222 PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT); 223 224 /* Send the LPC command */ 225 Status = LpcRequestWaitReplyPort(Port, 226 (PPORT_MESSAGE)Message, 227 (PPORT_MESSAGE)&Buffer[0]); 228 229 /* Flush the instruction cache */ 230 ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); 231 232 /* Copy the buffer back */ 233 if (NT_SUCCESS(Status)) RtlCopyMemory(Message, Buffer, sizeof(DBGKM_MSG)); 234 235 /* Resume the process if it was suspended */ 236 if (Suspended) DbgkpResumeProcess(); 237 return Status; 238 } 239 240 NTSTATUS 241 NTAPI 242 DbgkpSendApiMessage(IN OUT PDBGKM_MSG ApiMsg, 243 IN BOOLEAN SuspendProcess) 244 { 245 NTSTATUS Status; 246 BOOLEAN Suspended = FALSE; 247 PAGED_CODE(); 248 DBGKTRACE(DBGK_MESSAGE_DEBUG, "ApiMsg: %p SuspendProcess: %lx\n", ApiMsg, SuspendProcess); 249 250 /* Suspend process if required */ 251 if (SuspendProcess) Suspended = DbgkpSuspendProcess(); 252 253 /* Set return status */ 254 ApiMsg->ReturnedStatus = STATUS_PENDING; 255 256 /* Set create process reported state */ 257 PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT); 258 259 /* Send the LPC command */ 260 Status = DbgkpQueueMessage(PsGetCurrentProcess(), 261 PsGetCurrentThread(), 262 ApiMsg, 263 0, 264 NULL); 265 266 /* Flush the instruction cache */ 267 ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); 268 269 /* Resume the process if it was suspended */ 270 if (Suspended) DbgkpResumeProcess(); 271 return Status; 272 } 273 274 VOID 275 NTAPI 276 DbgkCopyProcessDebugPort(IN PEPROCESS Process, 277 IN PEPROCESS Parent) 278 { 279 PDEBUG_OBJECT DebugObject; 280 PAGED_CODE(); 281 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Parent: %p\n", Process, Parent); 282 283 /* Clear this process's port */ 284 Process->DebugPort = NULL; 285 286 /* Check if the parent has one */ 287 if (!Parent->DebugPort) return; 288 289 /* It does, acquire the mutex */ 290 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 291 292 /* Make sure it still has one, and that we should inherit */ 293 DebugObject = Parent->DebugPort; 294 if ((DebugObject) && !(Process->NoDebugInherit)) 295 { 296 /* Acquire the debug object's lock */ 297 ExAcquireFastMutex(&DebugObject->Mutex); 298 299 /* Make sure the debugger is active */ 300 if (!DebugObject->DebuggerInactive) 301 { 302 /* Reference the object and set it */ 303 ObReferenceObject(DebugObject); 304 Process->DebugPort = DebugObject; 305 } 306 307 /* Release the debug object */ 308 ExReleaseFastMutex(&DebugObject->Mutex); 309 } 310 311 /* Release the port mutex */ 312 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 313 } 314 315 BOOLEAN 316 NTAPI 317 DbgkForwardException(IN PEXCEPTION_RECORD ExceptionRecord, 318 IN BOOLEAN DebugPort, 319 IN BOOLEAN SecondChance) 320 { 321 DBGKM_MSG ApiMessage; 322 PDBGKM_EXCEPTION DbgKmException = &ApiMessage.Exception; 323 NTSTATUS Status; 324 PEPROCESS Process = PsGetCurrentProcess(); 325 PVOID Port; 326 BOOLEAN UseLpc = FALSE; 327 PAGED_CODE(); 328 DBGKTRACE(DBGK_EXCEPTION_DEBUG, 329 "ExceptionRecord: %p Port: %u\n", ExceptionRecord, DebugPort); 330 331 /* Setup the API Message */ 332 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | 333 (8 + sizeof(DBGKM_EXCEPTION)); 334 ApiMessage.h.u2.ZeroInit = 0; 335 ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; 336 ApiMessage.ApiNumber = DbgKmExceptionApi; 337 338 /* Check if this is to be sent on the debug port */ 339 if (DebugPort) 340 { 341 /* Use the debug port, unless the thread is being hidden */ 342 Port = PsGetCurrentThread()->HideFromDebugger ? 343 NULL : Process->DebugPort; 344 } 345 else 346 { 347 /* Otherwise, use the exception port */ 348 Port = Process->ExceptionPort; 349 ApiMessage.h.u2.ZeroInit = 0; 350 ApiMessage.h.u2.s2.Type = LPC_EXCEPTION; 351 UseLpc = TRUE; 352 } 353 354 /* Break out if there's no port */ 355 if (!Port) return FALSE; 356 357 /* Fill out the exception information */ 358 DbgKmException->ExceptionRecord = *ExceptionRecord; 359 DbgKmException->FirstChance = !SecondChance; 360 361 /* Check if we should use LPC */ 362 if (UseLpc) 363 { 364 /* Send the message on the LPC Port */ 365 Status = DbgkpSendApiMessageLpc(&ApiMessage, Port, DebugPort); 366 } 367 else 368 { 369 /* Use native debug object */ 370 Status = DbgkpSendApiMessage(&ApiMessage, DebugPort); 371 } 372 373 /* Check if we failed, and for a debug port, also check the return status */ 374 if (!(NT_SUCCESS(Status)) || 375 ((DebugPort) && 376 (!(NT_SUCCESS(ApiMessage.ReturnedStatus)) || 377 (ApiMessage.ReturnedStatus == DBG_EXCEPTION_NOT_HANDLED)))) 378 { 379 /* Fail */ 380 return FALSE; 381 } 382 383 /* Otherwise, we're ok */ 384 return TRUE; 385 } 386 387 VOID 388 NTAPI 389 DbgkpFreeDebugEvent(IN PDEBUG_EVENT DebugEvent) 390 { 391 PHANDLE Handle = NULL; 392 PAGED_CODE(); 393 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 394 395 /* Check if this event had a file handle */ 396 switch (DebugEvent->ApiMsg.ApiNumber) 397 { 398 /* Create process has a handle */ 399 case DbgKmCreateProcessApi: 400 401 /* Get the pointer */ 402 Handle = &DebugEvent->ApiMsg.CreateProcess.FileHandle; 403 break; 404 405 /* As does DLL load */ 406 case DbgKmLoadDllApi: 407 408 /* Get the pointer */ 409 Handle = &DebugEvent->ApiMsg.LoadDll.FileHandle; 410 411 default: 412 break; 413 } 414 415 /* Close the handle if it exsts */ 416 if ((Handle) && (*Handle)) ObCloseHandle(*Handle, KernelMode); 417 418 /* Dereference process and thread and free the event */ 419 ObDereferenceObject(DebugEvent->Process); 420 ObDereferenceObject(DebugEvent->Thread); 421 ExFreePoolWithTag(DebugEvent, 'EgbD'); 422 } 423 424 VOID 425 NTAPI 426 DbgkpWakeTarget(IN PDEBUG_EVENT DebugEvent) 427 { 428 PETHREAD Thread = DebugEvent->Thread; 429 PAGED_CODE(); 430 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 431 432 /* Check if we have to wake the thread */ 433 if (DebugEvent->Flags & DEBUG_EVENT_SUSPEND) PsResumeThread(Thread, NULL); 434 435 /* Check if we had locked the thread */ 436 if (DebugEvent->Flags & DEBUG_EVENT_RELEASE) 437 { 438 /* Unlock it */ 439 ExReleaseRundownProtection(&Thread->RundownProtect); 440 } 441 442 /* Check if we have to wake up the event */ 443 if (DebugEvent->Flags & DEBUG_EVENT_NOWAIT) 444 { 445 /* Otherwise, free the debug event */ 446 DbgkpFreeDebugEvent(DebugEvent); 447 } 448 else 449 { 450 /* Signal the continue event */ 451 KeSetEvent(&DebugEvent->ContinueEvent, IO_NO_INCREMENT, FALSE); 452 } 453 } 454 455 NTSTATUS 456 NTAPI 457 DbgkpPostFakeModuleMessages(IN PEPROCESS Process, 458 IN PETHREAD Thread, 459 IN PDEBUG_OBJECT DebugObject) 460 { 461 PPEB Peb = Process->Peb; 462 PPEB_LDR_DATA LdrData; 463 PLDR_DATA_TABLE_ENTRY LdrEntry; 464 PLIST_ENTRY ListHead, NextEntry; 465 DBGKM_MSG ApiMessage; 466 PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll; 467 ULONG i; 468 PIMAGE_NT_HEADERS NtHeader; 469 UNICODE_STRING ModuleName; 470 OBJECT_ATTRIBUTES ObjectAttributes; 471 IO_STATUS_BLOCK IoStatusBlock; 472 NTSTATUS Status; 473 UNICODE_STRING FullDllName; 474 PAGED_CODE(); 475 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Thread: %p DebugObject: %p\n", 476 Process, Thread, DebugObject); 477 478 /* Quit if there's no PEB */ 479 if (!Peb) return STATUS_SUCCESS; 480 481 /* Accessing user memory, need SEH */ 482 _SEH2_TRY 483 { 484 /* Get the Loader Data List */ 485 ProbeForRead(Peb, sizeof(*Peb), 1); 486 LdrData = Peb->Ldr; 487 ProbeForRead(LdrData, sizeof(*LdrData), 1); 488 ListHead = &LdrData->InLoadOrderModuleList; 489 ProbeForRead(ListHead, sizeof(*ListHead), 1); 490 NextEntry = ListHead->Flink; 491 492 /* Loop the modules */ 493 i = 0; 494 while ((NextEntry != ListHead) && (i < 500)) 495 { 496 ProbeForRead(NextEntry, sizeof(*NextEntry), 1); 497 /* Skip the first entry */ 498 if (!i) 499 { 500 /* Go to the next module */ 501 NextEntry = NextEntry->Flink; 502 i++; 503 continue; 504 } 505 506 /* Get the entry */ 507 LdrEntry = CONTAINING_RECORD(NextEntry, 508 LDR_DATA_TABLE_ENTRY, 509 InLoadOrderLinks); 510 ProbeForRead(LdrEntry, sizeof(*LdrEntry), 1); 511 512 /* Setup the API Message */ 513 RtlZeroMemory(&ApiMessage, sizeof(DBGKM_MSG)); 514 ApiMessage.ApiNumber = DbgKmLoadDllApi; 515 516 /* Set base and clear the name */ 517 LoadDll->BaseOfDll = LdrEntry->DllBase; 518 LoadDll->NamePointer = NULL; 519 520 /* Get the NT Headers */ 521 NtHeader = RtlImageNtHeader(LoadDll->BaseOfDll); 522 if (NtHeader) 523 { 524 /* Save debug data */ 525 LoadDll->DebugInfoFileOffset = NtHeader->FileHeader. 526 PointerToSymbolTable; 527 LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols; 528 } 529 530 /* Trace */ 531 FullDllName = LdrEntry->FullDllName; 532 ProbeForRead(FullDllName.Buffer, FullDllName.MaximumLength, 1); 533 DBGKTRACE(DBGK_PROCESS_DEBUG, "Name: %wZ. Base: %p\n", 534 &FullDllName, LdrEntry->DllBase); 535 536 /* Get the name of the DLL */ 537 Status = MmGetFileNameForAddress(NtHeader, &ModuleName); 538 if (NT_SUCCESS(Status)) 539 { 540 /* Setup the object attributes */ 541 InitializeObjectAttributes(&ObjectAttributes, 542 &ModuleName, 543 OBJ_FORCE_ACCESS_CHECK | 544 OBJ_KERNEL_HANDLE | 545 OBJ_CASE_INSENSITIVE, 546 NULL, 547 NULL); 548 549 /* Open the file to get a handle to it */ 550 Status = ZwOpenFile(&LoadDll->FileHandle, 551 GENERIC_READ | SYNCHRONIZE, 552 &ObjectAttributes, 553 &IoStatusBlock, 554 FILE_SHARE_READ | 555 FILE_SHARE_WRITE | 556 FILE_SHARE_DELETE, 557 FILE_SYNCHRONOUS_IO_NONALERT); 558 if (!NT_SUCCESS(Status)) LoadDll->FileHandle = NULL; 559 560 /* Free the name now */ 561 ExFreePool(ModuleName.Buffer); 562 } 563 564 /* Send the fake module load message */ 565 Status = DbgkpQueueMessage(Process, 566 Thread, 567 &ApiMessage, 568 DEBUG_EVENT_NOWAIT, 569 DebugObject); 570 if (!NT_SUCCESS(Status)) 571 { 572 /* Message send failed, close the file handle if we had one */ 573 if (LoadDll->FileHandle) ObCloseHandle(LoadDll->FileHandle, 574 KernelMode); 575 } 576 577 /* Go to the next module */ 578 NextEntry = NextEntry->Flink; 579 i++; 580 } 581 } 582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 583 { 584 NOTHING; 585 } 586 _SEH2_END; 587 588 /* Return success */ 589 return STATUS_SUCCESS; 590 } 591 592 NTSTATUS 593 NTAPI 594 DbgkpPostFakeThreadMessages(IN PEPROCESS Process, 595 IN PDEBUG_OBJECT DebugObject, 596 IN PETHREAD StartThread, 597 OUT PETHREAD *FirstThread, 598 OUT PETHREAD *LastThread) 599 { 600 PETHREAD pFirstThread = NULL, ThisThread, OldThread = NULL, pLastThread; 601 NTSTATUS Status = STATUS_UNSUCCESSFUL; 602 BOOLEAN IsFirstThread; 603 ULONG Flags; 604 DBGKM_MSG ApiMessage; 605 PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread; 606 PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess; 607 BOOLEAN First; 608 PIMAGE_NT_HEADERS NtHeader; 609 PAGED_CODE(); 610 DBGKTRACE(DBGK_THREAD_DEBUG, "Process: %p StartThread: %p Object: %p\n", 611 Process, StartThread, DebugObject); 612 613 /* Check if we have a start thread */ 614 if (StartThread) 615 { 616 /* Then the one we'll find won't be the first one */ 617 IsFirstThread = FALSE; 618 pFirstThread = StartThread; 619 ThisThread = StartThread; 620 621 /* Reference it */ 622 ObReferenceObject(StartThread); 623 } 624 else 625 { 626 /* Get the first thread ourselves */ 627 ThisThread = PsGetNextProcessThread(Process, NULL); 628 IsFirstThread = TRUE; 629 } 630 631 /* Start thread loop */ 632 do 633 { 634 /* Dereference the previous thread if we had one */ 635 if (OldThread) ObDereferenceObject(OldThread); 636 637 /* Set this as the last thread and lock it */ 638 pLastThread = ThisThread; 639 ObReferenceObject(ThisThread); 640 if (ExAcquireRundownProtection(&ThisThread->RundownProtect)) 641 { 642 /* Acquire worked, set flags */ 643 Flags = DEBUG_EVENT_RELEASE | DEBUG_EVENT_NOWAIT; 644 645 /* Check if this is a user thread */ 646 if (!ThisThread->SystemThread) 647 { 648 /* Suspend it */ 649 if (NT_SUCCESS(PsSuspendThread(ThisThread, NULL))) 650 { 651 /* Remember this */ 652 Flags |= DEBUG_EVENT_SUSPEND; 653 } 654 } 655 } 656 else 657 { 658 /* Couldn't acquire rundown */ 659 Flags = DEBUG_EVENT_PROTECT_FAILED | DEBUG_EVENT_NOWAIT; 660 } 661 662 /* Clear the API Message */ 663 RtlZeroMemory(&ApiMessage, sizeof(ApiMessage)); 664 665 /* Check if this is the first thread */ 666 if ((IsFirstThread) && 667 !(Flags & DEBUG_EVENT_PROTECT_FAILED) && 668 !(ThisThread->SystemThread) && 669 (ThisThread->GrantedAccess)) 670 { 671 /* It is, save the flag */ 672 First = TRUE; 673 } 674 else 675 { 676 /* It isn't, save the flag */ 677 First = FALSE; 678 } 679 680 /* Check if this is the first */ 681 if (First) 682 { 683 /* So we'll start with the create process message */ 684 ApiMessage.ApiNumber = DbgKmCreateProcessApi; 685 686 /* Get the file handle */ 687 if (Process->SectionObject) 688 { 689 /* Use the section object */ 690 CreateProcess->FileHandle = 691 DbgkpSectionToFileHandle(Process->SectionObject); 692 } 693 else 694 { 695 /* Don't return any handle */ 696 CreateProcess->FileHandle = NULL; 697 } 698 699 /* Set the base address */ 700 CreateProcess->BaseOfImage = Process->SectionBaseAddress; 701 702 /* Get the NT Header */ 703 NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); 704 if (NtHeader) 705 { 706 /* Fill out data from the header */ 707 CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader. 708 PointerToSymbolTable; 709 CreateProcess->DebugInfoSize = NtHeader->FileHeader. 710 NumberOfSymbols; 711 } 712 } 713 else 714 { 715 /* Otherwise it's a thread message */ 716 ApiMessage.ApiNumber = DbgKmCreateThreadApi; 717 CreateThread->StartAddress = ThisThread->StartAddress; 718 } 719 720 /* Trace */ 721 DBGKTRACE(DBGK_THREAD_DEBUG, "Thread: %p. First: %lx, OldThread: %p\n", 722 ThisThread, First, OldThread); 723 DBGKTRACE(DBGK_THREAD_DEBUG, "Start Address: %p\n", 724 ThisThread->StartAddress); 725 726 /* Queue the message */ 727 Status = DbgkpQueueMessage(Process, 728 ThisThread, 729 &ApiMessage, 730 Flags, 731 DebugObject); 732 if (!NT_SUCCESS(Status)) 733 { 734 /* Resume the thread if it was suspended */ 735 if (Flags & DEBUG_EVENT_SUSPEND) PsResumeThread(ThisThread, NULL); 736 737 /* Check if we acquired rundown */ 738 if (Flags & DEBUG_EVENT_RELEASE) 739 { 740 /* Release it */ 741 ExReleaseRundownProtection(&ThisThread->RundownProtect); 742 } 743 744 /* If this was a process create, check if we got a handle */ 745 if ((ApiMessage.ApiNumber == DbgKmCreateProcessApi) && 746 (CreateProcess->FileHandle)) 747 { 748 /* Close it */ 749 ObCloseHandle(CreateProcess->FileHandle, KernelMode); 750 } 751 752 /* Release our reference and break out */ 753 ObDereferenceObject(ThisThread); 754 break; 755 } 756 757 /* Check if this was the first message */ 758 if (First) 759 { 760 /* It isn't the first thread anymore */ 761 IsFirstThread = FALSE; 762 763 /* Reference this thread and set it as first */ 764 ObReferenceObject(ThisThread); 765 pFirstThread = ThisThread; 766 } 767 768 /* Get the next thread */ 769 ThisThread = PsGetNextProcessThread(Process, ThisThread); 770 OldThread = pLastThread; 771 } while (ThisThread); 772 773 /* Check the API status */ 774 if (!NT_SUCCESS(Status)) 775 { 776 /* Dereference and fail */ 777 if (pFirstThread) ObDereferenceObject(pFirstThread); 778 if (pLastThread) ObDereferenceObject(pLastThread); 779 return Status; 780 } 781 782 /* Make sure we have a first thread */ 783 if (!pFirstThread) return STATUS_UNSUCCESSFUL; 784 785 /* Return thread pointers */ 786 *FirstThread = pFirstThread; 787 *LastThread = pLastThread; 788 return Status; 789 } 790 791 NTSTATUS 792 NTAPI 793 DbgkpPostFakeProcessCreateMessages(IN PEPROCESS Process, 794 IN PDEBUG_OBJECT DebugObject, 795 OUT PETHREAD *LastThread) 796 { 797 KAPC_STATE ApcState; 798 PETHREAD FirstThread, FinalThread; 799 PETHREAD ReturnThread = NULL; 800 NTSTATUS Status; 801 PAGED_CODE(); 802 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p DebugObject: %p\n", 803 Process, DebugObject); 804 805 /* Attach to the process */ 806 KeStackAttachProcess(&Process->Pcb, &ApcState); 807 808 /* Post the fake thread messages */ 809 Status = DbgkpPostFakeThreadMessages(Process, 810 DebugObject, 811 NULL, 812 &FirstThread, 813 &FinalThread); 814 if (NT_SUCCESS(Status)) 815 { 816 /* Send the fake module messages too */ 817 Status = DbgkpPostFakeModuleMessages(Process, 818 FirstThread, 819 DebugObject); 820 if (!NT_SUCCESS(Status)) 821 { 822 /* We failed, dereference the final thread */ 823 ObDereferenceObject(FinalThread); 824 } 825 else 826 { 827 /* Set the final thread */ 828 ReturnThread = FinalThread; 829 } 830 831 /* Dereference the first thread */ 832 ObDereferenceObject(FirstThread); 833 } 834 835 /* Detach from the process */ 836 KeUnstackDetachProcess(&ApcState); 837 838 /* Return the last thread */ 839 *LastThread = ReturnThread; 840 return Status; 841 } 842 843 VOID 844 NTAPI 845 DbgkpConvertKernelToUserStateChange(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 846 IN PDEBUG_EVENT DebugEvent) 847 { 848 DBGKTRACE(DBGK_OBJECT_DEBUG, "DebugEvent: %p\n", DebugEvent); 849 850 /* Start by copying the client ID */ 851 WaitStateChange->AppClientId = DebugEvent->ClientId; 852 853 /* Now check which kind of event this was */ 854 switch (DebugEvent->ApiMsg.ApiNumber) 855 { 856 /* New process */ 857 case DbgKmCreateProcessApi: 858 859 /* Set the right native code */ 860 WaitStateChange->NewState = DbgCreateProcessStateChange; 861 862 /* Copy the information */ 863 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess = 864 DebugEvent->ApiMsg.CreateProcess; 865 866 /* Clear the file handle for us */ 867 DebugEvent->ApiMsg.CreateProcess.FileHandle = NULL; 868 break; 869 870 /* New thread */ 871 case DbgKmCreateThreadApi: 872 873 /* Set the right native code */ 874 WaitStateChange->NewState = DbgCreateThreadStateChange; 875 876 /* Copy information */ 877 WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress = 878 DebugEvent->ApiMsg.CreateThread.StartAddress; 879 WaitStateChange->StateInfo.CreateThread.NewThread.SubSystemKey = 880 DebugEvent->ApiMsg.CreateThread.SubSystemKey; 881 break; 882 883 /* Exception (or breakpoint/step) */ 884 case DbgKmExceptionApi: 885 886 /* Look at the exception code */ 887 if ((NTSTATUS)DebugEvent->ApiMsg.Exception.ExceptionRecord.ExceptionCode == 888 STATUS_BREAKPOINT) 889 { 890 /* Update this as a breakpoint exception */ 891 WaitStateChange->NewState = DbgBreakpointStateChange; 892 } 893 else if ((NTSTATUS)DebugEvent->ApiMsg.Exception.ExceptionRecord.ExceptionCode == 894 STATUS_SINGLE_STEP) 895 { 896 /* Update this as a single step exception */ 897 WaitStateChange->NewState = DbgSingleStepStateChange; 898 } 899 else 900 { 901 /* Otherwise, set default exception */ 902 WaitStateChange->NewState = DbgExceptionStateChange; 903 } 904 905 /* Copy the exception record */ 906 WaitStateChange->StateInfo.Exception.ExceptionRecord = 907 DebugEvent->ApiMsg.Exception.ExceptionRecord; 908 /* Copy FirstChance flag */ 909 WaitStateChange->StateInfo.Exception.FirstChance = 910 DebugEvent->ApiMsg.Exception.FirstChance; 911 break; 912 913 /* Process exited */ 914 case DbgKmExitProcessApi: 915 916 /* Set the right native code and copy the exit code */ 917 WaitStateChange->NewState = DbgExitProcessStateChange; 918 WaitStateChange->StateInfo.ExitProcess.ExitStatus = 919 DebugEvent->ApiMsg.ExitProcess.ExitStatus; 920 break; 921 922 /* Thread exited */ 923 case DbgKmExitThreadApi: 924 925 /* Set the right native code */ 926 WaitStateChange->NewState = DbgExitThreadStateChange; 927 WaitStateChange->StateInfo.ExitThread.ExitStatus = 928 DebugEvent->ApiMsg.ExitThread.ExitStatus; 929 break; 930 931 /* DLL Load */ 932 case DbgKmLoadDllApi: 933 934 /* Set the native code */ 935 WaitStateChange->NewState = DbgLoadDllStateChange; 936 937 /* Copy the data */ 938 WaitStateChange->StateInfo.LoadDll = DebugEvent->ApiMsg.LoadDll; 939 940 /* Clear the file handle for us */ 941 DebugEvent->ApiMsg.LoadDll.FileHandle = NULL; 942 break; 943 944 /* DLL Unload */ 945 case DbgKmUnloadDllApi: 946 947 /* Set the native code and copy the address */ 948 WaitStateChange->NewState = DbgUnloadDllStateChange; 949 WaitStateChange->StateInfo.UnloadDll.BaseAddress = 950 DebugEvent->ApiMsg.UnloadDll.BaseAddress; 951 break; 952 953 default: 954 955 /* Shouldn't happen */ 956 ASSERT(FALSE); 957 } 958 } 959 960 VOID 961 NTAPI 962 DbgkpMarkProcessPeb(IN PEPROCESS Process) 963 { 964 KAPC_STATE ApcState; 965 PAGED_CODE(); 966 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p\n", Process); 967 968 /* Acquire process rundown */ 969 if (!ExAcquireRundownProtection(&Process->RundownProtect)) return; 970 971 /* Make sure we have a PEB */ 972 if (Process->Peb) 973 { 974 /* Attach to the process */ 975 KeStackAttachProcess(&Process->Pcb, &ApcState); 976 977 /* Acquire the debug port mutex */ 978 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 979 980 /* Set the IsBeingDebugged member of the PEB */ 981 Process->Peb->BeingDebugged = (Process->DebugPort) ? TRUE: FALSE; 982 983 /* Release lock */ 984 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 985 986 /* Detach from the process */ 987 KeUnstackDetachProcess(&ApcState); 988 } 989 990 /* Release rundown protection */ 991 ExReleaseRundownProtection(&Process->RundownProtect); 992 } 993 994 VOID 995 NTAPI 996 DbgkpOpenHandles(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 997 IN PEPROCESS Process, 998 IN PETHREAD Thread) 999 { 1000 NTSTATUS Status; 1001 HANDLE Handle; 1002 PHANDLE DupHandle; 1003 PAGED_CODE(); 1004 DBGKTRACE(DBGK_OBJECT_DEBUG, "Process: %p Thread: %p State: %lx\n", 1005 Process, Thread, WaitStateChange->NewState); 1006 1007 /* Check which state this is */ 1008 switch (WaitStateChange->NewState) 1009 { 1010 /* New thread */ 1011 case DbgCreateThreadStateChange: 1012 1013 /* Get handle to thread */ 1014 Status = ObOpenObjectByPointer(Thread, 1015 0, 1016 NULL, 1017 THREAD_ALL_ACCESS, 1018 PsThreadType, 1019 KernelMode, 1020 &Handle); 1021 if (NT_SUCCESS(Status)) 1022 { 1023 /* Save the thread handle */ 1024 WaitStateChange-> 1025 StateInfo.CreateThread.HandleToThread = Handle; 1026 } 1027 return; 1028 1029 /* New process */ 1030 case DbgCreateProcessStateChange: 1031 1032 /* Get handle to thread */ 1033 Status = ObOpenObjectByPointer(Thread, 1034 0, 1035 NULL, 1036 THREAD_ALL_ACCESS, 1037 PsThreadType, 1038 KernelMode, 1039 &Handle); 1040 if (NT_SUCCESS(Status)) 1041 { 1042 /* Save the thread handle */ 1043 WaitStateChange-> 1044 StateInfo.CreateProcessInfo.HandleToThread = Handle; 1045 } 1046 1047 /* Get handle to process */ 1048 Status = ObOpenObjectByPointer(Process, 1049 0, 1050 NULL, 1051 PROCESS_ALL_ACCESS, 1052 PsProcessType, 1053 KernelMode, 1054 &Handle); 1055 if (NT_SUCCESS(Status)) 1056 { 1057 /* Save the process handle */ 1058 WaitStateChange-> 1059 StateInfo.CreateProcessInfo.HandleToProcess = Handle; 1060 } 1061 1062 /* Fall through to duplicate file handle */ 1063 DupHandle = &WaitStateChange-> 1064 StateInfo.CreateProcessInfo.NewProcess.FileHandle; 1065 break; 1066 1067 /* DLL Load */ 1068 case DbgLoadDllStateChange: 1069 1070 /* Fall through to duplicate file handle */ 1071 DupHandle = &WaitStateChange->StateInfo.LoadDll.FileHandle; 1072 break; 1073 1074 /* Anything else has no handles */ 1075 default: 1076 return; 1077 } 1078 1079 /* If we got here, then we have to duplicate a handle, possibly */ 1080 Handle = *DupHandle; 1081 if (Handle) 1082 { 1083 /* Duplicate it */ 1084 Status = ObDuplicateObject(PsGetCurrentProcess(), 1085 Handle, 1086 PsGetCurrentProcess(), 1087 DupHandle, 1088 0, 1089 0, 1090 DUPLICATE_SAME_ACCESS, 1091 KernelMode); 1092 if (!NT_SUCCESS(Status)) *DupHandle = NULL; 1093 1094 /* Close the original handle */ 1095 ObCloseHandle(Handle, KernelMode); 1096 } 1097 } 1098 1099 VOID 1100 NTAPI 1101 DbgkpDeleteObject(IN PVOID DebugObject) 1102 { 1103 PAGED_CODE(); 1104 1105 /* Sanity check */ 1106 ASSERT(IsListEmpty(&((PDEBUG_OBJECT)DebugObject)->EventList)); 1107 } 1108 1109 VOID 1110 NTAPI 1111 DbgkpCloseObject(IN PEPROCESS OwnerProcess OPTIONAL, 1112 IN PVOID ObjectBody, 1113 IN ACCESS_MASK GrantedAccess, 1114 IN ULONG HandleCount, 1115 IN ULONG SystemHandleCount) 1116 { 1117 PDEBUG_OBJECT DebugObject = ObjectBody; 1118 PEPROCESS Process = NULL; 1119 BOOLEAN DebugPortCleared = FALSE; 1120 PLIST_ENTRY DebugEventList; 1121 PDEBUG_EVENT DebugEvent; 1122 PAGED_CODE(); 1123 DBGKTRACE(DBGK_OBJECT_DEBUG, "OwnerProcess: %p DebugObject: %p\n", 1124 OwnerProcess, DebugObject); 1125 1126 /* If this isn't the last handle, do nothing */ 1127 if (SystemHandleCount > 1) return; 1128 1129 /* Otherwise, lock the debug object */ 1130 ExAcquireFastMutex(&DebugObject->Mutex); 1131 1132 /* Set it as inactive */ 1133 DebugObject->DebuggerInactive = TRUE; 1134 1135 /* Remove it from the debug event list */ 1136 DebugEventList = DebugObject->EventList.Flink; 1137 InitializeListHead(&DebugObject->EventList); 1138 1139 /* Release the lock */ 1140 ExReleaseFastMutex(&DebugObject->Mutex); 1141 1142 /* Signal the wait event */ 1143 KeSetEvent(&DebugObject->EventsPresent, IO_NO_INCREMENT, FALSE); 1144 1145 /* Start looping each process */ 1146 while ((Process = PsGetNextProcess(Process))) 1147 { 1148 /* Check if the process has us as their debug port */ 1149 if (Process->DebugPort == DebugObject) 1150 { 1151 /* Acquire the process debug port lock */ 1152 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 1153 1154 /* Check if it's still us */ 1155 if (Process->DebugPort == DebugObject) 1156 { 1157 /* Clear it and remember */ 1158 Process->DebugPort = NULL; 1159 DebugPortCleared = TRUE; 1160 } 1161 1162 /* Release the port lock */ 1163 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1164 1165 /* Check if we cleared the debug port */ 1166 if (DebugPortCleared) 1167 { 1168 /* Mark this in the PEB */ 1169 DbgkpMarkProcessPeb(Process); 1170 1171 /* Check if we terminate on exit */ 1172 if (DebugObject->KillProcessOnExit) 1173 { 1174 /* Terminate the process */ 1175 PsTerminateProcess(Process, STATUS_DEBUGGER_INACTIVE); 1176 } 1177 1178 /* Dereference the debug object */ 1179 ObDereferenceObject(DebugObject); 1180 } 1181 } 1182 } 1183 1184 /* Loop debug events */ 1185 while (DebugEventList != &DebugObject->EventList) 1186 { 1187 /* Get the debug event */ 1188 DebugEvent = CONTAINING_RECORD(DebugEventList, DEBUG_EVENT, EventList); 1189 1190 /* Go to the next entry */ 1191 DebugEventList = DebugEventList->Flink; 1192 1193 /* Wake it up */ 1194 DebugEvent->Status = STATUS_DEBUGGER_INACTIVE; 1195 DbgkpWakeTarget(DebugEvent); 1196 } 1197 } 1198 1199 NTSTATUS 1200 NTAPI 1201 DbgkpSetProcessDebugObject(IN PEPROCESS Process, 1202 IN PDEBUG_OBJECT DebugObject, 1203 IN NTSTATUS MsgStatus, 1204 IN PETHREAD LastThread) 1205 { 1206 NTSTATUS Status; 1207 LIST_ENTRY TempList; 1208 BOOLEAN GlobalHeld = FALSE, DoSetEvent = TRUE; 1209 PETHREAD ThisThread, FirstThread; 1210 PLIST_ENTRY NextEntry; 1211 PDEBUG_EVENT DebugEvent; 1212 PETHREAD EventThread; 1213 PAGED_CODE(); 1214 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p DebugObject: %p\n", 1215 Process, DebugObject); 1216 1217 /* Initialize the temporary list */ 1218 InitializeListHead(&TempList); 1219 1220 /* Check if we have a success message */ 1221 if (NT_SUCCESS(MsgStatus)) 1222 { 1223 /* Then default to STATUS_SUCCESS */ 1224 Status = STATUS_SUCCESS; 1225 } 1226 else 1227 { 1228 /* No last thread, and set the failure code */ 1229 LastThread = NULL; 1230 Status = MsgStatus; 1231 } 1232 1233 /* Now check what status we have here */ 1234 if (NT_SUCCESS(Status)) 1235 { 1236 /* Acquire the global lock */ 1237 ThreadScan: 1238 GlobalHeld = TRUE; 1239 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 1240 1241 /* Check if we already have a port */ 1242 if (Process->DebugPort) 1243 { 1244 /* Set failure */ 1245 Status = STATUS_PORT_ALREADY_SET; 1246 } 1247 else 1248 { 1249 /* Otherwise, set the port and reference the thread */ 1250 Process->DebugPort = DebugObject; 1251 ObReferenceObject(LastThread); 1252 1253 /* Get the next thread */ 1254 ThisThread = PsGetNextProcessThread(Process, LastThread); 1255 if (ThisThread) 1256 { 1257 /* Clear the debug port and release the lock */ 1258 Process->DebugPort = NULL; 1259 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1260 GlobalHeld = FALSE; 1261 1262 /* Dereference the thread */ 1263 ObDereferenceObject(LastThread); 1264 1265 /* Post fake messages */ 1266 Status = DbgkpPostFakeThreadMessages(Process, 1267 DebugObject, 1268 ThisThread, 1269 &FirstThread, 1270 &LastThread); 1271 if (!NT_SUCCESS(Status)) 1272 { 1273 /* Clear the last thread */ 1274 LastThread = NULL; 1275 } 1276 else 1277 { 1278 /* Dereference the first thread and re-acquire the lock */ 1279 ObDereferenceObject(FirstThread); 1280 goto ThreadScan; 1281 } 1282 } 1283 } 1284 } 1285 1286 /* Acquire the debug object's lock */ 1287 ExAcquireFastMutex(&DebugObject->Mutex); 1288 1289 /* Check our status here */ 1290 if (NT_SUCCESS(Status)) 1291 { 1292 /* Check if we're disconnected */ 1293 if (DebugObject->DebuggerInactive) 1294 { 1295 /* Set status */ 1296 Process->DebugPort = NULL; 1297 Status = STATUS_DEBUGGER_INACTIVE; 1298 } 1299 else 1300 { 1301 /* Set the process flags */ 1302 PspSetProcessFlag(Process, 1303 PSF_NO_DEBUG_INHERIT_BIT | 1304 PSF_CREATE_REPORTED_BIT); 1305 1306 /* Reference the debug object */ 1307 ObReferenceObject(DebugObject); 1308 } 1309 } 1310 1311 /* Loop the events list */ 1312 NextEntry = DebugObject->EventList.Flink; 1313 while (NextEntry != &DebugObject->EventList) 1314 { 1315 /* Get the debug event and go to the next entry */ 1316 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 1317 NextEntry = NextEntry->Flink; 1318 DBGKTRACE(DBGK_PROCESS_DEBUG, "DebugEvent: %p Flags: %lx TH: %p/%p\n", 1319 DebugEvent, DebugEvent->Flags, 1320 DebugEvent->BackoutThread, PsGetCurrentThread()); 1321 1322 /* Check for if the debug event queue needs flushing */ 1323 if ((DebugEvent->Flags & DEBUG_EVENT_INACTIVE) && 1324 (DebugEvent->BackoutThread == PsGetCurrentThread())) 1325 { 1326 /* Get the event's thread */ 1327 EventThread = DebugEvent->Thread; 1328 DBGKTRACE(DBGK_PROCESS_DEBUG, "EventThread: %p MsgStatus: %lx\n", 1329 EventThread, MsgStatus); 1330 1331 /* Check if the status is success */ 1332 if ((MsgStatus == STATUS_SUCCESS) && 1333 (EventThread->GrantedAccess) && 1334 (!EventThread->SystemThread)) 1335 { 1336 /* Check if we couldn't acquire rundown for it */ 1337 if (DebugEvent->Flags & DEBUG_EVENT_PROTECT_FAILED) 1338 { 1339 /* Set the skip termination flag */ 1340 PspSetCrossThreadFlag(EventThread, CT_SKIP_CREATION_MSG_BIT); 1341 1342 /* Insert it into the temp list */ 1343 RemoveEntryList(&DebugEvent->EventList); 1344 InsertTailList(&TempList, &DebugEvent->EventList); 1345 } 1346 else 1347 { 1348 /* Do we need to signal the event */ 1349 if (DoSetEvent) 1350 { 1351 /* Do it */ 1352 DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE; 1353 KeSetEvent(&DebugObject->EventsPresent, 1354 IO_NO_INCREMENT, 1355 FALSE); 1356 DoSetEvent = FALSE; 1357 } 1358 1359 /* Clear the backout thread */ 1360 DebugEvent->BackoutThread = NULL; 1361 1362 /* Set skip flag */ 1363 PspSetCrossThreadFlag(EventThread, CT_SKIP_CREATION_MSG_BIT); 1364 } 1365 } 1366 else 1367 { 1368 /* Insert it into the temp list */ 1369 RemoveEntryList(&DebugEvent->EventList); 1370 InsertTailList(&TempList, &DebugEvent->EventList); 1371 } 1372 1373 /* Check if the lock is held */ 1374 if (DebugEvent->Flags & DEBUG_EVENT_RELEASE) 1375 { 1376 /* Release it */ 1377 DebugEvent->Flags &= ~DEBUG_EVENT_RELEASE; 1378 ExReleaseRundownProtection(&EventThread->RundownProtect); 1379 } 1380 } 1381 } 1382 1383 /* Release the debug object */ 1384 ExReleaseFastMutex(&DebugObject->Mutex); 1385 1386 /* Release the global lock if acquired */ 1387 if (GlobalHeld) ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1388 1389 /* Check if there's a thread to dereference */ 1390 if (LastThread) ObDereferenceObject(LastThread); 1391 1392 /* Loop our temporary list */ 1393 while (!IsListEmpty(&TempList)) 1394 { 1395 /* Remove the event */ 1396 NextEntry = RemoveHeadList(&TempList); 1397 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 1398 1399 /* Wake it */ 1400 DbgkpWakeTarget(DebugEvent); 1401 } 1402 1403 /* Check if we got here through success and mark the PEB, then return */ 1404 if (NT_SUCCESS(Status)) DbgkpMarkProcessPeb(Process); 1405 return Status; 1406 } 1407 1408 NTSTATUS 1409 NTAPI 1410 DbgkClearProcessDebugObject(IN PEPROCESS Process, 1411 IN PDEBUG_OBJECT SourceDebugObject OPTIONAL) 1412 { 1413 PDEBUG_OBJECT DebugObject; 1414 PDEBUG_EVENT DebugEvent; 1415 LIST_ENTRY TempList; 1416 PLIST_ENTRY NextEntry; 1417 PAGED_CODE(); 1418 DBGKTRACE(DBGK_OBJECT_DEBUG, "Process: %p DebugObject: %p\n", 1419 Process, SourceDebugObject); 1420 1421 /* Acquire the port lock */ 1422 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 1423 1424 /* Get the Process Debug Object */ 1425 DebugObject = Process->DebugPort; 1426 1427 /* 1428 * Check if the process had an object and it matches, 1429 * or if the process had an object but none was specified 1430 * (in which we are called from NtTerminateProcess) 1431 */ 1432 if ((DebugObject) && 1433 ((DebugObject == SourceDebugObject) || 1434 (SourceDebugObject == NULL))) 1435 { 1436 /* Clear the debug port */ 1437 Process->DebugPort = NULL; 1438 1439 /* Release the port lock and remove the PEB flag */ 1440 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1441 DbgkpMarkProcessPeb(Process); 1442 } 1443 else 1444 { 1445 /* Release the port lock and fail */ 1446 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1447 return STATUS_PORT_NOT_SET; 1448 } 1449 1450 /* Initialize the temporary list */ 1451 InitializeListHead(&TempList); 1452 1453 /* Acquire the Object */ 1454 ExAcquireFastMutex(&DebugObject->Mutex); 1455 1456 /* Loop the events */ 1457 NextEntry = DebugObject->EventList.Flink; 1458 while (NextEntry != &DebugObject->EventList) 1459 { 1460 /* Get the Event and go to the next entry */ 1461 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 1462 NextEntry = NextEntry->Flink; 1463 1464 /* Check that it belongs to the specified process */ 1465 if (DebugEvent->Process == Process) 1466 { 1467 /* Insert it into the temporary list */ 1468 RemoveEntryList(&DebugEvent->EventList); 1469 InsertTailList(&TempList, &DebugEvent->EventList); 1470 } 1471 } 1472 1473 /* Release the Object */ 1474 ExReleaseFastMutex(&DebugObject->Mutex); 1475 1476 /* Release the initial reference */ 1477 ObDereferenceObject(DebugObject); 1478 1479 /* Loop our temporary list */ 1480 while (!IsListEmpty(&TempList)) 1481 { 1482 /* Remove the event */ 1483 NextEntry = RemoveHeadList(&TempList); 1484 DebugEvent = CONTAINING_RECORD(NextEntry, DEBUG_EVENT, EventList); 1485 1486 /* Wake it up */ 1487 DebugEvent->Status = STATUS_DEBUGGER_INACTIVE; 1488 DbgkpWakeTarget(DebugEvent); 1489 } 1490 1491 /* Return Success */ 1492 return STATUS_SUCCESS; 1493 } 1494 1495 VOID 1496 INIT_FUNCTION 1497 NTAPI 1498 DbgkInitialize(VOID) 1499 { 1500 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 1501 UNICODE_STRING Name; 1502 PAGED_CODE(); 1503 1504 /* Initialize the process debug port mutex */ 1505 ExInitializeFastMutex(&DbgkpProcessDebugPortMutex); 1506 1507 /* Create the Debug Object Type */ 1508 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 1509 RtlInitUnicodeString(&Name, L"DebugObject"); 1510 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 1511 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DEBUG_OBJECT); 1512 ObjectTypeInitializer.GenericMapping = DbgkDebugObjectMapping; 1513 ObjectTypeInitializer.PoolType = NonPagedPool; 1514 ObjectTypeInitializer.ValidAccessMask = DEBUG_OBJECT_ALL_ACCESS; 1515 ObjectTypeInitializer.SecurityRequired = TRUE; 1516 ObjectTypeInitializer.CloseProcedure = DbgkpCloseObject; 1517 ObjectTypeInitializer.DeleteProcedure = DbgkpDeleteObject; 1518 ObCreateObjectType(&Name, 1519 &ObjectTypeInitializer, 1520 NULL, 1521 &DbgkDebugObjectType); 1522 } 1523 1524 NTSTATUS 1525 NTAPI 1526 DbgkOpenProcessDebugPort(IN PEPROCESS Process, 1527 IN KPROCESSOR_MODE PreviousMode, 1528 OUT HANDLE *DebugHandle) 1529 { 1530 PDEBUG_OBJECT DebugObject; 1531 NTSTATUS Status; 1532 PAGED_CODE(); 1533 1534 /* If there's no debug port, just exit */ 1535 if (!Process->DebugPort) return STATUS_PORT_NOT_SET; 1536 1537 /* Otherwise, acquire the lock while we grab the port */ 1538 ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); 1539 1540 /* Grab it and reference it if it exists */ 1541 DebugObject = Process->DebugPort; 1542 if (DebugObject) ObReferenceObject(DebugObject); 1543 1544 /* Release the lock now */ 1545 ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); 1546 1547 /* Bail out if it doesn't exist */ 1548 if (!DebugObject) return STATUS_PORT_NOT_SET; 1549 1550 /* Now get a handle to it */ 1551 Status = ObOpenObjectByPointer(DebugObject, 1552 0, 1553 NULL, 1554 MAXIMUM_ALLOWED, 1555 DbgkDebugObjectType, 1556 PreviousMode, 1557 DebugHandle); 1558 if (!NT_SUCCESS(Status)) ObDereferenceObject(DebugObject); 1559 1560 /* Return status */ 1561 return Status; 1562 } 1563 1564 /* PUBLIC FUNCTIONS **********************************************************/ 1565 1566 /* 1567 * @implemented 1568 */ 1569 NTSTATUS 1570 NTAPI 1571 NtCreateDebugObject(OUT PHANDLE DebugHandle, 1572 IN ACCESS_MASK DesiredAccess, 1573 IN POBJECT_ATTRIBUTES ObjectAttributes, 1574 IN ULONG Flags) 1575 { 1576 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1577 PDEBUG_OBJECT DebugObject; 1578 HANDLE hDebug; 1579 NTSTATUS Status; 1580 PAGED_CODE(); 1581 1582 /* Check if we were called from user mode*/ 1583 if (PreviousMode != KernelMode) 1584 { 1585 /* Enter SEH for probing */ 1586 _SEH2_TRY 1587 { 1588 /* Probe the handle */ 1589 ProbeForWriteHandle(DebugHandle); 1590 } 1591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1592 { 1593 /* Return the exception code */ 1594 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1595 } _SEH2_END; 1596 } 1597 1598 /* Check for invalid flags */ 1599 if (Flags & ~DBGK_ALL_FLAGS) return STATUS_INVALID_PARAMETER; 1600 1601 /* Create the Object */ 1602 Status = ObCreateObject(PreviousMode, 1603 DbgkDebugObjectType, 1604 ObjectAttributes, 1605 PreviousMode, 1606 NULL, 1607 sizeof(DEBUG_OBJECT), 1608 0, 1609 0, 1610 (PVOID*)&DebugObject); 1611 if (NT_SUCCESS(Status)) 1612 { 1613 /* Initialize the Debug Object's Fast Mutex */ 1614 ExInitializeFastMutex(&DebugObject->Mutex); 1615 1616 /* Initialize the State Event List */ 1617 InitializeListHead(&DebugObject->EventList); 1618 1619 /* Initialize the Debug Object's Wait Event */ 1620 KeInitializeEvent(&DebugObject->EventsPresent, 1621 NotificationEvent, 1622 FALSE); 1623 1624 /* Set the Flags */ 1625 DebugObject->Flags = 0; 1626 if (Flags & DBGK_KILL_PROCESS_ON_EXIT) 1627 { 1628 DebugObject->KillProcessOnExit = TRUE; 1629 } 1630 1631 /* Insert it */ 1632 Status = ObInsertObject((PVOID)DebugObject, 1633 NULL, 1634 DesiredAccess, 1635 0, 1636 NULL, 1637 &hDebug); 1638 if (NT_SUCCESS(Status)) 1639 { 1640 /* Enter SEH to protect the write */ 1641 _SEH2_TRY 1642 { 1643 /* Return the handle */ 1644 *DebugHandle = hDebug; 1645 } 1646 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1647 { 1648 /* Get the exception code */ 1649 Status = _SEH2_GetExceptionCode(); 1650 } _SEH2_END; 1651 } 1652 } 1653 1654 /* Return Status */ 1655 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p DebugObject: %p\n", 1656 hDebug, DebugObject); 1657 return Status; 1658 } 1659 1660 /* 1661 * @implemented 1662 */ 1663 NTSTATUS 1664 NTAPI 1665 NtDebugContinue(IN HANDLE DebugHandle, 1666 IN PCLIENT_ID AppClientId, 1667 IN NTSTATUS ContinueStatus) 1668 { 1669 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1670 PDEBUG_OBJECT DebugObject; 1671 NTSTATUS Status; 1672 PDEBUG_EVENT DebugEvent = NULL, DebugEventToWake = NULL; 1673 PLIST_ENTRY ListHead, NextEntry; 1674 BOOLEAN NeedsWake = FALSE; 1675 CLIENT_ID ClientId; 1676 PAGED_CODE(); 1677 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p Status: %d\n", 1678 DebugHandle, ContinueStatus); 1679 1680 /* Check if we were called from user mode*/ 1681 if (PreviousMode != KernelMode) 1682 { 1683 /* Enter SEH for probing */ 1684 _SEH2_TRY 1685 { 1686 /* Probe the handle */ 1687 ProbeForRead(AppClientId, sizeof(CLIENT_ID), sizeof(ULONG)); 1688 ClientId = *AppClientId; 1689 AppClientId = &ClientId; 1690 } 1691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1692 { 1693 /* Return the exception code */ 1694 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1695 } _SEH2_END; 1696 } 1697 1698 /* Make sure that the status is valid */ 1699 if ((ContinueStatus != DBG_CONTINUE) && 1700 (ContinueStatus != DBG_EXCEPTION_HANDLED) && 1701 (ContinueStatus != DBG_EXCEPTION_NOT_HANDLED) && 1702 (ContinueStatus != DBG_TERMINATE_THREAD) && 1703 (ContinueStatus != DBG_TERMINATE_PROCESS)) 1704 { 1705 /* Invalid status */ 1706 Status = STATUS_INVALID_PARAMETER; 1707 } 1708 else 1709 { 1710 /* Get the debug object */ 1711 Status = ObReferenceObjectByHandle(DebugHandle, 1712 DEBUG_OBJECT_WAIT_STATE_CHANGE, 1713 DbgkDebugObjectType, 1714 PreviousMode, 1715 (PVOID*)&DebugObject, 1716 NULL); 1717 if (NT_SUCCESS(Status)) 1718 { 1719 /* Acquire the mutex */ 1720 ExAcquireFastMutex(&DebugObject->Mutex); 1721 1722 /* Loop the state list */ 1723 ListHead = &DebugObject->EventList; 1724 NextEntry = ListHead->Flink; 1725 while (ListHead != NextEntry) 1726 { 1727 /* Get the current debug event */ 1728 DebugEvent = CONTAINING_RECORD(NextEntry, 1729 DEBUG_EVENT, 1730 EventList); 1731 1732 /* Compare process ID */ 1733 if (DebugEvent->ClientId.UniqueProcess == 1734 AppClientId->UniqueProcess) 1735 { 1736 /* Check if we already found a match */ 1737 if (NeedsWake) 1738 { 1739 /* Wake it up and break out */ 1740 DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE; 1741 KeSetEvent(&DebugObject->EventsPresent, 1742 IO_NO_INCREMENT, 1743 FALSE); 1744 break; 1745 } 1746 1747 /* Compare thread ID and flag */ 1748 if ((DebugEvent->ClientId.UniqueThread == 1749 AppClientId->UniqueThread) && (DebugEvent->Flags & DEBUG_EVENT_READ)) 1750 { 1751 /* Remove the event from the list */ 1752 RemoveEntryList(NextEntry); 1753 1754 /* Remember who to wake */ 1755 NeedsWake = TRUE; 1756 DebugEventToWake = DebugEvent; 1757 } 1758 } 1759 1760 /* Go to the next entry */ 1761 NextEntry = NextEntry->Flink; 1762 } 1763 1764 /* Release the mutex */ 1765 ExReleaseFastMutex(&DebugObject->Mutex); 1766 1767 /* Dereference the object */ 1768 ObDereferenceObject(DebugObject); 1769 1770 /* Check if need a wait */ 1771 if (NeedsWake) 1772 { 1773 /* Set the continue status */ 1774 DebugEventToWake->ApiMsg.ReturnedStatus = ContinueStatus; 1775 DebugEventToWake->Status = STATUS_SUCCESS; 1776 1777 /* Wake the target */ 1778 DbgkpWakeTarget(DebugEventToWake); 1779 } 1780 else 1781 { 1782 /* Fail */ 1783 Status = STATUS_INVALID_PARAMETER; 1784 } 1785 } 1786 } 1787 1788 /* Return status */ 1789 return Status; 1790 } 1791 1792 /* 1793 * @implemented 1794 */ 1795 NTSTATUS 1796 NTAPI 1797 NtDebugActiveProcess(IN HANDLE ProcessHandle, 1798 IN HANDLE DebugHandle) 1799 { 1800 PEPROCESS Process; 1801 PDEBUG_OBJECT DebugObject; 1802 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1803 PETHREAD LastThread; 1804 NTSTATUS Status; 1805 PAGED_CODE(); 1806 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Handle: %p\n", 1807 ProcessHandle, DebugHandle); 1808 1809 /* Reference the process */ 1810 Status = ObReferenceObjectByHandle(ProcessHandle, 1811 PROCESS_SUSPEND_RESUME, 1812 PsProcessType, 1813 PreviousMode, 1814 (PVOID*)&Process, 1815 NULL); 1816 if (!NT_SUCCESS(Status)) return Status; 1817 1818 /* Don't allow debugging the current process or the system process */ 1819 if ((Process == PsGetCurrentProcess()) || 1820 (Process == PsInitialSystemProcess)) 1821 { 1822 /* Dereference and fail */ 1823 ObDereferenceObject(Process); 1824 return STATUS_ACCESS_DENIED; 1825 } 1826 1827 /* Reference the debug object */ 1828 Status = ObReferenceObjectByHandle(DebugHandle, 1829 DEBUG_OBJECT_ADD_REMOVE_PROCESS, 1830 DbgkDebugObjectType, 1831 PreviousMode, 1832 (PVOID*)&DebugObject, 1833 NULL); 1834 if (!NT_SUCCESS(Status)) 1835 { 1836 /* Dereference the process and exit */ 1837 ObDereferenceObject(Process); 1838 return Status; 1839 } 1840 1841 /* Acquire process rundown protection */ 1842 if (!ExAcquireRundownProtection(&Process->RundownProtect)) 1843 { 1844 /* Dereference the process and debug object and exit */ 1845 ObDereferenceObject(Process); 1846 ObDereferenceObject(DebugObject); 1847 return STATUS_PROCESS_IS_TERMINATING; 1848 } 1849 1850 /* Send fake create messages for debuggers to have a consistent state */ 1851 Status = DbgkpPostFakeProcessCreateMessages(Process, 1852 DebugObject, 1853 &LastThread); 1854 Status = DbgkpSetProcessDebugObject(Process, 1855 DebugObject, 1856 Status, 1857 LastThread); 1858 1859 /* Release rundown protection */ 1860 ExReleaseRundownProtection(&Process->RundownProtect); 1861 1862 /* Dereference the process and debug object and return status */ 1863 ObDereferenceObject(Process); 1864 ObDereferenceObject(DebugObject); 1865 return Status; 1866 } 1867 1868 /* 1869 * @implemented 1870 */ 1871 NTSTATUS 1872 NTAPI 1873 NtRemoveProcessDebug(IN HANDLE ProcessHandle, 1874 IN HANDLE DebugHandle) 1875 { 1876 PEPROCESS Process; 1877 PDEBUG_OBJECT DebugObject; 1878 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1879 NTSTATUS Status; 1880 PAGED_CODE(); 1881 DBGKTRACE(DBGK_PROCESS_DEBUG, "Process: %p Handle: %p\n", 1882 ProcessHandle, DebugHandle); 1883 1884 /* Reference the process */ 1885 Status = ObReferenceObjectByHandle(ProcessHandle, 1886 PROCESS_SUSPEND_RESUME, 1887 PsProcessType, 1888 PreviousMode, 1889 (PVOID*)&Process, 1890 NULL); 1891 if (!NT_SUCCESS(Status)) return Status; 1892 1893 /* Reference the debug object */ 1894 Status = ObReferenceObjectByHandle(DebugHandle, 1895 DEBUG_OBJECT_ADD_REMOVE_PROCESS, 1896 DbgkDebugObjectType, 1897 PreviousMode, 1898 (PVOID*)&DebugObject, 1899 NULL); 1900 if (!NT_SUCCESS(Status)) 1901 { 1902 /* Dereference the process and exit */ 1903 ObDereferenceObject(Process); 1904 return Status; 1905 } 1906 1907 /* Remove the debug object */ 1908 Status = DbgkClearProcessDebugObject(Process, DebugObject); 1909 1910 /* Dereference the process and debug object and return status */ 1911 ObDereferenceObject(Process); 1912 ObDereferenceObject(DebugObject); 1913 return Status; 1914 } 1915 1916 /* 1917 * @implemented 1918 */ 1919 NTSTATUS 1920 NTAPI 1921 NtSetInformationDebugObject(IN HANDLE DebugHandle, 1922 IN DEBUGOBJECTINFOCLASS DebugObjectInformationClass, 1923 IN PVOID DebugInformation, 1924 IN ULONG DebugInformationLength, 1925 OUT PULONG ReturnLength OPTIONAL) 1926 { 1927 PDEBUG_OBJECT DebugObject; 1928 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1929 NTSTATUS Status; 1930 PDEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION DebugInfo = DebugInformation; 1931 PAGED_CODE(); 1932 1933 /* Check buffers and parameters */ 1934 Status = DefaultSetInfoBufferCheck(DebugObjectInformationClass, 1935 DbgkpDebugObjectInfoClass, 1936 sizeof(DbgkpDebugObjectInfoClass) / 1937 sizeof(DbgkpDebugObjectInfoClass[0]), 1938 DebugInformation, 1939 DebugInformationLength, 1940 PreviousMode); 1941 if (!NT_SUCCESS(Status)) return Status; 1942 1943 /* Check if the caller wanted the return length */ 1944 if (ReturnLength) 1945 { 1946 /* Enter SEH for probe */ 1947 _SEH2_TRY 1948 { 1949 /* Return required length to user-mode */ 1950 ProbeForWriteUlong(ReturnLength); 1951 *ReturnLength = sizeof(*DebugInfo); 1952 } 1953 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1954 { 1955 /* Return the exception code */ 1956 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1957 } 1958 _SEH2_END; 1959 } 1960 1961 /* Open the Object */ 1962 Status = ObReferenceObjectByHandle(DebugHandle, 1963 DEBUG_OBJECT_WAIT_STATE_CHANGE, 1964 DbgkDebugObjectType, 1965 PreviousMode, 1966 (PVOID*)&DebugObject, 1967 NULL); 1968 if (NT_SUCCESS(Status)) 1969 { 1970 /* Acquire the object */ 1971 ExAcquireFastMutex(&DebugObject->Mutex); 1972 1973 /* Set the proper flag */ 1974 if (DebugInfo->KillProcessOnExit) 1975 { 1976 /* Enable killing the process */ 1977 DebugObject->KillProcessOnExit = TRUE; 1978 } 1979 else 1980 { 1981 /* Disable */ 1982 DebugObject->KillProcessOnExit = FALSE; 1983 } 1984 1985 /* Release the mutex */ 1986 ExReleaseFastMutex(&DebugObject->Mutex); 1987 1988 /* Release the Object */ 1989 ObDereferenceObject(DebugObject); 1990 } 1991 1992 /* Return Status */ 1993 return Status; 1994 } 1995 1996 /* 1997 * @implemented 1998 */ 1999 NTSTATUS 2000 NTAPI 2001 NtWaitForDebugEvent(IN HANDLE DebugHandle, 2002 IN BOOLEAN Alertable, 2003 IN PLARGE_INTEGER Timeout OPTIONAL, 2004 OUT PDBGUI_WAIT_STATE_CHANGE StateChange) 2005 { 2006 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2007 LARGE_INTEGER LocalTimeOut; 2008 PEPROCESS Process; 2009 LARGE_INTEGER StartTime; 2010 PETHREAD Thread; 2011 BOOLEAN GotEvent; 2012 LARGE_INTEGER NewTime; 2013 PDEBUG_OBJECT DebugObject; 2014 DBGUI_WAIT_STATE_CHANGE WaitStateChange; 2015 NTSTATUS Status; 2016 PDEBUG_EVENT DebugEvent = NULL, DebugEvent2; 2017 PLIST_ENTRY ListHead, NextEntry, NextEntry2; 2018 PAGED_CODE(); 2019 DBGKTRACE(DBGK_OBJECT_DEBUG, "Handle: %p\n", DebugHandle); 2020 2021 /* Clear the initial wait state change structure and the timeout */ 2022 RtlZeroMemory(&WaitStateChange, sizeof(WaitStateChange)); 2023 LocalTimeOut.QuadPart = 0; 2024 2025 /* Check if we were called from user mode */ 2026 if (PreviousMode != KernelMode) 2027 { 2028 /* Protect probe in SEH */ 2029 _SEH2_TRY 2030 { 2031 /* Check if we came with a timeout */ 2032 if (Timeout) 2033 { 2034 /* Probe it */ 2035 ProbeForReadLargeInteger(Timeout); 2036 2037 /* Make a local copy */ 2038 LocalTimeOut = *Timeout; 2039 Timeout = &LocalTimeOut; 2040 } 2041 2042 /* Probe the state change structure */ 2043 ProbeForWrite(StateChange, sizeof(*StateChange), sizeof(ULONG)); 2044 } 2045 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2046 { 2047 /* Return the exception code */ 2048 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2049 } 2050 _SEH2_END; 2051 } 2052 else 2053 { 2054 /* Copy directly */ 2055 if (Timeout) LocalTimeOut = *Timeout; 2056 } 2057 2058 /* If we were passed a timeout, query the current time */ 2059 if (Timeout) KeQuerySystemTime(&StartTime); 2060 2061 /* Get the debug object */ 2062 Status = ObReferenceObjectByHandle(DebugHandle, 2063 DEBUG_OBJECT_WAIT_STATE_CHANGE, 2064 DbgkDebugObjectType, 2065 PreviousMode, 2066 (PVOID*)&DebugObject, 2067 NULL); 2068 if (!NT_SUCCESS(Status)) return Status; 2069 2070 /* Clear process and thread */ 2071 Process = NULL; 2072 Thread = NULL; 2073 2074 /* Wait on the debug object given to us */ 2075 while (TRUE) 2076 { 2077 Status = KeWaitForSingleObject(&DebugObject->EventsPresent, 2078 Executive, 2079 PreviousMode, 2080 Alertable, 2081 Timeout); 2082 if (!NT_SUCCESS(Status) || 2083 (Status == STATUS_TIMEOUT) || 2084 (Status == STATUS_ALERTED) || 2085 (Status == STATUS_USER_APC)) 2086 { 2087 /* Break out the wait */ 2088 break; 2089 } 2090 2091 /* Lock the object */ 2092 GotEvent = FALSE; 2093 ExAcquireFastMutex(&DebugObject->Mutex); 2094 2095 /* Check if a debugger is connected */ 2096 if (DebugObject->DebuggerInactive) 2097 { 2098 /* Not connected */ 2099 Status = STATUS_DEBUGGER_INACTIVE; 2100 } 2101 else 2102 { 2103 /* Loop the events */ 2104 ListHead = &DebugObject->EventList; 2105 NextEntry = ListHead->Flink; 2106 while (ListHead != NextEntry) 2107 { 2108 /* Get the debug event */ 2109 DebugEvent = CONTAINING_RECORD(NextEntry, 2110 DEBUG_EVENT, 2111 EventList); 2112 DBGKTRACE(DBGK_PROCESS_DEBUG, "DebugEvent: %p Flags: %lx\n", 2113 DebugEvent, DebugEvent->Flags); 2114 2115 /* Check flags */ 2116 if (!(DebugEvent->Flags & (DEBUG_EVENT_INACTIVE | DEBUG_EVENT_READ))) 2117 { 2118 /* We got an event */ 2119 GotEvent = TRUE; 2120 2121 /* Loop the list internally */ 2122 NextEntry2 = DebugObject->EventList.Flink; 2123 while (NextEntry2 != NextEntry) 2124 { 2125 /* Get the debug event */ 2126 DebugEvent2 = CONTAINING_RECORD(NextEntry2, 2127 DEBUG_EVENT, 2128 EventList); 2129 2130 /* Try to match process IDs */ 2131 if (DebugEvent2->ClientId.UniqueProcess == 2132 DebugEvent->ClientId.UniqueProcess) 2133 { 2134 /* Found it, break out */ 2135 DebugEvent->Flags |= DEBUG_EVENT_INACTIVE; 2136 DebugEvent->BackoutThread = NULL; 2137 GotEvent = FALSE; 2138 break; 2139 } 2140 2141 /* Move to the next entry */ 2142 NextEntry2 = NextEntry2->Flink; 2143 } 2144 2145 /* Check if we still have a valid event */ 2146 if (GotEvent) break; 2147 } 2148 2149 /* Move to the next entry */ 2150 NextEntry = NextEntry->Flink; 2151 } 2152 2153 /* Check if we have an event */ 2154 if (GotEvent) 2155 { 2156 /* Save and reference the process and thread */ 2157 Process = DebugEvent->Process; 2158 Thread = DebugEvent->Thread; 2159 ObReferenceObject(Process); 2160 ObReferenceObject(Thread); 2161 2162 /* Convert to user-mode structure */ 2163 DbgkpConvertKernelToUserStateChange(&WaitStateChange, 2164 DebugEvent); 2165 2166 /* Set flag */ 2167 DebugEvent->Flags |= DEBUG_EVENT_READ; 2168 } 2169 else 2170 { 2171 /* Unsignal the event */ 2172 KeClearEvent(&DebugObject->EventsPresent); 2173 } 2174 2175 /* Set success */ 2176 Status = STATUS_SUCCESS; 2177 } 2178 2179 /* Release the mutex */ 2180 ExReleaseFastMutex(&DebugObject->Mutex); 2181 if (!NT_SUCCESS(Status)) break; 2182 2183 /* Check if we got an event */ 2184 if (!GotEvent) 2185 { 2186 /* Check if we can wait again */ 2187 if (LocalTimeOut.QuadPart < 0) 2188 { 2189 /* Query the new time */ 2190 KeQuerySystemTime(&NewTime); 2191 2192 /* Substract times */ 2193 LocalTimeOut.QuadPart += (NewTime.QuadPart - StartTime.QuadPart); 2194 StartTime = NewTime; 2195 2196 /* Check if we've timed out */ 2197 if (LocalTimeOut.QuadPart >= 0) 2198 { 2199 /* We have, break out of the loop */ 2200 Status = STATUS_TIMEOUT; 2201 break; 2202 } 2203 } 2204 } 2205 else 2206 { 2207 /* Open the handles and dereference the objects */ 2208 DbgkpOpenHandles(&WaitStateChange, Process, Thread); 2209 ObDereferenceObject(Process); 2210 ObDereferenceObject(Thread); 2211 break; 2212 } 2213 } 2214 2215 /* We're done, dereference the object */ 2216 ObDereferenceObject(DebugObject); 2217 2218 /* Protect write with SEH */ 2219 _SEH2_TRY 2220 { 2221 /* Return our wait state change structure */ 2222 *StateChange = WaitStateChange; 2223 } 2224 _SEH2_EXCEPT(ExSystemExceptionFilter()) 2225 { 2226 /* Get SEH Exception code */ 2227 Status = _SEH2_GetExceptionCode(); 2228 } 2229 _SEH2_END; 2230 2231 /* Return status */ 2232 return Status; 2233 } 2234