📄 kdctrl.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
kdctrl.c
Abstract:
This module implements CPU specific remote debug APIs.
Environment:
WinCE
--*/
#include "kdp.h"
#if defined(x86)
int __cdecl _inp(unsigned short);
int __cdecl _outp(unsigned short, int);
unsigned short __cdecl _inpw(unsigned short);
unsigned short __cdecl _outpw(unsigned short, unsigned short);
unsigned long __cdecl _inpd(unsigned short);
unsigned long __cdecl _outpd(unsigned short, unsigned long);
PVOID __inline GetRegistrationHead(void)
{
__asm mov eax, dword ptr fs:[0];
}
#pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpd)
#endif
BOOL fThreadWalk;
DWORD ReloadAllSymbols(LPBYTE lpBuffer, BOOL fDoCopy);
static NTSTATUS GetModuleRefCount(HMODULE hDll, LPVOID pBuffer, USHORT *pnLength);
BOOL CheckIfPThreadExists (PTHREAD pThreadToValidate)
{
DWORD dwProcessIdx;
PTHREAD pThread;
for (dwProcessIdx = 0; dwProcessIdx < MAX_PROCESSES; dwProcessIdx++)
{ // For each process:
if (kdProcArray [dwProcessIdx].dwVMBase)
{ // Only if VM Base Addr of process is valid (not null):
for (pThread = kdProcArray [dwProcessIdx].pTh; // Get process main thread
pThread;
pThread = pThread->pNextInProc) // Next thread
{ // walk list of threads attached to process (until we reach the end of the list or we found the matching pThread)
if (pThreadToValidate == pThread) return TRUE;
}
}
}
return FALSE;
}
VOID
KdpReadControlSpace (
IN DBGKD_COMMAND *pdbgkdCmdPacket,
IN PSTRING AdditionalData
)
/*++
Routine Description:
This function is called in response of a read control space command
message. Its function is to read implementation
specific system data.
Arguments:
pdbgkdCmdPacket - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Return Value:
None.
--*/
{
DBGKD_READ_MEMORY *a = &pdbgkdCmdPacket->u.ReadMemory;
STRING MessageHeader;
ULONG NextOffset;
DWORD dwReturnAddr;
DWORD dwFramePtr = 0;
DWORD dwStackPtr = 0;
DWORD dwProcHandle = 0;
MessageHeader.Length = sizeof(*pdbgkdCmdPacket);
MessageHeader.Buffer = (PCHAR)pdbgkdCmdPacket;
pdbgkdCmdPacket->dwReturnStatus = STATUS_UNSUCCESSFUL; // By default (shorter and safer)
//
// qwTgtAddress field is being used as the ControlSpace request id
//
switch (a->qwTgtAddress)
{
case HANDLE_PROCESS_THREAD_INFO_REQ: // Replacing HANDLE_PROCESS_INFO_REQUEST
GetProcessAndThreadInfo (AdditionalData);
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS; // the return status is in the message itself
break;
case HANDLE_GET_NEXT_OFFSET_REQUEST:
if (AdditionalData->Length != sizeof(ULONG)) {
AdditionalData->Length = 0;
break; // Unsucessful
}
memcpy((PVOID)&NextOffset, (PVOID)AdditionalData->Buffer, sizeof(ULONG));
if (!TranslateAddress(&NextOffset, g_pctxException)) {
AdditionalData->Length = 0;
break; // Unsucessful
}
memcpy((PVOID)AdditionalData->Buffer, (PVOID)&NextOffset, sizeof(ULONG));
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
AdditionalData->Length = sizeof(ULONG);
break;
case HANDLE_STACKWALK_REQUEST:
//
// Translate a stack frame address
//
DEBUGGERMSG(KDZONE_STACKW, (L"++ReadCtrl HANDLE_STACKWALK_REQUEST\r\n"));
if ((sizeof(DWORD) != AdditionalData->Length) &&
(2*sizeof(DWORD) != AdditionalData->Length) &&
(3*sizeof(DWORD) != AdditionalData->Length))
{
// Invalid argument
DEBUGGERMSG (KDZONE_ALERT, (L" ReadCtrl Bad AdditionalData Length (%i)\r\n", AdditionalData->Length));
AdditionalData->Length = 0;
}
else
{
memcpy((VOID*)&dwReturnAddr, (PVOID)AdditionalData->Buffer, sizeof(DWORD));
if (2*sizeof(DWORD) <= AdditionalData->Length)
{
memcpy((PVOID)&dwFramePtr, (PVOID)(AdditionalData->Buffer + sizeof(DWORD)), sizeof(DWORD));
DEBUGGERMSG (KDZONE_STACKW, (L" ReadCtrl dwFramePtr=%8.8lX\r\n", dwFramePtr));
}
else
{
dwFramePtr = 0;
}
DEBUGGERMSG (KDZONE_STACKW, (L" ReadCtrl Old RetAddr=%8.8lX\r\n", dwReturnAddr));
if (!TranslateRA (&dwReturnAddr, &dwStackPtr, dwFramePtr, &dwProcHandle))
{
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl TranslateRA FAILED\r\n"));
AdditionalData->Length = 0;
}
else
{
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl: New RetAddr=%8.8lX\r\n", dwReturnAddr));
if (dwStackPtr)
{
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl: New dwStackPtr=%8.8lX\r\n", dwStackPtr));
}
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl: New dwProcHandle=%8.8lX\r\n", dwProcHandle));
memcpy((PVOID)AdditionalData->Buffer, (PVOID)&dwReturnAddr, sizeof(DWORD));
AdditionalData->Length = sizeof(DWORD);
// Pass Previous SP
memcpy ((PVOID) (AdditionalData->Buffer + AdditionalData->Length), (PVOID)&dwStackPtr, sizeof(DWORD));
AdditionalData->Length += sizeof(DWORD);
memcpy ((PVOID) (AdditionalData->Buffer + AdditionalData->Length), (PVOID)&dwProcHandle, sizeof(DWORD));
AdditionalData->Length += sizeof(DWORD);
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
}
}
DEBUGGERMSG(KDZONE_STACKW, (L"--ReadCtrl HANDLE_STACKWALK_REQUEST\r\n"));
break;
case HANDLE_THREADSTACK_REQUEST:
//
// Set up a (thread-specific) stackwalk
//
DEBUGGERMSG(KDZONE_STACKW, (L"++ReadCtrl HANDLE_THREADSTACK_REQUEST\r\n"));
pWalkThread = (PTHREAD)Kdstrtoul(AdditionalData->Buffer, 0x10);
// Ensure pWalkThread is valid
if (!CheckIfPThreadExists(pWalkThread))
{
DEBUGGERMSG (KDZONE_ALERT, (L" ReadCtrl pWalkThread is invalid (%8.8lX)\r\n", (DWORD)pWalkThread));
AdditionalData->Length = 0;
}
else
{
fThreadWalk = TRUE;
g_fTopFrame = TRUE;
pStk = pWalkThread->pcstkTop;
pLastProc = pWalkThread->pProc;
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl pWalkThread=%8.8lX pLastProc=%8.8lX pStk=%8.8lX\r\n", pWalkThread, pLastProc, pStk));
//
// The thread's context will be returned in AdditionalData->Buffer
//
AdditionalData->Length = sizeof(CONTEXT);
if (pWalkThread == pCurThread)
{
memcpy(AdditionalData->Buffer, g_pctxException, sizeof(CONTEXT));
}
else
{
CpuContextToContext((CONTEXT*)AdditionalData->Buffer, &pWalkThread->ctx);
}
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl Context copied\r\n"));
//
// Slotize the PC if not in the kernel or a DLL
//
if (pLastProc)
{
if ((ZeroPtr(CONTEXT_TO_PROGRAM_COUNTER((PCONTEXT)AdditionalData->Buffer)) > (1 << VA_SECTION)) ||
(ZeroPtr(CONTEXT_TO_PROGRAM_COUNTER((PCONTEXT)AdditionalData->Buffer)) < (DWORD)DllLoadBase))
CONTEXT_TO_PROGRAM_COUNTER((PCONTEXT)AdditionalData->Buffer) =
(UINT)MapPtrProc(CONTEXT_TO_PROGRAM_COUNTER((PCONTEXT)AdditionalData->Buffer), pLastProc);
}
else
{
DEBUGGERMSG(KDZONE_STACKW, (L" ReadCtrl *** ERROR pLastProc is NULL\r\n"));
}
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
}
DEBUGGERMSG(KDZONE_STACKW, (L"--ReadCtrl HANDLE_THREADSTACK_REQUEST\r\n"));
break;
case HANDLE_THREADSTACK_TERMINATE:
//
// Terminate a (thread-specific) stackwalk
//
DEBUGGERMSG(KDZONE_STACKW, (L"++ReadCtrl HANDLE_THREADSTACK_TERMINATE\r\n"));
fThreadWalk = FALSE;
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
DEBUGGERMSG(KDZONE_STACKW, (L"--ReadCtrl HANDLE_THREADSTACK_TERMINATE\r\n"));
break;
case HANDLE_RELOAD_MODULES_REQUEST:
AdditionalData->Length = (WORD)ReloadAllSymbols( AdditionalData->Buffer, FALSE);
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
break;
case HANDLE_RELOAD_MODULES_INFO:
AdditionalData->Length = (WORD)ReloadAllSymbols( AdditionalData->Buffer, TRUE);
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
break;
case HANDLE_GETCURPROCTHREAD:
memcpy( AdditionalData->Buffer, &pCurProc, sizeof(DWORD));
memcpy( AdditionalData->Buffer+(sizeof(DWORD)), &pCurThread, sizeof(DWORD));
memcpy( AdditionalData->Buffer+(sizeof(DWORD)*2), &hCurProc, sizeof(DWORD));
memcpy( AdditionalData->Buffer+(sizeof(DWORD)*3), &hCurThread, sizeof(DWORD));
memcpy( AdditionalData->Buffer+(sizeof(DWORD)*4), &(pCurThread->pOwnerProc), sizeof(DWORD));
memcpy( AdditionalData->Buffer+(sizeof(DWORD)*5), &((PROCESS *)(pCurThread->pOwnerProc)->hProc), sizeof(DWORD));
AdditionalData->Length = sizeof(DWORD)*6;
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
break;
case HANDLE_GET_EXCEPTION_REGISTRATION:
#if defined(x86)
DEBUGGERMSG(KDZONE_CTRL, (L"++ReadCtrl HANDLE_GET_EXCEPTION_REGISTRATION\r\n"));
// This is only valid for x86 platforms!!! It is used
// by the kernel debugger for unwinding through exception
// handlers
if (AdditionalData->Length == 2*sizeof(VOID*))
{
CALLSTACK* pStack;
VOID* pRegistration;
VOID* pvCallStack = AdditionalData->Buffer+sizeof(VOID*);
memcpy(&pStack, pvCallStack, sizeof(VOID*));
if (pStack)
{
// we are at a PSL boundary and need to look up the next registration
// pointer -- don't trust the pointer we got from the host
pRegistration = (VOID*)pStack->extra;
pStack = pStack->pcstkNext;
}
else
{
// request for the registration head pointer
pRegistration = GetRegistrationHead();
pStack = pCurThread->pcstkTop;
}
memcpy(AdditionalData->Buffer, &pRegistration, sizeof(VOID*));
memcpy(pvCallStack, &pStack, sizeof(VOID*));
DEBUGGERMSG(KDZONE_CTRL, (L" ReadCtrl HANDLE_GET_EXCEPTION_REGISTRATION: Registration Ptr: %8.8lx pCallStack: %8.8lx\r\n", (DWORD)pRegistration, (DWORD)pStack));
// AdditionalData->Length stays the same (2*sizeof(VOID*))
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
}
else
{ // ERROR case!!!
DEBUGGERMSG (KDZONE_ALERT, (L" ReadCtrl HANDLE_GET_EXCEPTION_REGISTRATION: Invalid parameter.\r\n"));
}
#else
DEBUGGERMSG (KDZONE_ALERT, (L" ReadCtrl HANDLE_GET_EXCEPTION_REGISTRATION: Registration Head request not supported on this platform.\r\n"));
AdditionalData->Length = 0;
#endif
DEBUGGERMSG (KDZONE_CTRL, (L"--ReadCtrl HANDLE_GET_EXCEPTION_REGISTRATION\r\n"));
break;
case HANDLE_MODULE_REFCOUNT_REQUEST:
DEBUGGERMSG(KDZONE_CTRL, (L"++ReadCtrl HANDLE_MODULE_REFCOUNT_REQUEST\r\n"));
/* Sanity check... */
if (AdditionalData->Length != sizeof(HMODULE))
{
DEBUGGERMSG(KDZONE_CTRL, (L"--ReadCtrl HANDLE_MODULE_REFCOUNT_REQUEST\r\n"));
pdbgkdCmdPacket->dwReturnStatus = STATUS_INVALID_PARAMETER;
AdditionalData->Length = 0;
break;
}
pdbgkdCmdPacket->dwReturnStatus = GetModuleRefCount(*((HMODULE *) AdditionalData->Buffer), AdditionalData->Buffer, &AdditionalData->Length);
DEBUGGERMSG(KDZONE_CTRL, (L"--ReadCtrl HANDLE_MODULE_REFCOUNT_REQUEST\r\n"));
break;
case HANDLE_DESC_HANDLE_DATA:
pdbgkdCmdPacket->dwReturnStatus = KdQueryHandleFields((PDBGKD_HANDLE_DESC_DATA) AdditionalData->Buffer, AdditionalData->Length);
break;
case HANDLE_GET_HANDLE_DATA:
pdbgkdCmdPacket->dwReturnStatus = KdQueryHandleList((PDBGKD_HANDLE_GET_DATA) AdditionalData->Buffer, AdditionalData->Length);
break;
default:
pdbgkdCmdPacket->dwReturnStatus = STATUS_NOT_IMPLEMENTED;
AdditionalData->Length = 0;
break; // Unsuccessful
}
if (AdditionalData->Length > a->dwTransferCount) {
AdditionalData->Length = (USHORT)a->dwTransferCount;
}
a->dwActualBytesRead = AdditionalData->Length;
KdpSendKdApiCmdPacket (&MessageHeader, AdditionalData);
}
VOID
KdpWriteControlSpace (
IN DBGKD_COMMAND *pdbgkdCmdPacket,
IN PSTRING AdditionalData
)
/*++
Routine Description:
This function is called in response of a write control space command
message. Its function is to write implementation
specific system data.
Arguments:
pdbgkdCmdPacket - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Return Value:
None.
--*/
{
DBGKD_WRITE_MEMORY *a = &pdbgkdCmdPacket->u.WriteMemory;
STRING MessageHeader;
LPSTR Params;
HANDLE hProcessFocus;
MessageHeader.Length = sizeof(*pdbgkdCmdPacket);
MessageHeader.Buffer = (PCHAR)pdbgkdCmdPacket;
pdbgkdCmdPacket->dwReturnStatus = STATUS_UNSUCCESSFUL; // By default (shorter and safer)
//
// None of these commands actually write anything directly to memory
//
a->dwActualBytesWritten = 0;
DEBUGGERMSG(KDZONE_CTRL, (L"++KdpWriteControlSpace\r\n"));
switch (a->qwTgtAddress)
{
case HANDLE_PROCESS_SWITCH_REQUEST:
Params = AdditionalData->Buffer;
DEBUGGERMSG(KDZONE_CTRL, (L" KdpWriteControlSpace HANDLE_PROCESS_SWITCH_REQUEST %a\r\n", Params));
hProcessFocus = (HANDLE) Kdstrtoul(Params, 16); // we are getting hProc as a param
g_pFocusProcOverride = HandleToProc (hProcessFocus);
if (g_pFocusProcOverride)
{
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
}
DEBUGGERMSG(KDZONE_CTRL, (L" KdpWriteControlSpace g_pFocusProcOverride=0x%08X\r\n", g_pFocusProcOverride));
break;
case HANDLE_THREAD_SWITCH_REQUEST:
// Unsupported in CE
/*
Params = AdditionalData->Buffer;
Thread = Kdstrtoul(Params, 16);
if (!SwitchToThread((PTHREAD)Thread)) {
break; // Unsuccessful
}
pdbgkdCmdPacket->dwReturnStatus = STATUS_SUCCESS;
*/
break;
case HANDLE_STACKWALK_REQUEST:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -