676 lines
17 KiB
C
676 lines
17 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 - 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbguiapi.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the DbgUi APIs
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 23-Jan-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "smsrvp.h"
|
|
|
|
//
|
|
// Forward declarations.
|
|
//
|
|
|
|
NTSTATUS
|
|
DbgpCreateProcess(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGUI_CREATE_PROCESS CreateProcessInfo
|
|
);
|
|
|
|
NTSTATUS
|
|
DbgpCreateThread(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGUI_CREATE_THREAD CreateThread
|
|
);
|
|
|
|
NTSTATUS
|
|
DbgpLoadDll(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGKM_LOAD_DLL LoadDll
|
|
);
|
|
|
|
NTSTATUS
|
|
DbgpUiWaitStateChange (
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGUI_APIMSG ApiMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a user interface has waited
|
|
on its state change notification semaphore, and wants to
|
|
pickup a state change message.
|
|
|
|
Arguments:
|
|
|
|
UserInterface - Supplies the address of the user interface making the call
|
|
|
|
ApiMsg - Supplies the DbgUi API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - A state change occured and is available in the
|
|
ApiMsg.
|
|
|
|
DBG_NO_STATE_CHANGE - No state change was found for the calling
|
|
user interface.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS st;
|
|
PDBGP_APP_THREAD AppThread;
|
|
DBG_STATE PreviousState;
|
|
|
|
st = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Scan the user interface's app list looking for an
|
|
// app whose State is not DbgIdle or DbgReplyPending
|
|
//
|
|
|
|
AppThread = DbgpLocateStateChangeApp(UserInterface,&PreviousState);
|
|
|
|
if ( !AppThread ) {
|
|
return DBG_NO_STATE_CHANGE;
|
|
}
|
|
|
|
ApiMsg->u.WaitStateChange.NewState = PreviousState;
|
|
ApiMsg->u.WaitStateChange.AppClientId = AppThread->AppClientId;
|
|
|
|
switch ( PreviousState ) {
|
|
|
|
case DbgCreateThreadStateChange :
|
|
//
|
|
// Open the thread and Dup a handle over to the user
|
|
// interface.
|
|
//
|
|
|
|
st = DbgpCreateThread(
|
|
UserInterface,
|
|
AppThread,
|
|
&ApiMsg->u.WaitStateChange.StateInfo.CreateThread
|
|
);
|
|
break;
|
|
|
|
case DbgCreateProcessStateChange :
|
|
|
|
//
|
|
// Open the process, thread, and section, and Dup a handle
|
|
// over to the user interface.
|
|
//
|
|
|
|
st = DbgpCreateProcess(
|
|
UserInterface,
|
|
AppThread,
|
|
&ApiMsg->u.WaitStateChange.StateInfo.CreateProcessInfo
|
|
);
|
|
break;
|
|
|
|
case DbgExitThreadStateChange :
|
|
ApiMsg->u.WaitStateChange.StateInfo.ExitThread =
|
|
AppThread->LastSsApiMsg.u.ExitThread;
|
|
break;
|
|
case DbgExitProcessStateChange :
|
|
ApiMsg->u.WaitStateChange.StateInfo.ExitProcess =
|
|
AppThread->LastSsApiMsg.u.ExitProcess;
|
|
break;
|
|
|
|
case DbgLoadDllStateChange :
|
|
|
|
//
|
|
// Dup File handle to the user interface
|
|
//
|
|
|
|
st = DbgpLoadDll(
|
|
UserInterface,
|
|
AppThread,
|
|
&ApiMsg->u.WaitStateChange.StateInfo.LoadDll
|
|
);
|
|
break;
|
|
|
|
case DbgUnloadDllStateChange :
|
|
|
|
//
|
|
// Dup section handle to the user interface
|
|
//
|
|
|
|
ApiMsg->u.WaitStateChange.StateInfo.UnloadDll =
|
|
AppThread->LastSsApiMsg.u.UnloadDll;
|
|
break;
|
|
|
|
case DbgExceptionStateChange :
|
|
case DbgBreakpointStateChange :
|
|
case DbgSingleStepStateChange :
|
|
ApiMsg->u.WaitStateChange.StateInfo.Exception =
|
|
AppThread->LastSsApiMsg.u.Exception;
|
|
break;
|
|
|
|
default :
|
|
st = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgpCreateThread(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGUI_CREATE_THREAD CreateThread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called during the processing of a WaitStateChange
|
|
DbgUi API when the the state change for the App was
|
|
DbgCreateThreadStateChange.
|
|
|
|
This functions main purpose is to dup a handle to the thread into
|
|
the thread's controlling user interface.
|
|
|
|
Arguments:
|
|
|
|
UserInterface - Supplies the address of the thread's user interface.
|
|
|
|
AppThread - Supplies the address of the application thread.
|
|
|
|
CreateThread - Supplies the address of the create thread message that
|
|
is being returned to the user interface.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS st;
|
|
|
|
|
|
CreateThread->HandleToThread = NULL;
|
|
CreateThread->NewThread = AppThread->LastSsApiMsg.u.CreateThread;
|
|
|
|
//
|
|
// If handle to thread was successfully opened,
|
|
// then attempt to duplicate it into the user interface
|
|
//
|
|
|
|
if ( AppThread->HandleToThread ) {
|
|
try {
|
|
st = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
AppThread->HandleToThread,
|
|
UserInterface->DebugUiProcess,
|
|
&CreateThread->HandleToThread,
|
|
DBGP_DUP_APP_THREAD_ACCESS,
|
|
0L,
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
}
|
|
except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
st = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(st)){
|
|
st = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
CreateThread->HandleToThread = NULL;
|
|
AppThread->HandleToThread = NULL;
|
|
} else {
|
|
|
|
AppThread->HandleToThread = (HANDLE)((ULONG)CreateThread->HandleToThread | 1);
|
|
}
|
|
} else {
|
|
st = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpCreateProcess(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGUI_CREATE_PROCESS CreateProcessInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called during the processing of a WaitStateChange
|
|
DbgUi API when the the state change for the App was
|
|
DbgCreateProcessStateChange.
|
|
|
|
This functions main purpose is to dup a handle to the thread, its
|
|
process, and the process's section into the thread's controlling
|
|
user interface.
|
|
|
|
Arguments:
|
|
|
|
UserInterface - Supplies the address of the thread's user interface.
|
|
|
|
AppThread - Supplies the address of the application thread.
|
|
|
|
CreateProcessInfo - Supplies the address of the create process message that
|
|
is being returned to the user interface.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS st;
|
|
NTSTATUS ReturnStatus;
|
|
|
|
ReturnStatus = STATUS_SUCCESS;
|
|
|
|
CreateProcessInfo->HandleToThread = NULL;
|
|
CreateProcessInfo->HandleToProcess = NULL;
|
|
|
|
CreateProcessInfo->NewProcess = AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess;
|
|
|
|
CreateProcessInfo->NewProcess.FileHandle = NULL;
|
|
|
|
//
|
|
// If handle to thread was successfully opened,
|
|
// then attempt to duplicate it into the user interface
|
|
//
|
|
|
|
if ( AppThread->HandleToThread ) {
|
|
try {
|
|
st = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
AppThread->HandleToThread,
|
|
UserInterface->DebugUiProcess,
|
|
&CreateProcessInfo->HandleToThread,
|
|
DBGP_DUP_APP_THREAD_ACCESS,
|
|
0L,
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
}
|
|
except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
st = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(st)){
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
CreateProcessInfo->HandleToThread = NULL;
|
|
AppThread->HandleToThread = NULL;
|
|
} else {
|
|
AppThread->HandleToThread = (HANDLE)((ULONG)CreateProcessInfo->HandleToThread | 1);
|
|
}
|
|
} else {
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
}
|
|
|
|
//
|
|
// If handle to process was successfully opened,
|
|
// then attempt to duplicate it into the user interface
|
|
//
|
|
|
|
if ( AppThread->AppProcess->DbgSrvHandleToProcess ) {
|
|
st = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
AppThread->AppProcess->DbgSrvHandleToProcess,
|
|
UserInterface->DebugUiProcess,
|
|
&CreateProcessInfo->HandleToProcess,
|
|
DBGP_DUP_APP_PROCESS_ACCESS,
|
|
0L,
|
|
0L
|
|
);
|
|
|
|
if (!NT_SUCCESS(st)){
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
CreateProcessInfo->HandleToProcess = NULL;
|
|
AppThread->AppProcess->HandleToProcess = NULL;
|
|
} else {
|
|
|
|
AppThread->AppProcess->HandleToProcess =
|
|
CreateProcessInfo->HandleToProcess;
|
|
|
|
if ( AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess.FileHandle ) {
|
|
|
|
st = NtDuplicateObject(
|
|
AppThread->AppProcess->DbgSrvHandleToProcess,
|
|
AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess.FileHandle,
|
|
UserInterface->DebugUiProcess,
|
|
&CreateProcessInfo->NewProcess.FileHandle,
|
|
DBGP_DUP_APP_FILE_ACCESS,
|
|
0L,
|
|
0L
|
|
);
|
|
|
|
if (!NT_SUCCESS(st)){
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
CreateProcessInfo->NewProcess.FileHandle = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgpLoadDll(
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGP_APP_THREAD AppThread,
|
|
OUT PDBGKM_LOAD_DLL LoadDll
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called during the processing of a WaitStateChange
|
|
DbgUi API when the the state change for the App was
|
|
DbgLoadDllStateChange.
|
|
|
|
This functions main purpose is to dup a handle to file into the
|
|
thread's controlling user interface.
|
|
|
|
Arguments:
|
|
|
|
UserInterface - Supplies the address of the thread's user interface.
|
|
|
|
AppThread - Supplies the address of the application thread.
|
|
|
|
LoadDll - Supplies the address of the load dll message that
|
|
is being returned to the user interface.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS st;
|
|
NTSTATUS ReturnStatus;
|
|
|
|
ReturnStatus = STATUS_SUCCESS;
|
|
|
|
|
|
*LoadDll = AppThread->LastSsApiMsg.u.LoadDll;
|
|
|
|
st = NtDuplicateObject(
|
|
AppThread->AppProcess->DbgSrvHandleToProcess,
|
|
AppThread->LastSsApiMsg.u.LoadDll.FileHandle,
|
|
UserInterface->DebugUiProcess,
|
|
&LoadDll->FileHandle,
|
|
DBGP_DUP_APP_FILE_ACCESS,
|
|
0L,
|
|
0L
|
|
);
|
|
|
|
if (!NT_SUCCESS(st)){
|
|
ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE;
|
|
LoadDll->FileHandle = NULL;
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgpUiContinue (
|
|
IN PDBGP_USER_INTERFACE UserInterface,
|
|
IN OUT PDBGUI_APIMSG ApiMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a user interface has received
|
|
a state change message, and wants to continue one of its
|
|
application threads. Continuing translates into a reply
|
|
to an outstanding DbgSs API.
|
|
|
|
Arguments:
|
|
|
|
UserInterface - Supplies the address of the user interface making the call
|
|
|
|
ApiMsg - Supplies the DbgUi API message that contains the information
|
|
needed to complete this call.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
STATUS_INVALID_CID - An invalid ClientId was specified for the
|
|
AppClientId, or the specified Application was not waiting
|
|
for a continue.
|
|
|
|
STATUS_INVALID_PARAMETER - An invalid continue status was specified.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS st;
|
|
PDBGP_APP_THREAD AppThread;
|
|
PDBGUI_CONTINUE args;
|
|
DBGSRV_APIMSG ContinueMsg;
|
|
PDBGP_SUBSYSTEM Subsystem;
|
|
|
|
args = &ApiMsg->u.Continue;
|
|
|
|
//
|
|
// Make sure that Continue status is valid
|
|
//
|
|
|
|
switch (args->ContinueStatus) {
|
|
|
|
case DBG_EXCEPTION_HANDLED :
|
|
case DBG_EXCEPTION_NOT_HANDLED :
|
|
case DBG_TERMINATE_THREAD :
|
|
case DBG_TERMINATE_PROCESS :
|
|
case DBG_CONTINUE :
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
RtlEnterCriticalSection(&DbgpHashTableLock);
|
|
|
|
|
|
AppThread = DbgpIsAppInHashTable(&args->AppClientId);
|
|
|
|
if ( !AppThread ) {
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
Subsystem = AppThread->Subsystem;
|
|
|
|
//
|
|
// Now determine what type of continue this is. Depending on
|
|
// the threads continue state certain things need to happen.
|
|
// If we are continuing an exit thread or exit process, data
|
|
// structures need to be torn down, and handles in the user
|
|
// interface need to be closed.
|
|
//
|
|
|
|
RtlEnterCriticalSection(&UserInterface->UserInterfaceLock);
|
|
|
|
//
|
|
// Disallow continues on Apps that have not been picked up
|
|
// yet.
|
|
//
|
|
|
|
if ( AppThread->CurrentState != DbgReplyPending ) {
|
|
RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock);
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
return STATUS_INVALID_CID;
|
|
}
|
|
|
|
AppThread->CurrentState = DbgIdle;
|
|
|
|
DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,AppThread->LastSsApiMsg.ContinueKey);
|
|
ContinueMsg.ReturnedStatus = args->ContinueStatus;
|
|
|
|
switch (AppThread->ContinueState) {
|
|
|
|
//
|
|
// These involve data structure tear down
|
|
//
|
|
|
|
case DbgExitThreadStateChange :
|
|
|
|
//
|
|
// Try to close the handle to the thread that
|
|
// the user interface has.
|
|
//
|
|
|
|
if ( AppThread->HandleToThread ) {
|
|
try {
|
|
NtDuplicateObject(
|
|
AppThread->UserInterface->DebugUiProcess,
|
|
AppThread->HandleToThread,
|
|
NULL,
|
|
NULL,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
}
|
|
except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
;
|
|
}
|
|
}
|
|
AppThread->HandleToThread = NULL;
|
|
|
|
//
|
|
// delink the thread from its process, and deallocate it.
|
|
//
|
|
|
|
RemoveEntryList(&AppThread->AppLinks);
|
|
|
|
//
|
|
// Remove the thread from the thread hash table, and
|
|
// deallocate the thread
|
|
//
|
|
|
|
RemoveEntryList(&AppThread->HashTableLinks);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0,AppThread);
|
|
|
|
break;
|
|
|
|
case DbgExitProcessStateChange :
|
|
//
|
|
// Try to close the handle to the thread that
|
|
// the user interface has.
|
|
//
|
|
|
|
if ( AppThread->HandleToThread ) {
|
|
try {
|
|
st = NtDuplicateObject(
|
|
AppThread->UserInterface->DebugUiProcess,
|
|
AppThread->HandleToThread,
|
|
NULL,
|
|
NULL,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
}
|
|
except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
;
|
|
}
|
|
}
|
|
AppThread->HandleToThread = NULL;
|
|
|
|
//
|
|
// Try to close the handle to the process
|
|
// that we gave to the user interface
|
|
//
|
|
|
|
if ( AppThread->AppProcess->DbgSrvHandleToProcess ) {
|
|
try {
|
|
st = NtDuplicateObject(
|
|
AppThread->UserInterface->DebugUiProcess,
|
|
AppThread->AppProcess->HandleToProcess,
|
|
NULL,
|
|
NULL,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
}
|
|
except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
;
|
|
}
|
|
NtClose(AppThread->AppProcess->DbgSrvHandleToProcess);
|
|
}
|
|
|
|
//
|
|
// Remove the thread from the thread hash table,
|
|
// the process from the process hash table, and
|
|
// the process from its user interface.
|
|
//
|
|
|
|
RemoveEntryList(&AppThread->HashTableLinks);
|
|
RemoveEntryList(&AppThread->AppProcess->HashTableLinks);
|
|
RemoveEntryList(&AppThread->AppProcess->AppLinks);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0,AppThread->AppProcess);
|
|
RtlFreeHeap(RtlProcessHeap(), 0,AppThread);
|
|
|
|
break;
|
|
|
|
//
|
|
// No work needed
|
|
//
|
|
|
|
case DbgCreateThreadStateChange :
|
|
case DbgCreateProcessStateChange :
|
|
case DbgExceptionStateChange :
|
|
case DbgBreakpointStateChange :
|
|
case DbgSingleStepStateChange :
|
|
case DbgLoadDllStateChange :
|
|
case DbgUnloadDllStateChange :
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock);
|
|
RtlLeaveCriticalSection(&DbgpHashTableLock);
|
|
|
|
st = NtRequestPort(Subsystem->CommunicationPort, (PPORT_MESSAGE)&ContinueMsg);
|
|
ASSERT(NT_SUCCESS(st));
|
|
|
|
return st;
|
|
}
|