如何使用Windbg命令查看CMap条目

时间:2018-06-13 13:49:56

标签: visual-studio windbg dump

在调查转储时,我偶然发现了一个CMap对象。这在Visual Studio中很容易调试,如下所示:

pThread->p<Class>->m_mapParameters.m_pHashTable,2741

其中2741是m_mapParameters CMap对象的m_nHashTableSize。

现在我已经尝试在Windbg中做同样的事情,但这不起作用。我唯一能做的就是:

dt pThread

然后,我开始点击,结果如下(只是自动生成的命令):

dx -r1 ((<application>!<Class> *)0x7f8e820)
dx -r1 (*((<application>!<Class> *)0x7f8e820)),nd
dx -r1 -n (*((<application>!<Class> *)0x7f8e820)),nd

然而,我陷入困境:没有办法(我发现)使用元素数量来获得CMap条目的完整列表。

有人知道是否有办法在Windbg(或Windbg预览)会话中获取CMap条目的完整列表?

提前致谢
多米尼克

2 个答案:

答案 0 :(得分:0)

当你说m_mapParameters是CMap对象时,你为什么要看pThread?

你可以使用dx m_mapParameters

下面是一个小示例代码,它在vs2017社区开发提示中编译的MFC最低应用程序中实现CMap,并在windbg中查看CMap

#define WINVER 0x501  // compiler warning for _WINNT_WINVER so adding winxp
#define _CRT_SECURE_NO_WARNINGS  // using sprintf which is deprecated
#include <afxwin.h>  
class CMainFrame : public CFrameWnd {
public: CMainFrame();
protected:
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    DECLARE_MESSAGE_MAP()
};
CMainFrame::CMainFrame() {
    Create(NULL, "MFC Test", WS_OVERLAPPEDWINDOW, CRect(120, 100, 700, 480), NULL);
}
class CMessagesApp : public CWinApp {
public: BOOL InitInstance();
};
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_KEYDOWN()
END_MESSAGE_MAP()
BOOL CMessagesApp::InitInstance() {
    m_pMainWnd = new CMainFrame; 
    m_pMainWnd->ShowWindow(SW_SHOW);m_pMainWnd->UpdateWindow();
    return TRUE;
}
CMessagesApp theApp;
CMap<UINT, UINT, CStringA, CStringA> myMap;  // global CMap Declaration
void CMainFrame::OnKeyDown(UINT nChar, UINT, UINT) {
    char buff[0x100] = { 0 }; char buffy[0x100] = { 0 };
    sprintf(buff, "you pressed %c \n", nChar);
    myMap[nChar] = CStringA(buff);  
    sprintf(buffy, "total number of keys is %d\n", myMap.GetSize());
    MessageBox(buffy);
}

编译执行按几个键盘键并将其附加到windbg

:\>cl /Zi /W4  /Ox /nologo /EHsc mfctest.cpp /link /nologo /subsystem:windows
mfctest.cpp

:\>mfctest.exe

:\>windbg -pn mfctest.exe

:\>

结果

0:001> dx mfctest!myMap
mfctest!myMap                 [Type: CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >]
    [=0x5c79bc] classCObject     : {"CObject"} [Type: CRuntimeClass]
    [+0x004] m_pHashTable     : 0x8d32b8 [Type: CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >::CAssoc * *]
    [+0x008] m_nHashTableSize : 0x11 [Type: unsigned int]
    [+0x00c] m_nCount         : 9 [Type: int]
    [+0x010] m_pFreeList      : 0x8dd958 [Type: CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >::CAssoc *]
    [+0x014] m_pBlocks        : 0x8dd8c0 [Type: CPlex *]
    [+0x018] m_nBlockSize     : 10 [Type: int]
0:001> dx mfctest!myMap.m_pHashTable[0]->value.m_pszData
mfctest!myMap.m_pHashTable[0]->value.m_pszData                 : 0x8cf808 : "you pressed U ." [Type: char *]

0:001> dx mfctest!myMap.m_nCount
mfctest!myMap.m_nCount : 9 [Type: int]

enter image description here

修改 这里是你如何转储CMap-&gt; pHashTable.values

此地图有26个键值对(a,b..z)
hashtablesize是默认的0x11(推荐的素数)

0:001> dt myMap
mfctest!myMap
   +0x000 __VFN_table : 0x0161b96c 
   =0161bba8 classCObject     : CRuntimeClass
   +0x004 m_pHashTable     : 0x002e0858  -> 0x002e0d30 CMap<cut>::CAssoc
   +0x008 m_nHashTableSize : 0x11
   +0x00c m_nCount         : 0n26
   +0x010 m_pFreeList      : 0x002e0d90 CMap<cut>::CAssoc
   +0x014 m_pBlocks        : 0x002e0d28 CPlex
   +0x018 m_nBlockSize     : 0n10

转储默认的pHashTables数组
下面的每个0x11 DWORD都是指向CMap :: CAssoc类型的pHashTable的指针 每个都可以有一个有效的pNext成员或null表示没有更多的条目

0:001> dd @@c++(myMap.m_pHashTable) L @@c++(myMap.m_nHashTableSize)
002e0858  002e0d30 002e0600 002e05d0 002e05a0
002e0868  002e0d80 002e0d50 002e0620 002e05f0
002e0878  002e05c0 002e0590 002e0d70 002e0d40
002e0888  002e0610 002e05e0 002e05b0 002e0950
002e0898  002e0d60

