如何基于WinDbg扩展中的转储文件内存创建对象?
我在一个大型应用程序上工作,经常使用WinDbg来诊断基于客户的DMP文件的问题。我已经为WinDbg写了一些小扩展,这些扩展已经证明对于从DMP文件中提取信息位非常有用。在我的扩展代码中,我发现自己以相同的方式反复引用C++类对象,一次又一次地,手动。例如:如何基于WinDbg扩展中的转储文件内存创建对象?
Address = GetExpression("somemodule!somesymbol");
ReadMemory(Address, &addressOfPtr, sizeof(addressOfPtr), &cb);
// get the actual address
ReadMemory(addressOfObj, &addressOfObj, sizeof(addressOfObj), &cb);
ULONG offset;
ULONG addressOfField;
GetFieldOffset("somemodule!somesymbolclass", "somefield", &offset);
ReadMemory(addressOfObj+offset, &addressOfField, sizeof(addressOfField), &cb);
行之有效,但我已经写了更多的扩展,具有更强大的功能(和访问我们的应用DMP文件的更多复杂的对象),我渴望一个更好的解决方案。我当然可以访问我们自己的应用程序的源代码,所以我认为应该有一种方法可以将对象从DMP文件中复制出来,并使用该内存在调试器扩展中创建一个实际对象,以便我可以调用函数通过链接来自我们的应用程序的DLL)。这可以帮助我省去手工从DMP中取出东西的麻烦。
这甚至可能吗?我尝试了一些显而易见的事情,例如在扩展中创建一个新对象,然后直接从DMP文件中用一个大的ReadMemory覆盖它。这似乎将数据放在正确的字段中,但是当我试图调用一个函数时却吓坏了。我想我失去了一些东西......也许C++拉了一些我不知道的vtable时髦性?我的代码看起来与此类似:
SomeClass* thisClass = SomeClass::New();
ReadMemory(addressOfObj, &(*thisClass), sizeof(*thisClass), &cb);
后续:它看起来像从EngExtCpp可能ExtRemoteTyped是我想要的吗?有没有人成功使用过这个?我需要谷歌了一些示例代码,但没有多少运气。
跟帖2:我追求这一调查的两种不同的路线。
1)我期待到ExtRemoteTyped,但现在看来这个类是真的只是为ReadMemory/GetFieldOffset调用一个帮手。是的,这将有助于加快ALOT的速度,但对于从DMP文件重新创建对象并没有什么帮助。尽管文档很渺茫,所以我可能会误解某些东西。 2)我也在考虑尝试使用ReadMemory来使用DMP文件中的数据覆盖在扩展中创建的对象。但是,我并没有像上面那样使用sizeof(* thisClass),而是认为我只会挑选出数据元素,并保持vtable不变。
有趣的想法,但这只会对最简单的对象的工作的希望。例如,如果对象包含指向其他对象(或vtable)的指针或引用,则这些对象不会很好地复制到新的地址空间。
但是,您可能会得到一个“代理”对象来工作,当您调用代理方法时,他们会对ReadMemory()
进行适当的调用以获取信息。这听起来是相当不错的工作,而且我认为对于您想要代理的每个类而言,它必须是或多或少的自定义代码集。这可能有更好的办法,但那是我头顶的东西。
是的,我在想同样的事情。我认为指针不能很好地工作,除非我使用ReadMemory跟随指针并复制了这些数据。但是我仍然可以在课堂上调用函数,不是吗?你的意思是关于vtables不能很好地复制? – pj4533 2010-04-04 14:30:22
@ pj4533:你可能可以在类上调用函数,但是如果类包含指针或引用,那么这些函数将会找到一个非常糟糕的对象。你可能会摆脱你在POD类和其他一些简单的类中所做的事情,但它会是非常可怕的东西。当然,您需要确保您构建调试器扩展的方式使对象布局相同。 – 2010-04-04 22:24:31
@ pj4533:通过vtables不能很好地复制,我的意思是任何具有虚函数的类中的vtable指针。它指向的是什么相当于一个函数跳转表,并且该表的位置将在调试对象和调试器进程中的不同地址处。 – 2010-04-04 22:26:27
我知道越来越内存转储一向以获取用于诊断的方式,但它的ETW更多的方便,你得到的调用栈,其中包括信息的系统调用和用户代码沿着信息。 MS一直在为包括Windows和VS.NET在内的所有产品做到这一点。
这是调试的一种非侵入性的方式。我已经做了相同的调试很长时间,现在用ETW,我能够解决大多数客户问题,而无需在调试器中花费大量时间。这是我的两分钱。
我真的没有学到很多关于Windows事件跟踪的知识。它似乎需要大量代码修改(添加对事件跟踪日志API的调用)?对于我们的应用程序的所有不同版本来说,这是不可能的,更不用说我们现在仍然支持的多个旧版本! – pj4533 2010-04-04 20:22:55
我刚刚听完我的初始预感,并将dmp文件中的数据复制到一个新对象中。
class SomeClassRemote : public SomeClass
{
protected:
SomeClassRemote (void);
SomeClassRemote (ULONG inRemoteAddress);
public:
static SomeClassRemote * New(ULONG inRemoteAddress);
virtual ~SomeClassRemote (void);
private:
ULONG m_Address;
};
并在实施:我通过使远程包装对象作出这样这更好
SomeClassRemote::SomeClassRemote (ULONG inRemoteAddress)
{
ULONG cb;
m_Address = inRemoteAddress;
// copy in all the data to the new object, skipping the virtual function tables
ReadMemory(inRemoteAddress + 0x4, (PVOID) ((ULONG)&(*this) +0x4), sizeof(SomeClass) - 4, &cb);
}
SomeClassRemote::SomeClassRemote(void)
{
}
SomeClassRemote::~SomeClassRemote(void)
{
}
SomeClassRemote* SomeClassRemote::New(ULONG inRemoteAddress)
{
SomeClassRemote*x = new SomeClassRemote(inRemoteAddress);
return (x);
}
这是基础,但后来我根据需要添加特定的覆盖,以抓住从更多信息dmp文件。这种技术允许我将这些新的远程对象传回原始源代码中,以便在各种实用功能中处理,因为它们是从原始类派生的。
确实像我这样的SEEMS应该能够以某种方式进行templatize ......但似乎总有某种原因,每个类的实现方式稍有不同,例如一些更复杂的对象有一对vtables,必须跳过。
伟大的问题PJ! – 2010-04-04 21:52:01