Я пытаюсь отладить некоторый основанный на STL код C++ в gdb. Код имеет что-то как
int myfunc()
{
std::map<int,int> m;
...
}
Теперь в gdb, внутри myfunc использующий "печать m" дает что-то очень ужасное. То, что я видел рекомендуемый, компилирует что-то как
void printmap( std::map<int,int> m )
{
for( std::map<int,int>::iterator it = ... )
{
printf("%d : %d", it->first, it->second );
}
}
Затем в выполнении gdb
(gdb) call printmap( m )
Это походит на хороший способ обработать проблему..., но могу я помещать printmap в отдельный объектный файл (или даже динамическая библиотека), что я затем загружаюсь в gdb во времени выполнения вместо того, чтобы компилировать его в мой двоичный файл - как перекомпиляция двоичного файла каждый раз, когда я хочу посмотреть на другую переменную STL, не забава.. в то время как компиляция и загрузка единственного.o файла для стандартной программы печати могут быть приемлемыми.
ОБНОВЛЕНИЕ:
Запрошенный предложением Nikolais я смотрю на dlopen/dlsym.
Таким образом, я еще не получил эту работу, но такое чувство, что я становлюсь ближе.
В printit.cpp
#include <stdio.h>
extern "C" void printit()
{
printf("OMG Fuzzies");
}
Скомпилируйте в использование .so
g++ -Wall -g -fPIC -c printit.cpp
g++ -shared -Wl,-undefined,dynamic_lookup -o printit.so printit.o
Запустите мое тестовое приложение и загрузитесь, .so, использующие dlopen (2 = RTLD_NOW) затем, пытаются получить символ для функции отладки с помощью 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
Так закрываются, но по некоторым причинам я не могу получить тот символ... (Я не могу даже получить его, если я поместил вызовы dlopen/dlsym в свой исполняемый файл), я предполагаю, что или компилирую lib неправильно или использую dlsym неправильно.
Если я могу получить символ, я предполагаю, что могу вызвать функцию с помощью чего-то как
(gdb) print (( void(*)() )(0x....))()
Я компилирую это на OS X 10.4, который мог бы вызывать часть моего .so горя... любые указатели будут цениться.
Узнанный, как получить всю эту работу. Отправили как решение ниже.
Итак, мое решение - загрузить общий объект, содержащий мои процедуры отладки, во время выполнения, используя dlopen. Оказывается, это даже проще, чем я думал, когда вы правильно используете все флаги компиляции.
В OS X это означает, что вы компилируете свое приложение и отлаживаете объект следующим образом:
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
-fPIC в приложении имеет решающее значение, как и -dynamiclib (вместо того, чтобы пытаться использовать флаг linux -shared)
Пример debug_helper.cpp может выглядеть так
#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);
}
Не знаю, почему я решил использовать stdio, а не iostream ... Думаю, вы можете использовать и то, и другое. (только не забудьте очистить потоки ...)
Теперь мой файл приложения выглядит так:
#include <map>
int main()
{
std::map<int,int> m;
m[1]=2;
m[2]=5;
m[3]=10;
m[4]=17;
}
И вот пример сеанса отладки (часть вывода удалена)
Запустите приложение и остановитесь на интересном point
(gdb) break main
(gdb) run
Reading symbols for shared libraries +++. done
Breakpoint 1, main () at test.cpp:5
5 std::map<int,int> m;
Загрузка вспомогательной библиотеки отладки
(gdb) print (void*) dlopen("debug_helper.so",2)
Reading symbols for shared libraries . done
$1 = (void *) 0x100270
(gdb) n
6 m[1]=2;
GDB умен и улавливает все новые символы для нас, поэтому нам не нужно использовать dlsym и т. д. Мы можем просто вызывать функции напрямую.
(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
Давайте добавим дополнительную информацию в printMap. Сначала выгрузите библиотеку.
(gdb) print (int) dlclose($1)
$2 = 0
Отредактируйте источник, чтобы добавить сумму записей. Перекомпилируйте, а затем загрузите новую библиотеку обратно в gdb (без перезапуска исполняемого файла или gdb)
(gdb) print (void*) dlopen("debug_helper.so",2)
Reading symbols for shared libraries . done
Используйте измененную функцию
$3 = (void *) 0x100270
(gdb) call printMap(m)
Map of size 3
1 : 2
2 : 5
3 : 10
SUM = 17
Я думаю, это делает все, что мне нужно.
Насколько я знаю, то, о чем вы просите, напрямую невозможно. Однако есть близкая альтернатива (кто сказал это о еще одном уровне косвенности? :)
Создайте отдельную динамическую библиотеку со всеми вашими подпрограммами принтера, а затем добавьте в свою программу оболочки печати отложенной загрузки . Под этим я подразумеваю что-то вроде:
/// 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 );
}
Затем вы можете вызвать print_map
в сеансе gdb, и библиотека загрузится автоматически.
Обратите внимание, что код выше принимает карту ссылка на константу . Функция, которую вы задали в вопросе, сделает копию своего аргумента.
Также посмотрите здесь , чтобы узнать о некоторых способах улучшения вывода GDB для контейнеров STL.
Я бы посоветовал взглянуть здесь: http://sourceware.org/gdb/wiki/STLSupport
Есть пара различные способы отображения контейнеров STL (и работа с ногами уже сделана за вас). Любой вариант потребует от вас перезапуска gdb после его настройки, но его можно использовать в дальнейшем.