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