2010-04-09 13 views
7

Estoy intentando depurar algún código C++ basado en STL en gdb. El código tiene algo así comoAgregar funciones en gdb en tiempo de ejecución

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

Ahora en GDB, dentro myfunc el uso de "impresión m" da algo muy feo. Lo que he visto recomendada es algo así como la compilación de

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

Luego, en GDB haciendo

(gdb) call printmap(m) 

Esto parece una buena manera de manejar el problema ... pero puedo poner en un printmap separada objeto archivo (o incluso biblioteca dinámica) que luego cargo en gdb en tiempo de ejecución en lugar de compilarlo en mi binario, ya que recompilar el binario cada vez que quiero ver otra variable STL no es divertido ... mientras compilo y cargo uno. o archivo para la rutina de impresión puede ser aceptable.


ACTUALIZACIÓN:

Impulsada por sugerencia de Nikolais estoy mirando dlopen/dlsym.

Así que todavía no lo tengo funcionando, pero parece que me estoy acercando.

En printit.cpp

#include <stdio.h> 

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

Compilar a un .so usando

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

Iniciar mi aplicación de prueba y cargar el .so dlopen (2 = RTLD_NOW) y luego tratar de conseguir el símbolo para una función de depuración usando 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 

Tan cerca pero por alguna razón no puedo conseguir ese símbolo ... (No puedo siquiera entiendo si pongo las llamadas dlopen/dlsym en mi ejecutable) que supongo que estoy bien compilar el lib incorrecto o usando dlsym incorrectamente.

Si puedo conseguir el símbolo Asumo que puedo llamar a la función usando algo como

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

Estoy compilando esta en OS X 10.4, lo que podría estar causando un poco de mi .so males. .. Cualquier indicador sería apreciada.


Averigüe cómo hacer que todo esto funcione. Han publicado como una solución a continuación.

Respuesta

6

Así que mi solución es cargar un objeto compartido que contiene mis rutinas de depuración en tiempo de ejecución, utilizando dlopen. Resulta que es incluso más simple de lo que pensaba cuando tienes todas las banderas de compilación correctas.

En OS X, esto significa que compile la aplicación y el objeto de depuración de esta manera:

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 

El -fPIC de la aplicación es crítica, como es el -dynamiclib (en lugar de tratar el linux bandera -shared)

Un ejemplo debug_helper.cpp podría tener este aspecto

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

no sabe por qué he elegido utilizar stdio en lugar de iostream cosas ... Creo que se puede u se tampoco. (Pero no se olvide para eliminar las corrientes ...)

Ahora mi archivo de aplicación se parece a esto:

#include <map> 

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

Y aquí está un ejemplo de depuración de sesión (parte de la producción eliminado)

inicio del aplicación y descanso en un punto interesante

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

de carga en la biblioteca de depuración ayudante

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

GDB es inteligente y atrapa todos los nuevos símbolos para que no necesitemos usar dlsym, etc. Podemos simplemente llamar a las funciones directamente.

(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 

Permite añadir más información a printMap. Primero descargue la biblioteca.

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

Edite la fuente para agregar en la suma de las entradas. Recompilar y luego cargar la nueva biblioteca de nuevo en GDB (sin reiniciar el ejecutable o GDB)

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

utilizar la función modificada

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

Creo que esto hace todo lo que necesito.

2

Lo que estás pidiendo no es directamente posible hasta donde yo sé. Hay una alternativa cercana, aunque (que dijo que alrededor de un mayor nivel de indirección? :)

Construir una biblioteca dinámica independiente con todas sus rutinas de impresora, a continuación, añadir carga envoltorios de impresión perezosos a su programa. Con esto quiero decir algo en la línea:

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

A continuación, puede llamar print_map en la sesión del BGF y la biblioteca se carga automágicamente. Tenga en cuenta que el código anterior acepta el mapa por const referencia. La función que usted pone en la pregunta haría una copia de su argumento.

También eche un vistazo a here para algunas formas de hacer que gdb produzca una mejor salida para contenedores STL.

+0

Sí, realmente no me importa si la llamada copia los argumentos o no. Pero esta solución todavía no es práctica para mí, ya que si quiero ver otra clase de STL necesito recompilar mi binario y reiniciar gdb. Sin embargo, puede estar en algo con el uso de dlopen. Investigaré más a fondo. –

+0

Oh, querías una solución * ahora *, sin siquiera salir de la consola gdb? Los niños de hoy en día ... :) –

1

Te sugiero echar un vistazo aquí: http://sourceware.org/gdb/wiki/STLSupport

Hay un par de maneras diferentes de mostrar los contenedores STL (y el trabajo de la pierna ya se ha hecho para usted). Cualquier opción requerirá que reinicies gdb después de que la hayas configurado, pero será bueno usarla más adelante.

Cuestiones relacionadas