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