3

我有一个烦人的问题Pykd.pyd:我在脚本中使用它,启动了几个DbgCommand函数,比如:

DbgCommand("dt 0x000000eab8748430 CMap<int,int,CUIntArray *,CUIntArray *> m_nCount")

这用于获取CMap对象的大小。由于这是在脚本中完成的,使用了大量的对象,我在Windbg(菜单editOpen/Close Log File)中使用日志文件,这里有一个问题:
Windbg窗口中查看这个时,我只看到DbgCommand调用的结果,但在日志文件中我也看到了命令本身:

Windbg窗户:

000000eab87488f0    CMap<int,int,CUIntArray *,CUIntArray *>  Size:[0]  // formatted DbgCommand result
000000eab8748930    CMap<int,int,CUIntArray *,CUIntArray *>  Size:[0]  // formatted DbgCommand result

日志文件:

dt 0x000000eab87488f0 CMap<int,int,CUIntArray *,CUIntArray *> m_nCount // DbgCommand command
000000eab87488f0    CMap<int,int,CUIntArray *,CUIntArray *>  Size:[0]  // formatted DbgCommand result
dt 0x000000eab8748930 CMap<int,int,CUIntArray *,CUIntArray *> m_nCount // DbgCommand command
000000eab8748930    CMap<int,int,CUIntArray *,CUIntArray *>  Size:[0]  // formatted DbgCommand result

如何避免DbgCommand将命令写入日志文件?

同时我发现suppressoutput存在一个参数,可以用来在屏幕上不显示命令的结果,但这不是我的意思,你可以在下面的摘录中看到:

测试脚本摘录:

dprintln("1 : x /2 <application_name>!CStringList::CStringList, true")
dbgCommand("x /2 <application_name>!CStringList::CStringList", True)
dprintln("2 : x /2 <application_name>!CStringList::CStringList, false")
dbgCommand("x /2 <application_name>!CStringList::CStringList", False)
dprintln("3")

屏幕上的结果:

1 : x /2 <application_name>!CStringList::CStringList, true
2 : x /2 <application_name>!CStringList::CStringList, false
004b6d3e          <application_name>!CStringList::CStringList
3

结果在日志文件中:

1 : x /2 <Application>!CStringList::CStringList, true
x /2 <Application>!CStringList::CStringList
004b6d3e          <Application>!CStringList::CStringList
2 : x /2 <Application>!CStringList::CStringList, false
x /2 <Application>!CStringList::CStringList
004b6d3e          <Application>!CStringList::CStringList
3

这似乎suppressoutput是为了不在DbgCommand屏幕上显示结果,而我有兴趣不在DbgCommand日志中显示输入。

让我解释一下typedvar解决方案有什么问题:

由于某些奇怪的原因,CMap对象CArray不能以简单的方式(标准windbg命令)使用,如您在此处看到的:

0000000000335e90    <application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int>

如您所见,dt不适用于此:

dt 0x0000000000335e90 <application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int>
Symbol <application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int> not found

这可以通过删除<application_name>and来处理__ptr64(不要忘记空格):

