2010-04-09 15 views
7

Ich versuche, einige STL-basierten C++ - Code in GDB zu debuggen. Der Code hat so etwas wieHinzufügen von Funktionen in GDB zur Laufzeit

int myfunc() 
{ 
    std::map<int,int> m; 
    ... 
} 

Jetzt in GDB, innen myfunc mit "print m" gibt etwas sehr hässlich. Was ich

void printmap(std::map<int,int> m) 
{ 
    for(std::map<int,int>::iterator it = ...) 
    { 
     printf("%d : %d", it->first, it->second); 
    } 
} 

Dann in gdb tun

(gdb) call printmap(m) 

empfohlen kompiliert wie

etwas gesehen Dies scheint ein guter Weg, um das Problem zu umgehen ... aber kann ich eine separate printmap setzen in Objektdatei (oder sogar dynamische Bibliothek), die ich dann zur Laufzeit in gdb lade, anstatt sie in meine Binärdatei zu kompilieren - das Kompilieren der Binärdatei jedes Mal, wenn ich eine andere STL-Variable betrachten möchte, macht keinen Spaß. o Datei für die Druckroutine kann akzeptabel sein.


UPDATE:

Angeregt durch Nikolais Vorschlag an Ich suche dlopen/dlsym.

Also habe ich noch nicht funktioniert, aber es fühlt sich an wie ich näher komme.

In printit.cpp

#include <stdio.h> 

extern "C" void printit() 
{ 
    printf("OMG Fuzzies"); 
} 

Compile zu einem .so

g++ -Wall -g -fPIC -c printit.cpp 
g++ -shared -Wl,-undefined,dynamic_lookup -o printit.so printit.o 
mit

meine Testanwendung starten und die .so laden mit dlopen (2 = RTLD_NOW) dann versuchen, das Symbol zu erhalten für eine Debugging-Funktion mit dlsym.

(gdb) break main 
(gdb) run 
(gdb) print (void*) dlopen("printit.so", 2) 
$1 = (void *) 0x100270 
(gdb) print (void*) dlsym(0x100270, "_printit") 
$2 = (void *) 0x0 

So nah, aber aus irgendeinem Grund kann ich nicht, dass das Symbol bekommen ... (Ich kann es sogar, wenn ich die setzen dlopen/dlsym Anrufe in meine ausführbare Datei) Ich vermute, ich bin entweder die Erstellung der lib falsch oder dlsym falsch verwenden.

Wenn ich das Symbol bekommen kann ich gehe davon aus ich die Funktion aufrufen kann so etwas wie

(gdb) print ((void(*)())(0x....))() 

ich mit diesem auf OS X 10.4 bin kompilieren, die einige meiner .so Leiden verursachen könnte. .. irgendwelche Hinweise würden geschätzt werden.


herausgefunden, wie all dies funktioniert. Habe als Lösung unten gepostet.

Antwort

6

Also meine Lösung ist, ein gemeinsames Objekt mit meinen Debugging-Routinen zur Laufzeit mit dlopen zu laden. Es stellt sich heraus, dass es noch einfacher ist, als ich dachte, wenn Sie alle Kompilierungsflags richtig gelesen haben.

Unter OS X dies bedeutet, dass Sie Ihre Anwendung und das Debuggen Objekt wie folgt zusammenstellen:

all : application.x debug_helper.so 

application.x : application.cpp 
    g++ -g application.cpp -o application.x -fPIC 

debug_helper.so : debug_helper.o 
    g++ -dynamiclib -o debug_helper.so debug_helper.o 

debug_helper.o : debug_helper.cpp 
    g++ -Wall -g -fPIC -c debug_helper.cpp 

Die -fPIC auf die Anwendung kritisch ist, wie der -dynamiclib ist (anstatt zu versuchen, die Linux -shared Flag)

Ein Beispiel debug_helper.cpp wie diese

aussehen könnte
#include <map> 
#include <stdio.h> 

extern "C" 
void printMap(const std::map<int,int> &m) 
{ 
    printf("Map of size %d\n", int(m.size())); 
    for(std::map<int,int>::const_iterator it = m.begin(); it!=m.end(); ++it) 
    { 
    printf("%d : %d \n", it->first, it->second); 
    } 
    fflush(stdout); 
} 

Sie wissen nicht, warum ich stdio anstatt iostream Sachen zu verwenden, entschied ... ich denke, können Sie u se entweder. (Nur nicht vergessen, die Ströme zu spülen ...)

