Добавьте функции в gdb во времени выполнения

Я пытаюсь отладить некоторый основанный на 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 горя... любые указатели будут цениться.


Узнанный, как получить всю эту работу. Отправили как решение ниже.

8
задан Michael Anderson 10 April 2010 в 03:44
поделиться

3 ответа

Итак, мое решение - загрузить общий объект, содержащий мои процедуры отладки, во время выполнения, используя 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

Я думаю, это делает все, что мне нужно.

7
ответ дан 5 December 2019 в 17:35
поделиться

Насколько я знаю, то, о чем вы просите, напрямую невозможно. Однако есть близкая альтернатива (кто сказал это о еще одном уровне косвенности? :)

Создайте отдельную динамическую библиотеку со всеми вашими подпрограммами принтера, а затем добавьте в свою программу оболочки печати отложенной загрузки . Под этим я подразумеваю что-то вроде:

/// 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.

2
ответ дан 5 December 2019 в 17:35
поделиться

Я бы посоветовал взглянуть здесь: http://sourceware.org/gdb/wiki/STLSupport

Есть пара различные способы отображения контейнеров STL (и работа с ногами уже сделана за вас). Любой вариант потребует от вас перезапуска gdb после его настройки, но его можно использовать в дальнейшем.

1
ответ дан 5 December 2019 в 17:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: