Windows NT 4.0 source code leak
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

/*++
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;
}