2016-05-13 4 views
2

gdbの新しいバージョンでは、C++でのvtableの解析が便利です。 GDBの任意のクラスのvtbl関数を出力します。

は、私は今私がスコープ内に何の変数を持っていない状況を想像してみて、私は info vtbl ...

(gdb) info vtbl m 
vtable for 'Matcher' @ 0x400ef0 (subobject @ 0x603010): 
[0]: 0x400d9a <Matcher::match()> 

を介して、主に存在する両方の変数の仮想テーブルにアクセスすることができ

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(); 
} 

このサンプルコードを持っていると言います仮想オブジェクト(または純粋な仮想基本クラス)の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とRTIがあります。私は直接のvtableのメモリ位置にアクセスし、手動でバイトを検査することができる理論的に

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

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

をそれ整合の場合には16であるが、それは任意の数とすることができますあまりにも痛いですし、私は行に沿って何かを行う便利な方法を知りたいです(gdb) info vtbl 'vtable for Matcher'

私はGDB 7.8を使用していますが、どのバージョンでもできます。

答えて

0

GDBはこれを行うための組み込みの方法を提供していませんが、恐れ入ります。

ハックで近似できます。ハックは次のようになります:

  • print &'vtable for Type'のようなvtableのベースアドレスを取得します。

  • print &'typeinfo for Type'のようなタイプのtypeinfoのベースアドレスを取得します。

  • vtableを単語単位で検索し、typeinfoへのポインタを探します。次の単語はvtableポインタが指すべき場所です。

  • これでvtableポインタとしてダミーオブジェクトを作成します。

ただし、サブオブジェクトvtableを使用している場合、これは機能しません。その場合、より正確な偽のオブジェクトを作成する必要があります。

全体として、このサポートをgdbに追加する方がよいでしょう。ハックなく正しいことをしようとする可能性があります。今のvtableをダンプし、ポインタがあるべき場所を確認

(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> 

:ここ

が、これは上にあなたのプログラムのためにどのように動作するかです。仮想ベースがないため、ここでは2番目の単語です。

(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 <[email protected]@CXXABI_1.3+16> 0x400af8 <_ZTS8NMatcher> 
0x400af0 <_ZTI8NMatcher+16>: 0x400b08 <_ZTI7Matcher> 0x65686374614d4e38 

したがって、偽のオブジェクトを作成します。残念ながら、あなたは偽のvtableポインタを設定し、この:-(

(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()> 
関連する問題