准备使用c ++表达式求值程序转储

0:001> $$ each of 0x11 dword are pointers to pHashTable and can have a valid pNext 
0:001> $$ lets c++ expressify the first array member
0:001> r? @$t0 = myMap.m_pHashTable[0]
0:001> ? @$t0
Evaluate expression: 3018032 = 002e0d30 <<<<< see the dump above
0:001> r? @$t0 = myMap.m_pHashTable[1]
0:001> ? @$t0
Evaluate expression: 3016192 = 002e0600 <<<<< see the dump above

0:001> $$ @$t0 represents the pHashTables and if you have sufficiently 
0:001> $$ big data m_nHashTableSize would be modified 

0:001> ?? myMap.m_nHashTableSize
unsigned int 0x11

0:001> $$ now that we have an expression that points to the first pHashTable 
0:001> we can iterate over the pNext and dump the keys

0:001> ? @$t0
Evaluate expression: 3016192 = 002e0600

转储实际条目

0:001> $$ we are going to iterate the second HashTable entries
0:001> .printf "%ma\n" , @@c++(@$t0->value.m_pszData)
you pressed R 

0:001> $$ choose the pNext if it exists
0:001> .printf "%ma\n" , @@c++(@$t0->pNext->value.m_pszData)
you pressed A 

0:001> .printf "%ma\n" , @@c++(@$t0->pNext->pNext->value.m_pszData)
Memory access error at 'm_pszData)'
0:001> ? @@c++(@$t0->pNext->pNext)
Evaluate expression: 0 = 00000000
0:001> $$ we reached the end so choose the next pHashTable and repeat the process
0:001> r? @$t0 = myMap.m_pHashTable[0]
0:001> ? @$t0
Evaluate expression: 3018032 = 002e0d30
0:001> $$ we are going to iterate the first HashTable entries
0:001> .printf "%ma\n" , @@c++(@$t0->value.m_pszData)
you pressed U 

0:001> .printf "%ma\n" , @@c++(@$t0->pNext->value.m_pszData)
you pressed D 

0:001> .printf "%ma\n" , @@c++(@$t0->pNext->pNext->value.m_pszData)
Memory access error at 'm_pszData)'

一个示例javascript代码,用于使用来自dt / v / t mfctest的类描述转储CMap条目以实例化CMap(int,int.CString,CString)!myMap

"use strict";
// usage !dumpcmap address
// typeDescription is copied from windbg dt /v /t myMap for this instantiation
// of CMap (int,int,CString,Cstring) myMap and pointerised 
function initializeScript() {
    return [new host.functionAlias(dump_CMap, "dumpcmap")];
}

function log(instr) {
    host.diagnostics.debugLog(instr + "\n")
}

function dump_CMap(input ) {
    var typeDescription = "(CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > > *)"
    var foo = host.evaluateExpression( typeDescription + input.toString() )
    for(var i =0; i< foo.m_nHashTableSize ; i ++) {
        log (foo.m_pHashTable[i].value)
        if(foo.m_pHashTable[i].pNext != 0) {
            log (foo.m_pHashTable[i].pNext.value)
        } 
    }
}

执行js的结果

0:001> ? myMap
Evaluate expression: 17889164 = 0110f78c
0:001> ?? myMap
class CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >
   +0x000 __VFN_table : 0x0108b96c 
   =0108bba8 classCObject     : CRuntimeClass
   +0x004 m_pHashTable     : 0x00325660  -> 0x00331460 CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >::CAssoc
   +0x008 m_nHashTableSize : 0x11
   +0x00c m_nCount         : 0n26
   +0x010 m_pFreeList      : 0x003314c0 CMap<unsigned int,unsigned int,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >,ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > >::CAssoc
   +0x014 m_pBlocks        : 0x00331458 CPlex
   +0x018 m_nBlockSize     : 0n10
0:001> .scriptload c:\wdscr\dump_cmap.js
JavaScript script successfully loaded from 'c:\wdscr\dump_cmap.js'
0:001> !dumpcmap 0x0110f78c
"you pressed U"
"you pressed D"
"you pressed R"
"you pressed A"
"you pressed O"
[object Object]
"you pressed L"
[object Object]
"you pressed Z"
"you pressed I"
"you pressed W"
"you pressed F"
"you pressed T"
"you pressed C"
"you pressed Q"
[object Object]
"you pressed N"
[object Object]
"you pressed K"
[object Object]
"you pressed Y"
"you pressed H"
"you pressed V"
"you pressed E"
"you pressed S"
"you pressed B"
"you pressed P"
[object Object]
"you pressed M"
[object Object]
"you pressed J"
[object Object]
"you pressed X"
"you pressed G"
@$dumpcmap(0x0110f78c)

答案 1 :(得分:0)

糟糕,这似乎是Windbg dt命令的标准功能:

Option           Description
======           ===========
-a[quantity]     Show each array element on a new line, with its index.
                 A total of quantity elements will be displayed.
                 There must be no space between the a and the quantity.
                 If -a is not followed by a digit, all items in the array are shown.
                 The -a[quantity] switch should appear immediately before each type name or
                 field name that you want displayed in this manner.

然而,虽然这个解释提到不需要元素的数量,但我已经看到过没有将数量导致显示元素太多的情况。

因此:

dt -a2741 pThread->p<Class>->m_mapParameters.m_pHashTable