2016-05-13 11 views
2

Neuere Version von gdb ermöglichen das bequeme Parsen von VTables in C++.Drucken vtbl Funktionen jeder Klasse in GDB

sagen, dass ich diesen Beispielcode

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

ich die virtuelle Tabelle beiden Variablen in Haupt zugreifen kann über info vtbl ...

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

Nun stellen Sie eine Situation, wo ich keine Variable im Umfang habe und Ich möchte die vtable eines virtuellen Objekts (oder einer reinen virtuellen Basisklasse) untersuchen. Dafür brauche ich kein Objekt. Die vtable ist statisch und sollte zugänglich sein.

einen Blick auf die Symbole sehen Lassen Sie die V-Tabelle zu finden:

(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 

ich nicht die aufgeführten Speicherplatz oben direkt verwenden können. Die virtuellen Methoden beginnen nicht am Anfang der vtable. Es gibt Offset und RTI für die ersten x Bytes. Im Fall von Matcher ist es 16, aber es kann jede beliebige Zahl sein:

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

In der Theorie kann ich den Speicherplatz des VTable direkt zugreifen und das Bytes manuell überprüfen:

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

Aber die ist zu schmerzhaft und ich würde gerne eine bequeme Art und Weise wissen, etwas zu tun in Richtung der (gdb) info vtbl 'vtable for Matcher'

Ich benutze GDB 7.8 aber jede Version wird tun.

Antwort

0

GDB bietet keine integrierte Möglichkeit, dies zu tun, fürchte ich.

Sie könnten es vielleicht mit einem Hack annähern. Der Hack würde wie folgt funktionieren:

  • die Basisadresse des VTable Get, wie print &'vtable for Type'.

  • Ermitteln Sie die Basisadresse des typeinfo für den Typ wie print &'typeinfo for Type'.

  • Durchsuchen Sie die vtable Wort für Wort und suchen Sie nach einem Zeiger auf die Typinfo. Das nächste Wort ist die Stelle, auf die ein Vtable-Zeiger zeigen sollte.

  • Erstellen Sie nun ein Dummy-Objekt mit diesem als Vtable-Zeiger.

Dies funktioniert jedoch nicht, wenn Sie ein Unterobjekt vtable haben. In diesem Fall müssten Sie ein falsches Objekt erstellen, das korrekter ist.

Im Großen und Ganzen wäre es besser, diese Unterstützung zu gdb hinzuzufügen. Es könnte versuchen, das Richtige ohne Hacks zu tun.

Hier ist, wie dies für Ihr Programm funktioniert über:

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

nun die VTable-Dump und sehen, wo der Zeiger sein sollte.Es ist das zweite Wort hier, weil es keine virtuellen Basen gibt:

(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 

Also, machen Sie ein falsches Objekt. Leider müssen Sie den unteren Lauf dieses :-(

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

Stellen Sie den gefälschte VTable-Zeiger tun Hinweis wir ein Wort nach dem Zeiger auf das Objekt verwenden Typeinfo.

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

Jetzt funktioniert es:

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