705 lines
16 KiB
C
705 lines
16 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 - 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbgssapi.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the DbgSs APIs
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 22-Jan-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "smsrvp.h"
|
|
|
|
NTSTATUS
|
|
DbgpSsException (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that an exception has occured.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_THREAD AppThread;
|
|
NTSTATUS ExceptionCode;
|
|
|
|
//
|
|
// Locate AppThread
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Verify that the thread is DbgIdle (i.e. we are expecting a state change)
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgIdle ) {
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
return DBG_APP_NOT_IDLE;
|
|
}
|
|
|
|
ExceptionCode = ApiMsg->u.Exception.ExceptionRecord.ExceptionCode;
|
|
|
|
if ( ExceptionCode == STATUS_BREAKPOINT ) {
|
|
AppThread->CurrentState = DbgBreakpointStateChange;
|
|
} else if ( ExceptionCode == STATUS_SINGLE_STEP ) {
|
|
AppThread->CurrentState = DbgSingleStepStateChange;
|
|
} else {
|
|
AppThread->CurrentState = DbgExceptionStateChange;
|
|
}
|
|
|
|
AppThread->ContinueState = AppThread->CurrentState;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
return DBG_REPLY_LATER;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsCreateThread (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a thread has been created.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
STATUS_INVALID_CID - Process that this thread is part of could not
|
|
be located.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_PROCESS AppProcess;
|
|
PDBGP_APP_THREAD AppThread;
|
|
NTSTATUS st;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
|
|
//
|
|
// Locate AppProcess this thread is a part of
|
|
//
|
|
|
|
RtlEnterCriticalSection(&DbgpHashTableLock);
|
|
|
|
AppProcess = DbgpIsAppProcessInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppProcess ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
//
|
|
// Now look to see if a thread whose ClientId matches
|
|
// the new threads ClientId exists in the APP table.
|
|
// This check is not really necessary, its really just
|
|
// a question of trust of DbgSs APIs.
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( AppThread ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate an initialize and application thread structure.
|
|
// Link this into its process and into the application
|
|
// hash table
|
|
//
|
|
|
|
AppThread = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_THREAD));
|
|
|
|
if ( !AppThread ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
AppThread->CurrentState = DbgCreateThreadStateChange;
|
|
AppThread->ContinueState = DbgCreateThreadStateChange;
|
|
AppThread->AppProcess = AppProcess;
|
|
AppThread->UserInterface = AppProcess->UserInterface;
|
|
AppThread->AppClientId = ApiMsg->AppClientId;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
//
|
|
// Get a local handle to the thread.
|
|
//
|
|
|
|
InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
|
|
st = NtOpenThread(
|
|
&AppThread->HandleToThread,
|
|
DBGP_OPEN_APP_THREAD_ACCESS,
|
|
&Obja,
|
|
&AppThread->AppClientId
|
|
);
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
AppThread->HandleToThread = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Insert thread on its process app list
|
|
//
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
InsertTailList(
|
|
&AppProcess->AppThreadListHead,
|
|
&AppThread->AppLinks
|
|
);
|
|
|
|
//
|
|
// Insert thread in app hash table
|
|
//
|
|
|
|
InsertTailList(
|
|
&DbgpAppThreadHashTable[DBGP_THREAD_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)],
|
|
&AppThread->HashTableLinks
|
|
);
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
|
|
|
|
return DBG_REPLY_LATER;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsCreateProcess (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a new process has been created.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
STATUS_INVALID_CID - An invalid ClientId was specified for the
|
|
DebugUiClientId.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_USER_INTERFACE UserInterface;
|
|
PDBGP_APP_PROCESS AppProcess;
|
|
PDBGP_APP_THREAD AppThread;
|
|
PDBGSS_CREATE_PROCESS args;
|
|
NTSTATUS st;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
|
|
args = &ApiMsg->u.CreateProcessInfo;
|
|
|
|
//
|
|
// Locate user interface specified by DebugUiClientId
|
|
//
|
|
|
|
RtlEnterCriticalSection(&DbgpHashTableLock);
|
|
|
|
UserInterface = DbgpIsUiInHashTable(&args->DebugUiClientId);
|
|
|
|
if ( !UserInterface ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
//
|
|
// Now look to see if a thread whose ClientId matches
|
|
// the new threads ClientId exists in the APP tables.
|
|
// This check is not really necessary, its really just
|
|
// a question of trust of DbgSs APIs.
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( AppThread ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate an initialize and application thread and process structure.
|
|
// Link these into the user interface and into the application
|
|
// hash table
|
|
//
|
|
|
|
AppProcess = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_PROCESS));
|
|
|
|
if ( !AppProcess ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
AppThread = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_THREAD));
|
|
|
|
if ( !AppThread ) {
|
|
RtlFreeHeap(RtlProcessHeap(),0,AppProcess);
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
AppThread->CurrentState = DbgCreateProcessStateChange;
|
|
AppThread->CurrentState = DbgCreateProcessStateChange;
|
|
AppThread->AppProcess = AppProcess;
|
|
AppThread->UserInterface = UserInterface;
|
|
AppThread->AppClientId = ApiMsg->AppClientId;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
AppProcess->AppClientId.UniqueProcess = ApiMsg->AppClientId.UniqueProcess;
|
|
AppProcess->AppClientId.UniqueThread = NULL;
|
|
AppProcess->UserInterface = UserInterface;
|
|
InitializeListHead(&AppProcess->AppThreadListHead);
|
|
|
|
InsertTailList(
|
|
&AppProcess->AppThreadListHead,
|
|
&AppThread->AppLinks
|
|
);
|
|
|
|
|
|
//
|
|
// Get a local handle to the thread.
|
|
//
|
|
|
|
InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
|
|
st = NtOpenThread(
|
|
&AppThread->HandleToThread,
|
|
DBGP_OPEN_APP_THREAD_ACCESS,
|
|
&Obja,
|
|
&AppThread->AppClientId
|
|
);
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
AppThread->HandleToThread = NULL;
|
|
}
|
|
|
|
//
|
|
// Get a local handle to the process.
|
|
//
|
|
|
|
InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
|
|
st = NtOpenProcess(
|
|
&AppProcess->DbgSrvHandleToProcess,
|
|
DBGP_OPEN_APP_PROCESS_ACCESS,
|
|
&Obja,
|
|
&AppThread->AppClientId
|
|
);
|
|
|
|
if ( !NT_SUCCESS(st) ) {
|
|
AppProcess->DbgSrvHandleToProcess = NULL;
|
|
}
|
|
|
|
//
|
|
// Insert process on its user interfaces app list
|
|
//
|
|
|
|
RtlEnterCriticalSection(&UserInterface->UserInterfaceLock);
|
|
|
|
InsertTailList(
|
|
&UserInterface->AppProcessListHead,
|
|
&AppProcess->AppLinks
|
|
);
|
|
|
|
//
|
|
// Insert process in app hash table
|
|
//
|
|
|
|
InsertTailList(
|
|
&DbgpAppProcessHashTable[DBGP_PROCESS_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)],
|
|
&AppProcess->HashTableLinks
|
|
);
|
|
|
|
//
|
|
// Insert thread in app hash table
|
|
//
|
|
|
|
InsertTailList(
|
|
&DbgpAppThreadHashTable[DBGP_THREAD_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)],
|
|
&AppThread->HashTableLinks
|
|
);
|
|
|
|
NtReleaseSemaphore(
|
|
UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock);
|
|
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
|
|
|
|
return DBG_REPLY_LATER;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsExitThread (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a thread is exiting.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_THREAD AppThread;
|
|
|
|
//
|
|
// Locate AppThread
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Verify that the thread is DbgIdle (i.e. we are expecting a state change)
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgIdle ) {
|
|
DbgPrint("Not Idle\n");
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
return DBG_APP_NOT_IDLE;
|
|
}
|
|
|
|
AppThread->CurrentState = DbgExitThreadStateChange;
|
|
AppThread->ContinueState = DbgExitThreadStateChange;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
return DBG_REPLY_LATER;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsExitProcess (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a process is exiting.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_THREAD AppThread;
|
|
|
|
//
|
|
// Locate AppThread
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Verify that the thread is DbgIdle (i.e. we are expecting a state change)
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgIdle ) {
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
return DBG_APP_NOT_IDLE;
|
|
}
|
|
|
|
AppThread->CurrentState = DbgExitProcessStateChange;
|
|
AppThread->ContinueState = DbgExitProcessStateChange;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
return DBG_REPLY_LATER;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsLoadDll (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a process has loaded a Dll.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_THREAD AppThread;
|
|
|
|
//
|
|
// Locate AppThread
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Verify that the thread is DbgIdle (i.e. we are expecting a state change)
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgIdle ) {
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
return DBG_APP_NOT_IDLE;
|
|
}
|
|
|
|
AppThread->CurrentState = DbgLoadDllStateChange;
|
|
AppThread->ContinueState = AppThread->CurrentState;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
return DBG_REPLY_LATER;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpSsUnloadDll (
|
|
IN PDBGP_SUBSYSTEM Subsystem,
|
|
IN OUT PDBGSS_APIMSG ApiMsg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a subsystem wants to
|
|
report that a process has unloaded a dll.
|
|
|
|
Arguments:
|
|
|
|
Subsystem - Supplies the address of the subsystem making the call
|
|
|
|
ApiMsg - Supplies the DbgSs API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
DBG_REPLY_LATER - Successful receipt of message. A reply will be
|
|
generated when a continue is received from Ui.
|
|
|
|
+ TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGP_APP_THREAD AppThread;
|
|
|
|
//
|
|
// Locate AppThread
|
|
//
|
|
|
|
AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->Subsystem = Subsystem;
|
|
|
|
RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Verify that the thread is DbgIdle (i.e. we are expecting a state change)
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgIdle ) {
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
return DBG_APP_NOT_IDLE;
|
|
}
|
|
|
|
AppThread->CurrentState = DbgUnloadDllStateChange;
|
|
AppThread->ContinueState = AppThread->CurrentState;
|
|
AppThread->LastSsApiMsg = *ApiMsg;
|
|
|
|
NtReleaseSemaphore(
|
|
AppThread->UserInterface->StateChangeSemaphore,
|
|
1,
|
|
NULL
|
|
);
|
|
|
|
RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock);
|
|
|
|
return DBG_REPLY_LATER;
|
|
}
|