С++: отладка с GDB

Автор: | 07/19/2014
 

cpp_logo

Домашняя страница проекта — http://www.gnu.org/software/gdb/

Устанавливаем сам отладчик:

# yum -y install gdb

Предположим, у нас есть файл myfirst.cpp:

#include <iostream>

int main () {
  // using namespace std;
  // using std::cout;
  using std::endl;

  std::cout << "Come up and C++ me some time.";
  std::cout << endl;
  std::cout << "You won't regret it!" << endl;
  return 0;
  }

Собираем его:

$ g++ myfirst.cpp -o myfirst.o

И запускаем отладчик:

$ gdb myfirst.o
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-64.el6_5.2)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/setevoy/scripts/cpp/prata/myfirst.o...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o
Come up and C++ me some time.
You won't regret it!

Program exited normally.
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64 libgcc-4.4.7-4.el6.x86_64 libstdc++-4.4.7-4.el6.x86_64

Посмотреть доступные команды можно с помощью help в интерфейсе самого отладчика:

(gdb) help
List of classes of commands:

aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands

Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.

Кроме того, gdb сообщает, что:

Missing separate debuginfos

Для их установки нам понадобится утилита debuginfo-install, которая входит в набор yum-utils:

# yum -y install yum-utils

Теперь устанавливаем сами пакеты:

# debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64 libgcc-4.4.7-4.el6.x86_64 libstdc++-4.4.7-4.el6.x86_64

Если получаем сообщение вида:

...
Could not find debuginfo for main pkg: glibc-2.12-1.132.el6_5.2.x86_64
Could not find debuginfo pkg for dependency package glibc-2.12-1.132.el6_5.2.x86_64

Значит не подключён репозиторий Debuginfo.

Редактируем файл /etc/yum.repos.d/CentOS-Debuginfo.repo, и меняем:

enabled=0

на

enabled=1

Проверим нашу программу и gdb ещё раз:

$ gdb myfirst.o
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-64.el6_5.2)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/setevoy/scripts/cpp/prata/myfirst.o...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o
Come up and C++ me some time.
You won't regret it!

Program exited normally.

Обратите внимание на сообщение (no debugging symbols found).
Что бы получать полную информацию от отладчика, нам необходимо перекомпилировать проект так, чтобы его двоичный файл содержал отладочную информацию. Эта информация включает в себя, в частности, описание соответствий между адресами исполняемого кода и строками в исходном коде.
Запускаем компилятор g++ с опцией -g:

$ g++ myfirst.cpp -o myfirst.o -g

И нова запускаем gdb:

$ gdb myfirst.o
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-64.el6_5.2)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/setevoy/scripts/cpp/prata/myfirst.o...done.
(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o
Come up and C++ me some time.
You won't regret it!

Program exited normally.

Что бы посмотреть исходный код программы — выполните команду list:

(gdb) list
1 #include <iostream>
2
3 int main () {
4 // using namespace std;
5 // using std::cout;
6 using std::endl;
7
8 std::cout << "Come up and C++ me some time.";
9 std::cout << endl;
10 std::cout << "You won't regret it!" << endl;

Команда будет выведена не вся, а только первые 10 строк кода.

Для продолжения просмотра кода — просто ещё раз укажите list:

(gdb) list
3 int main () {
4 // using namespace std;
5 // using std::cout;
6 using std::endl;
7
8 std::cout << "Come up and C++ me some time.";
9 std::cout << endl;
10 std::cout << "You won't regret it!" << endl;
11 return 0;
12 }

Зададим точку остановки, с которой мы будет проверять работу программы:

(gdb) break 8
Breakpoint 1 at 0x400818: file myfirst.cpp, line 8.

Запустим программу на выполнение в дебаггере:

(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o

Breakpoint 1, main () at myfirst.cpp:8
8 std::cout << "Come up and C++ me some time.";

Остановка выполнена на 8 строке.

Просмотреть список точек остановки:

(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400818 in main() at myfirst.cpp:8
breakpoint already hit 1 time

Удалить точку:

(gdb) delete 1

Зададим новую точку:

(gdb) break 11
Breakpoint 4 at 0x400852: file myfirst.cpp, line 11.

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o
Come up and C++ me some time.
You won't regret it!

Breakpoint 4, main () at myfirst.cpp:11
11 return 0;

Пройдём по шагам выполнения программы.

Создадим точку:

(gdb) list
1 #include <iostream>
2
3 int main () {
4 // using namespace std;
5 // using std::cout;
6 using std::endl;

(gdb) break 6
Breakpoint 5 at 0x400818: file myfirst.cpp, line 6.

Запускаем:

(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o

Breakpoint 5, main () at myfirst.cpp:8
8 std::cout << "Come up and C++ me some time.";

И делаем шаг:

(gdb) step
std::operator<< <std::char_traits<char> > (__out=..., __s=0x4009a8 "Come up and C++ me some time.") at /usr/src/debug/gcc-4.4.7-20120601/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/ostream:505
505 operator<<(basic_ostream<char, _Traits>& __out, const char* __s)

Тут мы, например, видим как вызывается класс char_traits.

Или так:

(gdb) s
507 if (!__s)

Чтобы при вызове функции программа не входила в неё, а продолжала дальше выполняться только на текущем уровне стека, вместо step даётся команда next или просто n:

(gdb) run
Starting program: /home/setevoy/scripts/cpp/prata/myfirst.o

Breakpoint 1, main () at myfirst.cpp:8
8 std::cout << "Come up and C++ me some time.";
(gdb) n
9 std::cout << endl;
(gdb) n
Come up and C++ me some time.
10 std::cout << "You won't regret it!" << endl;
(gdb) n
You won't regret it!
11 return 0;
(gdb) n
12 }
(gdb) n
__libc_start_main (main=0x400814 <main()>, argc=1, ubp_av=0x7fffffffe088, init=<value optimized out>, fini=<value optimized out>, rtld_fini=<value optimized out>, stack_end=0x7fffffffe078) at libc-start.c:258
258 exit (result);
(gdb) n

Program exited normally.

Ссылки по теме

http://www.cs.cmu.edu
http://www.gnu.org