📄 kdhandle.c
字号:
cBufFields = cFields;
else if (cBufFields < cFields)
status = STATUS_BUFFER_TOO_SMALL;
pHandleFields->out.cFields = cBufFields;
// Copy over fields
j = 0;
for(i = 0; i < lengthof(g_pGenericDesc) && cBufFields > 0; i++, j++, cBufFields--)
{
pHandleFields->out.pFieldDesc[j].nType = g_pGenericDesc[i].nType;
pHandleFields->out.pFieldDesc[j].nFieldId = g_pGenericDesc[i].nFieldId;
}
for(i = 0; i < pAPIDesc->cEntries && cBufFields > 0; i++, j++, cBufFields--)
{
pHandleFields->out.pFieldDesc[j].nType = pAPIDesc->pDesc[i].nType;
pHandleFields->out.pFieldDesc[j].nFieldId = pAPIDesc->pDesc[i].nFieldId;
}
CommonExit:
DEBUGGERMSG(KDZONE_HANDLEEX, (L"--KdQueryHandleFields\r\n"));
return status;
}
/*++
Routine Name:
KdQueryOneHandle
Routine Description:
This routine fetches information for a specific handle. To determine which
fields will be present in the data, use KdQueryHandleFields with pid=-1 and
api=1 << handle->pci->type.
Arguments:
hHandle - [in] Handle to query
pHandleBuffer - [out] Pointer to results buffer
nBufLen - [in] Length of pHandleBuffer buffer in bytes
Unlike other routines, this one does not expect the caller to fill out the
in structure in pHandleBuffer.
Return Value:
STATUS_SUCCESS Success
STATUS_INVALID_PARAMETER hHandle is invalid
STATUS_BUFFER_TOO_SMALL Insufficient buffer space
--*/
NTSTATUS KdQueryOneHandle(HANDLE hHandle, PDBGKD_HANDLE_GET_DATA pHandleBuffer, UINT nBufLen)
{
HDATA *phHandle = KdHandleToPtr(hHandle);
PCKD_API_DESC pAPIDesc;
UINT cFields, nMinLen;
if (phHandle == NULL)
return STATUS_INVALID_PARAMETER;
pAPIDesc = &g_pTypeMap[phHandle->pci->type];
cFields = lengthof(g_pGenericDesc) + pAPIDesc->cEntries;
nMinLen = sizeof(pHandleBuffer->out) + (sizeof(DBGKD_HANDLE_FIELD_DATA) * cFields);
if (nBufLen < nMinLen)
return STATUS_BUFFER_TOO_SMALL;
// This is a little tricky. The API filter causes handle-specific fields to
// show up. We don't need a PID filter. Limiting the buffer size causes
// only one handle to be returned. Setting the start point to the handle we
// want information on causes it to get information for our specific
// handle.
pHandleBuffer->in.nPIDFilter = -1;
pHandleBuffer->in.nAPIFilter = 1 << phHandle->pci->type;
pHandleBuffer->in.hStart = (HANDLE) phHandle;
return KdQueryHandleList(pHandleBuffer, nMinLen);
}
/*++
Routine Name:
KdQueryHandleList
Routine Description:
This routine traverses the kernel handle list. It returns in the buffer a
list of handles matching specific APIs or owned by specific processes.
Arguments:
pHandleBuffer - [in/out] Pointer to results buffer
nBufLen - [in] Length of pHandleBuffer buffer in bytes
The caller should fill out the "in" structure in pHandleBuffer according to
its description. The "out" structure is used to return results. See kdp.h
for more information about how this structure is used. If an error is
returned, the contents of pHandleBuffer are undefined.
The actual buffer size is allowed to vary, so use nBufLen to indicate the
size of pHandleBuffer (including headers).
Return Value:
STATUS_SUCCESS Success
STATUS_INVALID_PARAMETER pHandleBuffer.in.hStart is invalid
--*/
NTSTATUS KdQueryHandleList(PDBGKD_HANDLE_GET_DATA pHandleBuffer, UINT nBufLen)
{
HDATA *pCurHandle;
PDBGKD_HANDLE_FIELD_DATA pCurField;
PCKD_API_DESC pAPIDesc;
NTSTATUS status;
HDATA hTemp;
UINT32 nPIDFilter, nAPIFilter;
UINT i, j, cBufFields;
DEBUGGERMSG(KDZONE_HANDLEEX, (L"++KdQueryHandleList\r\n"));
// Not having buffer space for the headers is an error. We must have enough
// space for both input and output data!
if (nBufLen < sizeof(*pHandleBuffer))
{
status = STATUS_INVALID_PARAMETER;
goto CommonExit;
}
// Save some input parameters and zero the buffer
pCurHandle = (HDATA *) pHandleBuffer->in.hStart;
nPIDFilter = pHandleBuffer->in.nPIDFilter;
nAPIFilter = pHandleBuffer->in.nAPIFilter;
memset(pHandleBuffer, 0, nBufLen);
DEBUGGERMSG(KDZONE_HANDLEEX, (L" PID Mask: %08lX, API Mask: %08lX, Start=%08p\r\n",
nPIDFilter, nAPIFilter, pCurHandle));
// Compute number of DBGKD_HANDLE_FIELD_DATA entries in the buffer
cBufFields = (nBufLen - sizeof(pHandleBuffer->out)) / sizeof(DBGKD_HANDLE_FIELD_DATA);
DEBUGGERMSG(KDZONE_HANDLEEX, (L" Buffer (addr=%08p, length=%u) has room for %u fields\r\n", pHandleBuffer, nBufLen, cBufFields));
// NULL handle means start at the beginning
if (pCurHandle == NULL)
pCurHandle = (HDATA *) pHandleList->linkage.fwd;
// Test the waters...
if (KdpMoveMemory(&hTemp, pCurHandle, sizeof(HDATA)) < sizeof(HDATA))
{
status = STATUS_INVALID_PARAMETER;
goto CommonExit;
}
pHandleBuffer->out.cFields = 0;
for(i = 0; i < cBufFields; i++)
pHandleBuffer->out.pFields[i].fValid = 0;
// Seems like a valid pointer, so lets start blasting data.
pCurField = pHandleBuffer->out.pFields;
for(; pCurHandle != pHandleList; pCurHandle = (HDATA *) pCurHandle->linkage.fwd)
{
// Verify that handle matches both filters
if ((nPIDFilter & pCurHandle->lock) == 0 ||
(nAPIFilter & (1 << pCurHandle->pci->type)) == 0)
continue;
// Cache description of handle-specific data. If we're not doing
// handle-specific data, cache the NULL descriptor to simplify the
// processing code.
if ((nAPIFilter & (nAPIFilter - 1)) == 0 &&
pCurHandle->pci->type < lengthof(g_pTypeMap))
pAPIDesc = &g_pTypeMap[pCurHandle->pci->type];
else
pAPIDesc = &g_descNull;
// If we don't have enough space to process this handle, we'll come
// back to it.
if (cBufFields < (lengthof(g_pGenericDesc) + pAPIDesc->cEntries))
break;
for(i = 0, j = 0; i < lengthof(g_pGenericDesc); i++, j++)
KdHandleGetField(&pCurField[j], &g_pGenericDesc[i], pCurHandle);
// Skip app-specific data. This happens for instance on threads
// that die. The pointer is no longer valid, but the handle doesn't
// disappear while apps have a reference to it.
if (pAPIDesc->pfnValidateHandle(pCurHandle))
{
for(i = 0; i < pAPIDesc->cEntries; i++, j++)
KdHandleGetField(&pCurField[j], &pAPIDesc->pDesc[i], pCurHandle->pvObj);
}
// Now update buffer & length
i = (lengthof(g_pGenericDesc) + pAPIDesc->cEntries);
cBufFields -= i;
pCurField += i;
pHandleBuffer->out.cFields += i;
}
// We don't want to traverse the list all over again!
if (pCurHandle == pHandleList)
pCurHandle = NULL;
// We broke out on the current handle, so we should resume
pHandleBuffer->out.hContinue = (HANDLE) pCurHandle;
DEBUGGERMSG(KDZONE_HANDLEEX, (L" Next Handle: %08p\r\n", pCurHandle));
status = STATUS_SUCCESS;
CommonExit:
DEBUGGERMSG(KDZONE_HANDLEEX, (L"--KdQueryHandleList\r\n"));
return status;
}
/*++
Routine Name:
_CountTrailingZeros
Routine Description:
This is a clever function to extract the zero-based index of the
least-significant one bit in nMask. If we ever get an intrinsic for this,
this function should go away promptly.
Arguments:
nMask - [in] Bitmask to extract least-significant one from
Return Value:
Zero-based index of the least-significant one
--*/
#pragma warning(push)
#pragma warning(disable:4146)
static UINT _CountTrailingZeros(UINT32 nMask)
{
#if !_INTRINSIC_IS_SUPPORTED(_CountLeadingZeros)
nMask = (nMask & -nMask) - 1;
return (UINT) g_abCntLeadTbl32[((g_nCntLeadMagic32 * nMask) >> 27) & 0x1F];
#else
return ((sizeof(UINT32) * CHAR_BIT) - (_CountLeadingZeros(nMask & -nMask) + 1));
#endif /* !_INTRINSIC_IS_SUPPORTED(_CountLeadingZeros) */
}
#pragma warning(pop)
/*++
Routine Name:
KdHandleGetField
Routine Description:
This function interprets a KD_HANDLE_DESC and extracts the datum into a
DBGKD_HANDLE_FIELD_DATA structure.
Arguments:
pField - [out] Buffer that receives the datum
pDesc - [in] Description of datum to read
pvStruct - [in] Pointer to structure to read datum from
Return Value:
Zero-based index of the least-significant one
--*/
static void KdHandleGetField(PDBGKD_HANDLE_FIELD_DATA pField, PCKD_HANDLE_DESC pDesc, LPCVOID pvStruct)
{
UINT32 nData;
BOOL fSigned;
pField->nFieldId = pDesc->nFieldId;
if (pDesc->pfnReadField != NULL)
{
pField->nData = pDesc->pfnReadField(pvStruct);
}
else
{
// move pointer to field
pvStruct = (LPCVOID)((DWORD) pvStruct + pDesc->nOffset);
fSigned = (pDesc->nType == KD_FIELD_SINT ? TRUE : FALSE);
switch(pDesc->nSize)
{
case 1:
if (fSigned)
nData = (UINT32) *((signed __int8 *) pvStruct);
else
nData = (UINT32) *((unsigned __int8 *) pvStruct);
break;
case 2:
if (fSigned)
nData = (UINT32) *((signed __int16 *) pvStruct);
else
nData = (UINT32) *((unsigned __int16 *) pvStruct);
break;
case 4:
if (fSigned)
nData = (UINT32) *((signed __int32 *) pvStruct);
else
nData = (UINT32) *((unsigned __int32 *) pvStruct);
break;
default:
CODE_NEVER_REACHED();
}
pField->nData = nData;
}
pField->fValid = 1;
}
static BOOL KdDontValidate(HDATA *ph)
{
return TRUE;
}
static BOOL KdValidateThread(HDATA *ph)
{
PROCESS *pProc;
THREAD *pThread;
UINT32 nRefKey;
for(nRefKey = ph->lock; nRefKey != 0; nRefKey &= (nRefKey - 1))
{
pProc = &kdProcArray[_CountTrailingZeros(nRefKey)];
for(pThread = pProc->pTh; pThread != NULL; pThread = pThread->pNextInProc)
{
if (pThread->hTh == ph->hValue)
return TRUE;
}
}
return FALSE;
}
static BOOL KdValidateProcess(HDATA *ph)
{
UINT i;
for(i = 0; i < MAX_PROCESSES; i++)
{
if (kdProcArray[i].hProc == ph->hValue)
return TRUE;
}
return FALSE;
}
static UINT32 KdReadGlobalRefCount(HANDLE hHandle)
{
const HDATA *pHandle = (const HDATA *) hHandle;
UINT i, c;
// typedef union REFINFO
// {
// ulong count;
// FULLREF *pFr;
// } REFINFO;
//
// When count < 0x10000, the handle is owned by 1 process and the count
// corresponds to the reference count in that process. When
// count >= 0x10000, the pFr field is used for reference counting.
if (pHandle->ref.count < 0x10000)
return pHandle->ref.count;
// Sum up the number of references in each process
c = 0;
for(i = 0; i < MAX_PROCESSES; i++)
c += pHandle->ref.pFr->usRefs[i];
return c;
}
static UINT32 KdReadHandleType(PCVOID pvData)
{
UINT nType = ((const HDATA *) pvData)->pci->type;
if (nType == HT_CRITSEC)
return (UINT32) L"Crit Sec";
else if (nType == HT_MANUALEVENT)
return (UINT32) L"Manual Event";
else if (nType < lengthof(g_apszHandleTypeNames))
return (UINT32) g_apszHandleTypeNames[nType];
DEBUGGERMSG(KDZONE_HANDLEEX, (L" KdReadHandleType: hHandle=%08lX, unknown type=%u\r\n", pvData, nType));
return (UINT32) L"?";
}
static UINT32 KdReadHandleName(PCVOID pvData)
{
const HDATA *phHandle = (const HDATA *) pvData;
switch(phHandle->pci->type)
{
case HT_EVENT:
{
const EVENT *pEvent = (const EVENT *) phHandle->pvObj;
return (UINT32)(pEvent->name == NULL ? NULL : pEvent->name->name);
}
case HT_MUTEX:
{
const MUTEX *pMutex = (const MUTEX *) phHandle->pvObj;
return (UINT32)(pMutex->name == NULL ? NULL : pMutex->name->name);
}
case HT_SEMAPHORE:
{
const SEMAPHORE *pSem = (const SEMAPHORE *) phHandle->pvObj;
return (UINT32)(pSem->name == NULL ? NULL : pSem->name->name);
}
case SH_CURPROC:
return (UINT32)((PROCESS *) phHandle->pvObj)->lpszProcName;
default:
return (UINT32) L"";
}
}
static UINT32 KdReadThreadPID(PCVOID pvData)
{
return (UINT32)(((const THREAD *) pvData)->pOwnerProc->procnum);
}
static UINT32 KdReadMutexOwner(PCVOID pvData)
{
return (UINT32)(((const MUTEX *) pvData)->pOwner->hTh);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -