ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sun May 27 2012 04:37:09 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.