//----------------------------------------------------------------------------- // // // File: fifqdbg.cpp // // Description: Implementation for CFifoQueueDbgIterator class. // // Author: Mike Swafford (MikeSwa) // // History: // 9/13/99 - MikeSwa Created // // Copyright (C) 1999 Microsoft Corporation // //----------------------------------------------------------------------------- #define _ANSI_UNICODE_STRINGS_DEFINED_ #include "aqincs.h" #ifdef PLATINUM #include "ptrwinst.h" #include "ptntdefs.h" #include "ptntintf.h" #else //PLATINUM #include "rwinst.h" #endif //PLATINUM #include #include #include #define MIN(x, y) ((x) > (y) ? (y) : (x)) //---[ GetQueueType ]---------------------------------------------------------- // // // Description: // Determines the queue type for a given ptr // Parameters: // hCurrentProcess Handle to the debuggee process // pvAddressOtherProc Addess of the DMQ in the debugee process // Returns: // AQ_QUEUE_TYPE_UNKNOWN Queue type cannot be determined // AQ_QUEUE_TYPE_FIFOQ Queue is a CFifoQ // AQ_QUEUE_TYPE_DMQ Queue is a CDestMsgQueue // AQ_QUEUE_TYPE_LMQ Queue is a CLinkMsgQueue // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- AQ_QUEUE_TYPE CQueueDbgIterator::GetQueueType(HANDLE hCurrentProcess, PVOID pvAddressOtherProc) { BYTE pbQueueBuffer[100]; ZeroMemory(pbQueueBuffer, sizeof(pbQueueBuffer)); if (!ReadMemory(pvAddressOtherProc, pbQueueBuffer, sizeof(pbQueueBuffer), NULL)) return AQ_QUEUE_TYPE_UNKNOWN; if (FIFOQ_SIG == ((CFifoQueue *)pbQueueBuffer)->m_dwSignature) return AQ_QUEUE_TYPE_FIFOQ; if (DESTMSGQ_SIG == ((CDestMsgQueue *)pbQueueBuffer)->m_dwSignature) return AQ_QUEUE_TYPE_DMQ; if (LINK_MSGQ_SIG == ((CLinkMsgQueue *)pbQueueBuffer)->m_dwSignature) return AQ_QUEUE_TYPE_LMQ; return AQ_QUEUE_TYPE_UNKNOWN; } #define pvGetNextPage(pvCurrent) ((PVOID) ((CFifoQueuePage *)pvCurrent)->m_pfqpNext) CFifoQueueDbgIterator::CFifoQueueDbgIterator(PWINDBG_EXTENSION_APIS pApis) { m_iCurrentPage = 0; m_iCurrentIndexInPage = 0; m_cPagesLoaded = 0; m_iHeadIndex = 0; m_iTailIndex = 0; pExtensionApis = pApis; ZeroMemory(m_pbQueueBuffer, sizeof(m_pbQueueBuffer)); }; CFifoQueueDbgIterator::~CFifoQueueDbgIterator() { PVOID pvCurrent = NULL; PVOID pvNext = NULL; pvCurrent = ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead; while (pvCurrent) { pvNext = pvGetNextPage(pvCurrent); free(pvCurrent); pvCurrent = pvNext; } } BOOL CFifoQueueDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc) { DWORD cbBytes = 0; PVOID pvPageOtherProc = NULL; PVOID pvPageThisProc = NULL; PVOID pvPreviousPageThisProc = NULL; //Read the entire queue structure in memory if (!ReadMemory(pvAddressOtherProc, m_pbQueueBuffer, sizeof(m_pbQueueBuffer), NULL)) return FALSE; //Iterate over the previous pointers from the head page pvPageOtherProc = ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead; ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead = NULL; while (pvPageOtherProc) { pvPageThisProc = malloc(sizeof(CFifoQueuePage)); if (!pvPageThisProc) return FALSE; if (pvPreviousPageThisProc) { ((CFifoQueuePage *)pvPreviousPageThisProc)->m_pfqpNext = (CFifoQueuePage *) pvPageThisProc; } else { ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead = (CFifoQueuePage *) pvPageThisProc; } if (!ReadMemory(pvPageOtherProc, pvPageThisProc, sizeof(CFifoQueuePage), NULL)) { if (pvPreviousPageThisProc) ((CFifoQueuePage *)pvPreviousPageThisProc)->m_pfqpNext = NULL; else ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead = NULL; free(pvPageThisProc); return FALSE; } if (!pvPreviousPageThisProc) { //This is the head page. save index m_iHeadIndex = (DWORD) ((DWORD_PTR) (((CFifoQueue *)m_pbQueueBuffer)->m_ppqdataHead - ((CFifoQueuePage *)pvPageOtherProc)->m_rgpqdata)); m_iCurrentIndexInPage = m_iHeadIndex; } //save tail index... in case this is the last page m_iTailIndex = (DWORD) ((DWORD_PTR) (((CFifoQueue *)m_pbQueueBuffer)->m_ppqdataTail - ((CFifoQueuePage *)pvPageOtherProc)->m_rgpqdata)); pvPreviousPageThisProc = pvPageThisProc; pvPageOtherProc = pvGetNextPage(pvPageThisProc); ((CFifoQueuePage *)pvPreviousPageThisProc)->m_pfqpNext = NULL; m_cPagesLoaded++; } return TRUE; } DWORD CFifoQueueDbgIterator::cGetCount() { return ((CFifoQueue *)m_pbQueueBuffer)->m_cQueueEntries; } PVOID CFifoQueueDbgIterator::pvGetNext() { PVOID pvCurrentPage = ((CFifoQueue *)m_pbQueueBuffer)->m_pfqpHead; PVOID pvData = NULL; DWORD i = 0; if (!pvCurrentPage) return NULL; //Loop over empty entries (left by DSN generation) or until //we reach the end of the queue do { //Figure out if we are on a page boundary if (FIFOQ_QUEUE_PAGE_SIZE == m_iCurrentIndexInPage) { m_iCurrentIndexInPage = 0; m_iCurrentPage++; } //Get current page for (i = 0; i < m_iCurrentPage; i++) { pvCurrentPage = pvGetNextPage(pvCurrentPage); if (!pvCurrentPage) return NULL; } if (!((CFifoQueuePage *)pvCurrentPage)->m_rgpqdata) return NULL; //Get data from current page pvData = ((CFifoQueuePage *)pvCurrentPage)->m_rgpqdata[m_iCurrentIndexInPage]; if ((m_iCurrentIndexInPage > m_iTailIndex) && !pvGetNextPage(pvCurrentPage)) { //We at the end of data return NULL; } m_iCurrentIndexInPage++; } while (!pvData); return pvData; } //---[ CDMQDbgIterator ]------------------------------------------------------- // // // Description: // Constructor for CDMQDbgIterator // Parameters: // pApis A ptr to the PWINDBG_EXTENSION_APIS struct passed in by // the debugger. // Returns: // - // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- CDMQDbgIterator::CDMQDbgIterator(PWINDBG_EXTENSION_APIS pApis) { ZeroMemory(m_pbDMQBuffer, sizeof(m_pbDMQBuffer)); ZeroMemory(m_pvFifoQOtherProc, sizeof(m_pvFifoQOtherProc)); ZeroMemory(m_szName, sizeof(m_szName)); m_pdmq = (CDestMsgQueue *)m_pbDMQBuffer; m_iCurrentFifoQ = 0; m_cCount = 0; pExtensionApis = pApis; m_cItemsReturnedThisQueue = 0; } //---[ CDMQDbgIterator::fInit ]------------------------------------------------ // // // Description: // Initializes the iterator (and the iterators for all its queues // Parameters: // hCurrentProcess Handle to the debuggee process // pvAddressOtherProc Addess of the DMQ in the debugee process // Returns: // TRUE on success // FALSE otherwise // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- BOOL CDMQDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc) { DWORD i = 0; PVOID pvQueue = NULL; BOOL fVerbose = TRUE && pExtensionApis; BYTE pbDomainEntry[sizeof(CDomainEntry)]; CDomainEntry *pdentry = (CDomainEntry *)pbDomainEntry; if (!ReadMemory(pvAddressOtherProc, m_pbDMQBuffer, sizeof(m_pbDMQBuffer), NULL)) { if (fVerbose) dprintf("ReadMemory failex 0x%X\n", GetLastError()); return FALSE; } if (DESTMSGQ_SIG != m_pdmq->m_dwSignature) { if (fVerbose) dprintf("Bad signature\n"); return FALSE; } //Get domain if possible if (ReadMemory(m_pdmq->m_dmap.m_pdentryDomainID, pbDomainEntry, sizeof(pbDomainEntry), NULL)) { ReadMemory(pdentry->m_szDomainName, m_szName, (DWORD)MIN((sizeof(m_szName)-1), (pdentry->m_cbDomainName+1)), NULL); } for (i = 0; i < NUM_PRIORITIES; i++) { m_rgfifoqdbg[i].SetApis(pExtensionApis); pvQueue = m_pdmq->m_rgpfqQueues[i]; m_pvFifoQOtherProc[i] = pvQueue; if (pvQueue) { if (!m_rgfifoqdbg[i].fInit(hCurrentProcess, pvQueue)) { if (fVerbose) dprintf("Cannot init queue %d at 0x%X\n", i, pvQueue); return FALSE; } m_cCount += m_rgfifoqdbg[i].cGetCount(); } } //Init retry queue m_rgfifoqdbg[NUM_PRIORITIES].SetApis(pExtensionApis); pvQueue = (((PBYTE)pvAddressOtherProc) + FIELD_OFFSET(CDestMsgQueue, m_fqRetryQueue)); m_pvFifoQOtherProc[NUM_PRIORITIES] = pvQueue; if (pvQueue) { if (!m_rgfifoqdbg[NUM_PRIORITIES].fInit(hCurrentProcess, pvQueue)) { if (fVerbose) dprintf("Cannon init retry queue at 0x%X\n", pvQueue); return FALSE; } m_cCount += m_rgfifoqdbg[NUM_PRIORITIES].cGetCount(); } return TRUE; } //---[ CDMQDbgIterator::pvGetNext ]-------------------------------------------- // // // Description: // Gets the next item from the DMQ // Parameters: // - // Returns: // An ptr to the item in the debuggee process on success // NULL when there are no more items // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- PVOID CDMQDbgIterator::pvGetNext() { PVOID pvItem = NULL; while (m_iCurrentFifoQ <= NUM_PRIORITIES) { if (m_pvFifoQOtherProc[m_iCurrentFifoQ]) { if (m_rgfifoqdbg[m_iCurrentFifoQ].cGetCount()) { pvItem = m_rgfifoqdbg[m_iCurrentFifoQ].pvGetNext(); //If we found an item we are done if (pvItem) { //If it is the first item annouce this queue if (!m_cItemsReturnedThisQueue && pExtensionApis) { dprintf("Dumping FifoQueue at address 0x%08X:\n", m_pvFifoQOtherProc[m_iCurrentFifoQ]); } m_cItemsReturnedThisQueue++; break; } } } m_iCurrentFifoQ++; m_cItemsReturnedThisQueue = 0; } return pvItem; } //---[ CQueueDbgIterator ]----------------------------------------------------- // // // Description: // Constructor for CQueueDbgIterator // Parameters: // pApis A ptr to the PWINDBG_EXTENSION_APIS struct passed in by // the debugger. // Returns: // - // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- CQueueDbgIterator::CQueueDbgIterator(PWINDBG_EXTENSION_APIS pApis) { pExtensionApis = pApis; m_pqdbgi = NULL; m_QueueType = AQ_QUEUE_TYPE_UNKNOWN; } //---[ CQueueDbgIterator::fInit ]---------------------------------------------- // // // Description: // Initialized generic queue iterator. Will determine the type // of queue and initialize the correct type-specific iterator. // Parameters: // hCurrentProcess Handle to the debuggee process // pvAddressOtherProc Addess of the DMQ in the debugee process // Returns: // TRUE on success // FALSE otherwise // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- BOOL CQueueDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc) { LPSTR szQueueType = "unknown"; m_QueueType = GetQueueType(hCurrentProcess, pvAddressOtherProc); switch (m_QueueType) { case AQ_QUEUE_TYPE_DMQ: m_pqdbgi = (IQueueDbgIterator *) &m_dmqdbg; szQueueType = "DMQ"; break; case AQ_QUEUE_TYPE_FIFOQ: m_pqdbgi = (IQueueDbgIterator *) &m_fifoqdbg; szQueueType = "CFifoQueue"; break; case AQ_QUEUE_TYPE_LMQ: m_pqdbgi = (IQueueDbgIterator *) &m_lmqdbg; szQueueType = "LMQ"; break; default: return FALSE; } if (!m_pqdbgi) return FALSE; m_pqdbgi->SetApis(pExtensionApis); if (!m_pqdbgi->fInit(hCurrentProcess, pvAddressOtherProc)) return FALSE; if (pExtensionApis) { dprintf("Dumping %s (%s) at address 0x%08X:\n", szQueueType, m_pqdbgi->szGetName(), pvAddressOtherProc); } return TRUE; } //---[ CQueueDbgIterator::cGetCount ]------------------------------------------ // // // Description: // Returns count of items in queue // Parameters: // - // Returns: // count of items in queue // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- DWORD CQueueDbgIterator::cGetCount() { if (!m_pqdbgi) return 0; else return m_pqdbgi->cGetCount(); } //---[ CQueueDbgIterator::pvGetNext ]------------------------------------------ // // // Description: // Returns the next item pointed to by the iterator // Parameters: // - // Returns: // Pointer to next item in debugee process on success // NULL if no more items or failure // History: // 10/21/1999 - MikeSwa Created // //----------------------------------------------------------------------------- PVOID CQueueDbgIterator::pvGetNext() { if (!m_pqdbgi) return NULL; else return m_pqdbgi->pvGetNext(); } //---[ CQueueDbgIterator::szGetName ]------------------------------------------ // // // Description: // Returns the name of the iterator // Parameters: // - // Returns: // Pointer to string for iterator // NULL if no name // History: // 10/22/1999 - MikeSwa Created // //----------------------------------------------------------------------------- LPSTR CQueueDbgIterator::szGetName() { if (!m_pqdbgi) return NULL; else return m_pqdbgi->szGetName(); } //---[ CLMQDbgIterator::CLMQDbgIterator ]-------------------------------------- // // // Description: // // Parameters: // // Returns: // // History: // 10/22/1999 - MikeSwa Created // //----------------------------------------------------------------------------- CLMQDbgIterator::CLMQDbgIterator(PWINDBG_EXTENSION_APIS pApis) { ZeroMemory(m_pbLMQBuffer, sizeof(m_pbLMQBuffer)); ZeroMemory(m_rgpvDMQOtherProc, sizeof(m_rgpvDMQOtherProc)); ZeroMemory(m_szName, sizeof(m_szName)); ZeroMemory(m_rgpvItemsPendingDelivery, sizeof(m_rgpvItemsPendingDelivery)); ZeroMemory(m_rgpvConnectionsOtherProc, sizeof(m_rgpvConnectionsOtherProc)); m_plmq = (CLinkMsgQueue *)m_pbLMQBuffer; m_iCurrentDMQ = 0; m_cCount = 0; m_cItemsThisDMQ = 0; m_cPending = 0; pExtensionApis = pApis; } //---[ CLMQDbgIterator::fInit ]------------------------------------------------ // // // Description: // Initializes iterator for CLinkMsgQueue // Parameters: // hCurrentProcess Handle to the debuggee process // pvAddressOtherProc Addess of the DMQ in the debugee process // Returns: // // History: // 10/22/1999 - MikeSwa Created // //----------------------------------------------------------------------------- BOOL CLMQDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc) { DWORD i = 0; PLIST_ENTRY pliCurrent = NULL; PLIST_ENTRY pliHead = NULL; BYTE pbConnection[sizeof(CSMTPConn)]; CSMTPConn *pConn = (CSMTPConn *)pbConnection; PVOID pvPending = NULL; PVOID pvConnOtherProc = NULL; BOOL fVerbose = TRUE && pExtensionApis; if (!ReadMemory(pvAddressOtherProc, m_pbLMQBuffer, sizeof(m_pbLMQBuffer), NULL)) { if (fVerbose) dprintf("ReadMemory failex 0x%X\n", GetLastError()); return FALSE; } if (LINK_MSGQ_SIG != m_plmq->m_dwSignature) { if (fVerbose) dprintf("Signature does not match\n"); return FALSE; } //Read in address of all the queues for this link //$$TODO - Support more than 1 quick list memcpy(m_rgpvDMQOtherProc, m_plmq->m_qlstQueues.m_rgpvData, sizeof(m_rgpvDMQOtherProc)); //Read in name of link ReadMemory(m_plmq->m_szSMTPDomain, m_szName, (DWORD)MIN((sizeof(m_szName)-1), (m_plmq->m_cbSMTPDomain+1)), NULL); for (i = 0; i < MAX_QUEUES_PER_LMQ; i++) { if (m_rgpvDMQOtherProc[i]) { m_rgdmqdbg[i].SetApis(pExtensionApis); if (!m_rgdmqdbg[i].fInit(hCurrentProcess, m_rgpvDMQOtherProc[i])) { if (fVerbose) dprintf("Unable to init DMQ at 0x%X\n", m_rgpvDMQOtherProc[i]); return FALSE; } m_cCount += m_rgdmqdbg[i].cGetCount(); } } //Get the messages pending on a connection pliCurrent = m_plmq->m_liConnections.Flink; //Loop through connections and save those with pending messages. while (pliHead != pliCurrent) { pvConnOtherProc = ((PBYTE) pliCurrent)-FIELD_OFFSET(CSMTPConn, m_liConnections); if (!ReadMemory(pvConnOtherProc, pbConnection, sizeof(pbConnection), NULL)) { break; } pliCurrent = pConn->m_liConnections.Flink; if (!pliHead) pliHead = pConn->m_liConnections.Blink; pvPending = pConn->m_dcntxtCurrentDeliveryContext.m_pmsgref; if (pvPending) { m_rgpvConnectionsOtherProc[m_cPending] = pvConnOtherProc; m_rgpvItemsPendingDelivery[m_cPending] = pvPending; m_cPending++; m_cCount++; } if (m_cPending >= MAX_CONNECTIONS_PER_LMQ) break; } return TRUE; } //---[ CLMQDbgIterator::pvGetNext ]-------------------------------------------- // // // Description: // Gets the next item in the current DMQ. Moves to next DMQ when that // is emtpy // Parameters: // - // Returns: // Next item on success // NULL when empty or failure // History: // 10/22/1999 - MikeSwa Created // //----------------------------------------------------------------------------- PVOID CLMQDbgIterator::pvGetNext() { PVOID pvItem = NULL; while (m_iCurrentDMQ < MAX_QUEUES_PER_LMQ) { if (m_rgpvDMQOtherProc[m_iCurrentDMQ]) { if (!m_cItemsThisDMQ && m_rgdmqdbg[m_iCurrentDMQ].cGetCount()) { if (pExtensionApis) { dprintf("Dumping DMQ (%s) at address 0x%08X:\n", m_rgdmqdbg[m_iCurrentDMQ].szGetName(), m_rgpvDMQOtherProc[m_iCurrentDMQ]); } } pvItem = m_rgdmqdbg[m_iCurrentDMQ].pvGetNext(); if (pvItem) { //Check if this is the first item for this DMQ m_cItemsThisDMQ++; break; } } m_iCurrentDMQ++; m_cItemsThisDMQ = 0; } //If the queues are empty, dump the connections if (!pvItem && m_cPending) { m_cPending--; if (pExtensionApis) { dprintf("Dumping Connection at address 0x%08X:\n", m_rgpvConnectionsOtherProc[m_cPending]); } pvItem = m_rgpvItemsPendingDelivery[m_cPending]; } return pvItem; }