Nun meine Anwendungsdatei sieht wie folgt aus:

#include <map> 

int main() 
{ 
    std::map<int,int> m; 
    m[1]=2; 
    m[2]=5; 
    m[3]=10; 
    m[4]=17; 
} 

Und heres ein Beispiel Debug-Sitzung (einige Ausgabe entfernt)

starten Anwendung und Pause an einem interessanten Punkt

(gdb) break main 
(gdb) run 
Reading symbols for shared libraries +++. done 
Breakpoint 1, main() at test.cpp:5 
5  std::map<int,int> m; 

laden in der Debug-Helfer Bibliothek

(gdb) print (void*) dlopen("debug_helper.so",2) 
Reading symbols for shared libraries . done 
$1 = (void *) 0x100270 
(gdb) n 
6  m[1]=2; 

GDB ist intelligent und fängt alle neuen Symbole für uns ein, so dass wir dlsym usw. nicht brauchen. Wir können die Funktionen einfach direkt aufrufen.

(gdb) call printMap(m) 
Map of size 0 
(gdb) n 
(gdb) n 
(gdb) n 
9  m[4]=17; 
(gdb) call printMap(m) 
Map of size 3 
1 : 2 
2 : 5 
3 : 10 

Fügen Sie weitere Informationen zu printMap hinzu. Entladen Sie zuerst die Bibliothek.

(gdb) print (int) dlclose($1) 
$2 = 0 

Bearbeiten Sie die Quelle, um die Summe der Einträge hinzuzufügen. Neu kompilieren und dann laden die neue Bibliothek zurück in GDB (ohne die ausführbare Datei oder GDB Neustart)

(gdb) print (void*) dlopen("debug_helper.so",2) 
Reading symbols for shared libraries . done 

Verwenden Sie die modifizierte Funktion

$3 = (void *) 0x100270 
(gdb) call printMap(m) 
Map of size 3 
1 : 2 
2 : 5 
3 : 10 
SUM = 17 

Ich denke, das alles tut, was ich brauche.

2

Was Sie verlangen ist nicht direkt möglich, soweit ich weiß. Es gibt eine enge Alternative obwohl (wer sagte, dass über eine weitere Ebene der Umleitung? :)

Erstellen Sie eine separate dynamische Bibliothek mit all Ihren Drucker-Routinen, fügen Sie dann lazy load drucken Wrapper zu Ihrem Programm. Damit meine ich, etwas entlang der Linien:

/// this is in your program, lazy print wrapper 
void print_map(const std::map<int,int>& m) // NOTE THE CONST REFERENCE 
{ 
    static bool loaded = false; 
    static void* print_lib = 0; 
    static void (*print_func_ptr)(const std::map<int,int>&) = 0; 

    if (!loaded) 
    { 
     // dlopen dynamic lib, check for errors, assign to print_lib 
     // dlsym the library function by name, assign to print_func_ptr 
     loaded = true; 
    } 

    print_func_ptr(m); 
} 

Dann können Sie print_map in der GDB-Sitzung aufrufen und die Bibliothek würde automatisch laden. Beachten Sie, dass der obige Code die Karte akzeptiert const Referenz. Die Funktion, die Sie in die Frage stellen, würde eine Kopie seiner Argumentation machen.

Schauen Sie auch here für einige Möglichkeiten, um gdb produzieren bessere Ausgabe für STL-Container.

+0

Ja, ich kümmerte mich nicht wirklich, ob der Anruf die Argumente kopierte oder nicht. Aber diese Lösung ist immer noch unpraktisch für mich, denn wenn ich eine andere STL-Klasse betrachten möchte, muss ich meine Binärdatei neu kompilieren und gdb neu starten. Sie können jedoch mit dlopen auf etwas zugreifen. Ich werde weiter untersuchen. –

+0

Oh, du wolltest eine Lösung * jetzt *, ohne die gdb Konsole zu verlassen? Kinder in diesen Tagen ... :) –

1

Ich würde vorschlagen, einen Blick hier: http://sourceware.org/gdb/wiki/STLSupport

Es gibt ein paar verschiedene Möglichkeiten von STL-Containern Anzeigen (und die Beinarbeit bereits für Sie getan wurde). Für jede Option müssen Sie gdb neu starten, nachdem Sie es konfiguriert haben, aber es ist gut, es später zu verwenden.

Verwandte Themen