我在大型应用程序上工作,并经常使用WINDBG根据客户的DMP文件来诊断问题。我为WindBG编写了一些小型扩展,这些扩展名对于从DMP文件中抽出一些信息非常有用。在我的扩展代码中,我发现自己以相同的方式一遍又一遍地手动地使用C ++类对象。例如:

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文件中访问更复杂的对象),我渴望获得更好的解决方案。我当然可以访问我们自己应用程序的源通过在我们的应用程序中链接DLL中的链接)。这将为我节省将东西手工从DMP中抽出的麻烦。

这甚至可能吗?我尝试了明显的事情,例如在扩展程序中创建一个新对象,然后直接从DMP文件中用大型读书记录覆盖它。这似乎将数据放在正确的字段中,但是当我尝试调用函数时,数据吓坏了。我认为我缺少一些东西...也许C ++拉了一些我不知道的VTable Funky-ness?我的代码看起来与此相似:

SomeClass* thisClass = SomeClass::New();
ReadMemory(addressOfObj, &(*thisClass), sizeof(*thisClass), &cb);

后续:我想要的是从engextCPP中进行极端型号?有人成功使用过吗?我需要搜索一些示例代码,但没有太多运气。

后续2:我正在对此进行两种不同的调查途径。
1)我正在研究ExtremoteTyped,但看来此类实际上只是ReadMemory/GetFieldOffset呼叫的助手。是的,这将有助于加快速度,但是在从DMP文件中重新创建对象时并没有真正的帮助。尽管文档很苗条,所以我可能会误解一些东西。 2)我还希望尝试使用redmemory用DMP文件中的数据覆盖我在扩展中创建的对象。但是,我没有像上面使用sizeof(*thisclass),而是想我只会挑选数据元素,然后将VTABLES不变。

有帮助吗?

解决方案

有趣的想法,但这将希望只能在最简单的对象上工作。例如,如果对象包含对其他对象(或VTABLES)的指示或引用,则这些对象不会很好地复制到新的地址空间。

但是,您也许可以获得一个“代理”对象来工作,当您调用代理方法时,他们会拨打适当的电话 ReadMemory() 获取信息。这听起来很工作,我认为这必须或多或少是您想要代理的每个类的定制代码集。可能有一种更好的方法可以解决这个问题,但这就是我头顶上的原因。

其他提示

我最终仅关注我的初始Hunch,然后将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文件中获取更多信息。这种技术使我可以将这些新的远程对象传递回我们的原始源代码,以在各种实用程序功能中处理,因为它们源自原始类。

肯定我应该能够以某种方式对此进行启动...但是似乎总有某种原因将每个类实现略有不同,例如,我们的一些更复杂的对象都有几个VTABLES,这两者都必须是跳过。

我知道获得内存转储一直是获取诊断信息的方法,但是ETW的信息非常简单,并且您可以获得信息以及包括信息系统调用和用户代码的通话堆栈。 MS一直为其所有产品(包括Windows和vs.net)这样做。

这是调试的一种非突破性方式。我进行了很长时间的调试,现在使用ETW,我能够解决大多数客户问题,而无需在调试器内花费大量时间。这是我的两分钱。

当WindBG攻击GDI泄漏示踪剂扩展时,我接近了类似的东西。我使用STL容器在客户端中进行数据存储,并且需要一种从扩展程序中遍历数据的方法。我最终使用极端电型直接在扩展侧实现了hash_map的部分,这很令人满意,但我花了一段时间才弄清楚; o)这里 是源代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top