gpt4 book ai didi

c++ - 打印 GDB 中任何类的 vtbl 函数

转载 作者:太空狗 更新时间:2023-10-29 22:59:19 30 4
gpt4 key购买 nike

较新版本的 gdb 允许在 C++ 中方便地解析 vtables。

假设我有这个示例代码

class Matcher {
public:
virtual void match() { cout << "base";}
};

class NMatcher: public Matcher{
public:
void match() { cout << "derived";}
};

int main() {
Matcher* m = new Matcher();
m->match();

Matcher *m2 = new NMatcher();
m2->match();
}

我可以通过 info vtbl ...

访问 main 中存在的两个变量的虚拟表
(gdb) info vtbl m
vtable for 'Matcher' @ 0x400ef0 (subobject @ 0x603010):
[0]: 0x400d9a <Matcher::match()>

现在想象这样一种情况,我在范围内没有变量,我想检查任何虚拟对象(或任何纯虚拟基类)的 vtable。为此,我并不严格需要一个对象。 vtable 是静态的,应该可以访问。

让我们看一下用于定位 vtable 的符号:

(gdb) info variables .*Matcher
All variables matching regular expression ".*Matcher":

Non-debugging symbols:
0x0000000000400ec0 vtable for NMatcher
0x0000000000400ee0 vtable for Matcher
0x0000000000400ef8 typeinfo name for NMatcher
0x0000000000400f10 typeinfo for NMatcher
0x0000000000400f28 typeinfo name for Matcher
0x0000000000400f40 typeinfo for Matcher

我不能直接使用上面列出的内存位置。虚拟方法不从 vtable 的开头开始。前 x 个字节存在偏移量和 RTI。在匹配器的情况下是 16,但它可以是任意数字:

(gdb) p *m
$22 = {
_vptr.Matcher = 0x400ef0 <vtable for Matcher+16>
}

理论上我可以直接访问 vtable 的内存位置并手动检查字节:

(gdb) x /4a 0x0000000000400ee0
0x400ee0 <_ZTV7Matcher>: 0x0 0x400f40 <_ZTI7Matcher>
0x400ef0 <_ZTV7Matcher+16>: 0x400d9a <Matcher::match()>

但这太痛苦了,我想知道一种按照(gdb) info vtbl 'vtable for Matcher'

做某事的便捷方法

我正在使用 GDB 7.8,但任何版本都可以。

最佳答案

恐怕 GDB 没有提供内置的方法来执行此操作。

你也许可以用黑客来近似它。黑客会像这样工作:

  • 获取 vtable 的基地址,如 print &'vtable for Type'

  • 获取类型的类型信息的基地址,如print &'typeinfo for Type'

  • 逐字搜索 vtable,寻找指向类型信息的指针。下一个词是 vtable 指针应该指向的位置。

  • 现在,用 this 作为 vtable 指针创建一个虚拟对象。

但是,如果您有一个子对象 vtable,这将不起作用。在那种情况下,您必须制作一个更正确的假对象。

总的来说,将此支持添加到 gdb 中会更好。它可以尝试在没有黑客攻击的情况下做正确的事情。

上面的程序是这样工作的:

(gdb) p &'vtable for NMatcher'
$1 = (<data variable, no debug info> *) 0x400ab0 <vtable for NMatcher>
(gdb) p &'typeinfo for NMatcher'
$2 = (<data variable, no debug info> *) 0x400ae0 <typeinfo for NMatcher>

现在转储 vtable 并查看指针应该在哪里。这是这里的第二个词,因为没有虚拟基地:

(gdb) x/10a $1
0x400ab0 <_ZTV8NMatcher>: 0x0 0x400ae0 <_ZTI8NMatcher>
0x400ac0 <_ZTV8NMatcher+16>: 0x4009b2 <NMatcher::match()> 0x0
0x400ad0 <_ZTV7Matcher+8>: 0x400b08 <_ZTI7Matcher> 0x400994 <Matcher::match()>
0x400ae0 <_ZTI8NMatcher>: 0x6011e0 <_ZTVN10__cxxabiv120__si_class_type_infoE@@CXXABI_1.3+16> 0x400af8 <_ZTS8NMatcher>
0x400af0 <_ZTI8NMatcher+16>: 0x400b08 <_ZTI7Matcher> 0x65686374614d4e38

所以,制作一个假对象。不幸的是,您需要较差的运行才能做到这一点:-(

(gdb) set $v = malloc(sizeof(void*))

设置假虚表指针。请注意,我们在指向 typeinfo 对象的指针后使用了一个词:

(gdb) set *$v = ((void **) $1) + 2

现在可以了:

(gdb) info vtbl (NMatcher*) $v
vtable for 'NMatcher' @ 0x400ac0 (subobject @ 0x613c20):
[0]: 0x4009b2 <NMatcher::match()>

关于c++ - 打印 GDB 中任何类的 vtbl 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37213562/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com