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