mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
560 lines
15 KiB
560 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbgloop.c
|
|
|
|
Abstract:
|
|
|
|
Debug Subsystem Listen and API loops
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 04-Oct-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "smsrvp.h"
|
|
|
|
NTSTATUS
|
|
DbgpSsHandleConnectionRequest(
|
|
IN PPORT_MESSAGE ConnectionRequest
|
|
);
|
|
|
|
NTSTATUS
|
|
DbgpUiHandleConnectionRequest(
|
|
IN PDBGUI_APIMSG Message
|
|
);
|
|
|
|
|
|
PDBGSS_API DbgpSsDispatch[DbgSsMaxApiNumber] = {
|
|
DbgpSsException,
|
|
DbgpSsCreateThread,
|
|
DbgpSsCreateProcess,
|
|
DbgpSsExitThread,
|
|
DbgpSsExitProcess,
|
|
DbgpSsLoadDll,
|
|
DbgpSsUnloadDll
|
|
};
|
|
|
|
|
|
#if DBG
|
|
PSZ DbgpSsApiName[ DbgSsMaxApiNumber+1 ] = {
|
|
"DbgpSsException",
|
|
"DbgpSsCreateThread",
|
|
"DbgpSsCreateProcess",
|
|
"DbgpSsExitThread",
|
|
"DbgpSsExitProcess",
|
|
"DbgpSsLoadDll",
|
|
"DbgpSsUnloadDll",
|
|
"Unknown DbgSs Api Number"
|
|
};
|
|
#endif // DBG
|
|
|
|
EXCEPTION_DISPOSITION
|
|
DbgpUnhandledExceptionFilter(
|
|
struct _EXCEPTION_POINTERS *ExceptionInfo
|
|
)
|
|
{
|
|
|
|
UNICODE_STRING UnicodeParameter;
|
|
ULONG Parameters[ 4 ];
|
|
ULONG Response;
|
|
BOOLEAN WasEnabled;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Terminating will cause sm's wait to sense that we crashed. This will
|
|
// result in a clean shutdown due to sm's hard error logic
|
|
//
|
|
|
|
//
|
|
// We are hosed, so raise a fata system error to shutdown the system.
|
|
// (Basically a user mode KeBugCheck).
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|
(BOOLEAN)TRUE,
|
|
TRUE,
|
|
&WasEnabled
|
|
);
|
|
|
|
if (Status == STATUS_NO_TOKEN) {
|
|
|
|
//
|
|
// No thread token, use the process token
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|
(BOOLEAN)TRUE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
}
|
|
|
|
RtlInitUnicodeString( &UnicodeParameter, L"Session Manager" );
|
|
Parameters[ 0 ] = (ULONG)&UnicodeParameter;
|
|
Parameters[ 1 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode;
|
|
Parameters[ 2 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress;
|
|
Parameters[ 3 ] = (ULONG)ExceptionInfo->ContextRecord;
|
|
Status = NtRaiseHardError( STATUS_SYSTEM_PROCESS_TERMINATED,
|
|
4,
|
|
1,
|
|
Parameters,
|
|
OptionShutdownSystem,
|
|
&Response
|
|
);
|
|
|
|
//
|
|
// If this returns, giveup
|
|
//
|
|
|
|
NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode);
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgpSsApiLoop (
|
|
IN PVOID ThreadParameter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the API loop for DbgSs APIs.
|
|
|
|
Arguments:
|
|
|
|
ThreadParameter - Not Used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGSRV_APIMSG ContinueMsg;
|
|
DBGSS_APIMSG ApiMsg;
|
|
NTSTATUS Status;
|
|
PDBGP_SUBSYSTEM Subsystem;
|
|
|
|
try {
|
|
for(;;) {
|
|
|
|
Status = NtReplyWaitReceivePort(
|
|
DbgpSsApiPort,
|
|
(PVOID *) &Subsystem,
|
|
NULL,
|
|
(PPORT_MESSAGE) &ApiMsg
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
if (ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) {
|
|
DbgpSsHandleConnectionRequest( (PPORT_MESSAGE) &ApiMsg );
|
|
} else if (ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED ) {
|
|
;
|
|
} else {
|
|
|
|
ApiMsg.ReturnedStatus = STATUS_PENDING;
|
|
|
|
if (ApiMsg.ApiNumber >= DbgSsMaxApiNumber ) {
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
} else {
|
|
|
|
Status = (DbgpSsDispatch[ApiMsg.ApiNumber])(Subsystem,&ApiMsg);
|
|
}
|
|
|
|
//
|
|
// Since all DbgSs API's are asynchronous, DBG_REPLY_LATER is used
|
|
// as a status code that means the API has been started. A continue
|
|
// will arrive at some point in the future. Otherwise, this loop
|
|
// will actually to the continue.
|
|
//
|
|
|
|
if ( Status != DBG_REPLY_LATER ) {
|
|
|
|
KdPrint(("DBGSS: %s Api Request Failed %lx\n",
|
|
DbgpSsApiName[ ApiMsg.ApiNumber ],
|
|
Status
|
|
));
|
|
|
|
DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,ApiMsg.ContinueKey);
|
|
ContinueMsg.ReturnedStatus = Status;
|
|
|
|
Status = NtRequestPort(Subsystem->CommunicationPort, (PPORT_MESSAGE)&ContinueMsg);
|
|
KdPrint(("DBGSS: Request Status %x\n",Status));
|
|
}
|
|
}
|
|
}
|
|
} except (DbgpUnhandledExceptionFilter( GetExceptionInformation() )) {
|
|
;
|
|
}
|
|
|
|
//
|
|
// Make the compiler happy
|
|
//
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsHandleConnectionRequest(
|
|
IN PPORT_MESSAGE ConnectionRequest
|
|
)
|
|
{
|
|
NTSTATUS st;
|
|
HANDLE CommunicationPort;
|
|
HANDLE SubsystemProcessHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
PDBGP_SUBSYSTEM Subsystem;
|
|
BOOLEAN Accept;
|
|
|
|
InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
|
|
st = NtOpenProcess(
|
|
&SubsystemProcessHandle,
|
|
DBGP_OPEN_SUBSYSTEM_ACCESS,
|
|
&Obja,
|
|
&ConnectionRequest->ClientId
|
|
);
|
|
|
|
//
|
|
// If we are unable to open the process, then we can not complete
|
|
// connection. This is because the handle is needed to pass thread
|
|
// and process handles from the subsystem to the DebugUi.
|
|
//
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
Accept = FALSE;
|
|
} else {
|
|
|
|
Accept = TRUE;
|
|
|
|
//
|
|
// Allocate a subsystem control block.
|
|
// The address of this block is used as the
|
|
// port context in all calls from a subsystem.
|
|
//
|
|
|
|
Subsystem = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_SUBSYSTEM));
|
|
Subsystem->SubsystemProcessHandle = SubsystemProcessHandle;
|
|
Subsystem->SubsystemClientId = ConnectionRequest->ClientId;
|
|
}
|
|
|
|
st = NtAcceptConnectPort(
|
|
&CommunicationPort,
|
|
(PVOID)Subsystem,
|
|
ConnectionRequest,
|
|
Accept,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ASSERT( NT_SUCCESS(st) );
|
|
|
|
if ( Accept ) {
|
|
|
|
Subsystem->CommunicationPort = CommunicationPort;
|
|
st = NtCompleteConnectPort(CommunicationPort);
|
|
ASSERT( NT_SUCCESS(st) );
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
PDBGUI_API DbgpUiDispatch[DbgUiMaxApiNumber] = {
|
|
DbgpUiWaitStateChange,
|
|
DbgpUiContinue
|
|
};
|
|
|
|
|
|
#if DBG
|
|
PSZ DbgpUiApiName[ DbgUiMaxApiNumber+1 ] = {
|
|
"DbgpUiWaitStateChange",
|
|
"DbgpUiContinue",
|
|
"Unknown DbgUi Api Number"
|
|
};
|
|
#endif // DBG
|
|
|
|
NTSTATUS
|
|
DbgpUiApiLoop (
|
|
IN PVOID ThreadParameter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the API loop for DbgUi APIs.
|
|
|
|
Arguments:
|
|
|
|
ThreadParameter - Not Used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGUI_APIMSG ReplyMsg;
|
|
DBGUI_APIMSG ApiMsg;
|
|
NTSTATUS Status;
|
|
PDBGP_USER_INTERFACE UserInterface;
|
|
|
|
try {
|
|
ReplyMsg = NULL;
|
|
for(;;) {
|
|
Status = NtReplyWaitReceivePort(
|
|
DbgpUiApiPort,
|
|
(PVOID *) &UserInterface,
|
|
(PPORT_MESSAGE) ReplyMsg,
|
|
(PPORT_MESSAGE) &ApiMsg
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
ReplyMsg = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) {
|
|
DbgpUiHandleConnectionRequest( &ApiMsg );
|
|
ReplyMsg = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (ApiMsg.h.u2.s2.Type == LPC_CLIENT_DIED) {
|
|
DbgpUiHasTerminated(&ApiMsg.h.ClientId);
|
|
ReplyMsg = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED) {
|
|
ReplyMsg = NULL;
|
|
continue;
|
|
}
|
|
|
|
ApiMsg.ReturnedStatus = STATUS_PENDING;
|
|
|
|
#if DBG && 0
|
|
if (ApiMsg.ApiNumber >= DbgUiMaxApiNumber ) {
|
|
ApiMsg.ApiNumber = DbgUiMaxApiNumber;
|
|
}
|
|
DbgPrint( "DBG_UILOOP: %s Api Request received from %lx.%lx\n",
|
|
DbgpUiApiName[ ApiMsg.ApiNumber ],
|
|
ApiMsg.h.ClientId.UniqueProcess,
|
|
ApiMsg.h.ClientId.UniqueThread
|
|
);
|
|
#endif // DBG
|
|
|
|
if (ApiMsg.ApiNumber >= DbgUiMaxApiNumber ) {
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
} else {
|
|
|
|
Status = (DbgpUiDispatch[ApiMsg.ApiNumber])(UserInterface,&ApiMsg);
|
|
}
|
|
|
|
//
|
|
// Some APIs do not cause an immediate reply. This is signaled
|
|
// by returning DBG_REPLY_LATER
|
|
//
|
|
|
|
if ( Status == DBG_REPLY_LATER ) {
|
|
ReplyMsg = NULL;
|
|
} else {
|
|
ApiMsg.ReturnedStatus = Status;
|
|
ReplyMsg = &ApiMsg;
|
|
}
|
|
|
|
ApiMsg.ReturnedStatus = Status;
|
|
ReplyMsg = &ApiMsg;
|
|
}
|
|
} except (DbgpUnhandledExceptionFilter( GetExceptionInformation() )) {
|
|
;
|
|
}
|
|
|
|
//
|
|
// Make the compiler happy
|
|
//
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgpUiHandleConnectionRequest(
|
|
IN PDBGUI_APIMSG Message
|
|
)
|
|
{
|
|
|
|
NTSTATUS st;
|
|
HANDLE CommunicationPort;
|
|
HANDLE UserInterfaceHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
PDBGP_USER_INTERFACE UserInterface;
|
|
PHANDLE ConnectionInformation;
|
|
BOOLEAN Accept;
|
|
|
|
//
|
|
// Createing a connection between a DebugUi and the debug
|
|
// subsystem causes the following to occur.
|
|
//
|
|
// - A UserInterface Control Block (UICB) is created and initialized
|
|
// - A handle to the Ui process is created and stored in UICB
|
|
// - A state change semaphore is created. A handle to this semaphore
|
|
// is placed in the Ui process. This handle is given SYNCHRONIZE
|
|
// access. The value of this handle is returned during connection
|
|
// accept as ConnectionInformation.
|
|
// - Address of the UICB is used as port context and is made available
|
|
// in all calls from the Ui.
|
|
// - The UICB is linked into the DebugUiHashTable
|
|
//
|
|
|
|
InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
|
|
st = NtOpenProcess(
|
|
&UserInterfaceHandle,
|
|
DBGP_OPEN_UI_ACCESS,
|
|
&Obja,
|
|
&Message->h.ClientId
|
|
);
|
|
|
|
//
|
|
// If we are unable to open the process, then we can not complete
|
|
// connection. This is because the handle is needed to pass thread
|
|
// and process handles from the subsystem to the DebugUi.
|
|
//
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
Accept = FALSE;
|
|
} else {
|
|
Accept = TRUE;
|
|
ConnectionInformation = &Message->DbgStateChangeSemaphore;
|
|
|
|
//
|
|
// Allocate a DebugUserInterface control block.
|
|
// The address of this block is used as the
|
|
// port context in all calls from a DebugUi.
|
|
//
|
|
|
|
UserInterface = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_USER_INTERFACE));
|
|
if ( !UserInterface ) {
|
|
st = STATUS_NO_MEMORY;
|
|
} else {
|
|
|
|
//
|
|
// Initialize UserInterface Control Block
|
|
//
|
|
|
|
UserInterface->DebugUiClientId = Message->h.ClientId;
|
|
UserInterface->DebugUiProcess = UserInterfaceHandle;
|
|
InitializeListHead(&UserInterface->AppProcessListHead);
|
|
|
|
//
|
|
// Create a state change semaphore. Dbg gets all access to
|
|
// semaphore. A handle to this semaphore with SYNCHRONIZE
|
|
// access is duplicated into the Ui. This handle is used
|
|
// by Ui to wait for state changes.
|
|
//
|
|
|
|
st = NtCreateSemaphore(
|
|
&UserInterface->StateChangeSemaphore,
|
|
SEMAPHORE_ALL_ACCESS,
|
|
NULL,
|
|
0L,
|
|
MAXLONG
|
|
);
|
|
}
|
|
if ( !NT_SUCCESS(st) ) {
|
|
|
|
//
|
|
// Create semaphore failed, so don't accept connection
|
|
//
|
|
|
|
NtClose(UserInterfaceHandle);
|
|
if ( UserInterface ) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0,UserInterface);
|
|
}
|
|
Accept = FALSE;
|
|
} else {
|
|
|
|
//
|
|
// Allocate a critical section for the user interface control
|
|
// block
|
|
//
|
|
|
|
st = RtlInitializeCriticalSection(
|
|
&UserInterface->UserInterfaceLock
|
|
);
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
|
|
NtClose(UserInterface->StateChangeSemaphore);
|
|
NtClose(UserInterfaceHandle);
|
|
RtlFreeHeap(RtlProcessHeap(), 0,UserInterface);
|
|
Accept = FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If this operation is successful then connection request
|
|
// can be accepted. The Ui's handle to the state change
|
|
// semaphore is returned in the connection information
|
|
// structure.
|
|
//
|
|
|
|
st = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
UserInterface->StateChangeSemaphore,
|
|
UserInterfaceHandle,
|
|
ConnectionInformation,
|
|
SYNCHRONIZE,
|
|
0L,
|
|
0L
|
|
);
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
RtlDeleteCriticalSection(
|
|
&UserInterface->UserInterfaceLock
|
|
);
|
|
NtClose(UserInterface->StateChangeSemaphore);
|
|
NtClose(UserInterfaceHandle);
|
|
RtlFreeHeap(RtlProcessHeap(), 0,UserInterface);
|
|
Accept = FALSE;
|
|
} else {
|
|
RtlEnterCriticalSection(&DbgpHashTableLock);
|
|
InsertTailList(
|
|
&DbgpUiHashTable[DBGP_PROCESS_CLIENT_ID_TO_INDEX(&UserInterface->DebugUiClientId)],
|
|
&UserInterface->HashTableLinks
|
|
);
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
st = NtAcceptConnectPort(
|
|
&CommunicationPort,
|
|
(PVOID)UserInterface,
|
|
(PPORT_MESSAGE)Message,
|
|
Accept,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( NT_SUCCESS(st) && Accept ) {
|
|
UserInterface->CommunicationPort = CommunicationPort;
|
|
NtCompleteConnectPort(CommunicationPort);
|
|
}
|
|
|
|
return st;
|
|
}
|