0:000> dt 0x0000000000335e90 CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const *,int,int>
<application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const *,int,int>
   +0x000 __VFN_table : 0x00000001`3fc77ac8 
   +0x008 m_pHashTable     : (null) 
   +0x010 m_nHashTableSize : 0x11
   +0x018 m_nCount         : 0n0
   +0x020 m_pFreeList      : (null) 
   +0x028 m_pBlocks        : (null) 
   +0x030 m_nBlockSize     : 0n10

这似乎与以下x /2 *!*结果相对应:

00000001`3fc77ac8 <application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int>::`vftable'

但是,如果我尝试使用typedVar它似乎不起作用:

if type_name.find("CMap<") != -1:
    dprintln("original type name : [%s]" % type_name)
    dprintln(("pointer : [0x" + pointer_format + "]") % ptr)
    var =  typedVar(type_name, ptr) # before translation of __ptr64
    nieuwe_grootte1 = var.m_nCount
    type_name = type_name.replace(application_name + "!","") # Normally type_name starts with "<application_name>!CMap<...", it must become "CMap<..."
    type_name = type_name.replace(" __ptr64","")             # apparently, when the CMap definition contains __ptr64, it doesn't work
                                                             # dt 0x000000eab8748430 CMap<int,int,CUIntArray *,CUIntArray *> m_nCount seems to work

    dprintln("after replacements type name : [%s]" % type_name)
    var =  typedVar(type_name, ptr) # after translation of __ptr64
    nieuwe_grootte2 = var.m_nCount

    grootte_result = dbgCommand(("dt 0x" + pointer_format + " %s m_nCount") % (ptr,type_name)).split(' : ')
    grootte = grootte_result[-1].split('\n')[0] # list[-1] is Python for "take the last entry of a list"
    grootte = grootte.replace("0n","")
    dprintln((pointer_format + "\t%s\t Size:[%s, %d, %d]") % (ptr, type_name, grootte, nieuwe_grootte1, nieuwe_grootte2))

这给出了以下结果:

original type name : [<application_name>!CMap<unsigned int,unsigned int,enum CService::PARAMETER_TYPE,enum CService::PARAMETER_TYPE>]
pointer : [0x00000000003355e0]
after replacements type name : [CMap<unsigned int,unsigned int,enum CService::PARAMETER_TYPE,enum CService::PARAMETER_TYPE>]
00000000003355e0    CMap<unsigned int,unsigned int,enum CService::PARAMETER_TYPE,enum CService::PARAMETER_TYPE>  Size:[105, 105, 105]
original type name : [<application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int>]
pointer : [0x0000000000335640]

Traceback (most recent call last):

  File "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\heap_stat_extra.py", line 215, in <module>
    var =  typedVar(type_name, ptr) # before translation of __ptr64

TypeException: <application_name>!CMap<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >,wchar_t const * __ptr64,int,int> : invalid type name

我已经尝试删除<application_name>和/或__ptr64但似乎无法解决问题。此外,dtand "x /2 ! " (格式不正确)的结果清楚地表明所提到的类型存在。typedVar处理__ptr64标签似乎有真正的问题。有解决方法吗?

编辑
我刚刚尝试过,使用来自 pykd_team 的 Python 命令,但它似乎仍然不起作用(这次是在CArray对象上),如您所见:

启动我的脚本会产生以下结果:

  File "C:\Temp_Folder\blabla\heap_stat_logs_backup.py", line 232, in <module>
    collection_Size = typedVar(type_name, ptr).m_nCount

TypeException: CArray<CSyncRules::VersionRestriction *,CSyncRules::VersionRestriction * const &> : invalid type name

试图调查什么是正确的类名:

0:000> !py
Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> app = pykd.module("<Application>")
>>> for tp in app.enumTypes("*CArray*"):
...   print tp
... 
CArray<CSyncRules::VersionRestriction *,CSyncRules::VersionRestriction * const &>
...

如您所见,类名是完全匹配的,但还有一个TypeException. 你知道现在该怎么做吗?(顺便说一句,我正在使用 Visual Studio Professional 2017)

新编辑

该问题很可能是由 PYKD 引起的,无法处理*类型定义中的星号 ( )。为了避免上述问题,我可以使用任何转义字符吗?

4

3 回答 3

1

使用 pykd.typedVar 类。它专为此类情况而设计

于 2017-12-14T19:10:10.173 回答
0

尝试改变:

dt 0x000000eab87488f0 CMap<int,int,CUIntArray *,CUIntArray *> m_nCount

至:

var =  typedVar("CMap<int,int,CUIntArray *,CUIntArray *>", 0x000000eab87488f0 )
print var
print var.m_nCount
print var.m_nCount * 2

您可以访问 CMap 类的任何字段并使用它,因为它们是自然的 python 类型

如果您要多次获取 typedVar,您可以缓存类型信息以避免性能问题:

CMap = typeInfo("CMap<int,int,CUIntArray *,CUIntArray *>")
var = typedVar( CMap, 0x000000eab87488f0 )
于 2017-12-15T09:26:50.327 回答
0

尝试为您的模块枚举类型(使用通配符掩码)并找到 CMap 的确切符号名称。

app = pykd.module("<application_name>")
for tp in app.enumTypes("CMap*"):
   print tp

我可以尝试在一个小示例中重现问题,但我需要知道您的 Visual Studio 版本。

于 2018-01-09T08:58:42.940 回答