Отладчик GDB (GNU debugger) построчно выполняет код программы, чтобы выявить ошибки в процессе её выполнения. Отладчик GDB позволяет менять значения переменных, устанавливать контрольные точки и условия остановки запущенной программы.

С помощью отладчика GDB вы можете:

  • задать условия, которые могут повлиять на поведение программы;
  • начать выполнение программы с заданными условиями;
  • указать условия, при наступлении которых выполнение программы будет остановлено;
  • исследовать причины остановки программы;
  • изменить код программы, чтобы устранить эффекты одной ошибки и продолжить выявление других.

Подготовка окружения и запуск отладчикаLink to Подготовка окружения и запуск отладчика


  1. Установите пакеты ПО:

    CentOS 7, AlmaLinux 9

    yum install -y billmanager-corporate-devel gdb gcc-c++
    CODE

    Ubuntu 20.04, AstraLinux 1.7.4

    apt install -y billmanager-corporate-devel gdb gcc-c++
    CODE
  2. Запустите BILLmanager.

  3. Подключитесь к процесcу BILLmanager:

    gdb -p $(ps aux | grep billmgr | head -1 | awk '{print $2}')
    CODE

Отладочные символыLink to Отладочные символы


Отладка возможна, если сборка осуществлена с отладочными символами. Подробнее о сборке проекта см. статью Взаимодействие на низком уровне, плагины с++.

Чтобы проверить наличие отладочных символов, выполните:

objdump -x {PATH_TO_SO_FILE} | grep debug
CODE
  • {PATH_TO_SO_FILE} — путь до файла модуля

Если в сборке присутствуют отладочные символы, то результат будет следующим:

[root@gdb-bill privatbank]# objdump -x /usr/local/mgr5/libexec/pmprivatbank.so | grep debug
 26 .debug_aranges 000010d0  0000000000000000  0000000000000000  0001daf5  2**0
 27 .debug_info   0002325b  0000000000000000  0000000000000000  0001ebc5  2**0
 28 .debug_abbrev 00000e4c  0000000000000000  0000000000000000  00041e20  2**0
 29 .debug_line   00002ae3  0000000000000000  0000000000000000  00042c6c  2**0
 30 .debug_str    00034dad  0000000000000000  0000000000000000  0004574f  2**0
 31 .debug_ranges 00001120  0000000000000000  0000000000000000  0007a4fc  2**0
0000000000000000 l    d  .debug_aranges	0000000000000000              .debug_aranges
0000000000000000 l    d  .debug_info	0000000000000000              .debug_info
0000000000000000 l    d  .debug_abbrev	0000000000000000              .debug_abbrev
0000000000000000 l    d  .debug_line	0000000000000000              .debug_line
0000000000000000 l    d  .debug_str	0000000000000000              .debug_str
0000000000000000 l    d  .debug_ranges	0000000000000000              .debug_ranges
[root@gdb-bill privatbank]#
CODE

Переменная окружения WITHOUT_DEBUG=yes отвечает за отсутствие отладочных символов при сборке модулей BILLmanager. Например, для модуля pmprivatbank при сборке без отладочных символов будет следующий результат:

Пример сборки с отключенными отладочными символами

[root@gdb-bill privatbank]# WITHOUT_DEBUG=yes make install
Create folder .build/.obj
Create folder .build/.dep
Compiling pmprivatbank.cpp
Create symbolic link to external libs
Create symbolic link for local libs
Building wrapper backend pmprivatbank
Create /usr/local/mgr5/libexec/pmprivatbank.so ...
Compiling privatbankpayment.cpp
Building wrapper backend privatbankpayment
Create /usr/local/mgr5/libexec/privatbankpayment.so ...
Compiling privatbankresult.cpp
Building wrapper backend privatbankresult
Create /usr/local/mgr5/libexec/privatbankresult.so ...
Shutdown billmgr ... done
[root@gdb-bill privatbank]# objdump -x /usr/local/mgr5/libexec/pmprivatbank.so | grep debug
[root@gdb-bill privatbank]#
CODE

ПримерыLink to Примеры


Примеры ниже составлены для ОС CentOS 7. В других ОС шаги или выводы могут отличаться.

Пример отладки подключаемой библиотекиLink to Пример отладки подключаемой библиотеки

  1. Создайте директорию /usr/local/mgr5/src/gdbtest/ со следующей структурой:

    Структура директории

    src/gdbtest/
    ├── gdbtest.cpp
    ├── Makefile
    └── xml
        └── billmgr_mod_gdbtest.xml
    1 directory, 3 files
    CODE

    Содержимое файла src/gdbtest/xml/billmgr_mod_gdbtest.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <mgrdata>
        <library name="libgdbtest"/>
    </mgrdata>
    CODE

    Содержимое файла src/gdbtest/gdbtest.cpp

    #include <api/action.h>
    #include <mgr/mgrlog.h>
    #include <mgr/mgraccess.h>
    
    MODULE("gdbtest");
    
    using namespace isp_api;
    
    class aTest : public StdListAction {
    public:
    	aTest()
    		: StdListAction("atest", MinLevel(lvAdmin)) {}
    
    	void List(Session& ses) const override
    	{
    		int a;
    	}
    };
    
    MODULE_INIT(aTest, "billmgr") {
    	new aTest;
    }
    CODE
    [root@gdb-bill mgr5]# cat src/gdbtest/Makefile
    MGR=billmgr
    PLUGIN=gdbtest
    
    LIB += libgdbtest
    libgdbtest_SOURCES += gdbtest.cpp
    libgdbtest_LDADD = -lmgrdb -lispapi
    
    include ../isp.mk
    CODE
  2. Соберите и установите модуль командой:

    cd /usr/local/mgr5/src/gdbtest/ && make install
    CODE

    Результат выполнения команды:

    [root@gdb-bill gdbtest]# cd /usr/local/mgr5/src/gdbtest/ && cp -f billmgr_mod_gdbtest.xml ../../etc/xml/ && make install DISTDIR=/usr/local/mgr5
    Create folder .build/.obj
    Create folder .build/.dep
    Compiling gdbtest.cpp
    gdbtest.cpp: In member function ‘virtual void aTest::List(isp_api::Session&) const’:
    gdbtest.cpp:19:7: warning: unused variable ‘a’ [-Wunused-variable]
       int a;
           ^
    Create symbolic link to external libs
    Create symbolic link for local libs
    Building library libgdbtest
    Create library ../../lib/libgdbtest.so
    Shutdown billmgr ... done
    CODE

    При сборке модуля BILLmanager будет остановлен.

  3. Запустите BILLmanager.

    /usr/local/mgr5/sbin/mgrctl -u billmgr
    CODE
  4. Подключитесь к BILLmanager:

    cd /usr/local/mgr5/ && gdb -p $(ps aux | grep billmgr | head -1 | awk '{print $2}')
    
    CODE

    При успешном подключении будет следующий вывод и приглашение для ввода команд (gdb):

    Reading symbols from lib/Libgdbtest.so…done.
    Loaded symbols for lib/libgdbtest…so
    0x00007fc9d087be9d in nanosleep () from /lib64/libpthread.so.0
    Missing separate debuginfos, use: debuginfo-install coremanager-5.399.0-2307201251307784. el7.x86_64 
    (gdb)
    CODE


  5. Проверьте, что отладочные символы для модуля подгрузились. Для этого выполните:

    (gdb) list gdbtest.cpp:1
    CODE


    	#include <api/action.h>
    	#include <mgr/mgrlog.h>
    	#include <mgr/mgraccess.h>
    
    
    	MODULE("gdbtest");
    
    	using namespace isp_api;
    CODE
  6. Для отладки модуля:

    1. Поставьте точку останова на 16 строку:

      (gdb) b gdbtest.cpp:16
      Breakpoint 1 at 0x7f2bb1304330: file gdbtest.cpp, line 16.
      CODE
      • b — команда gdb, устанавливающая точку останова
      • gdbtest.cpp — имя cpp-файла
      • 16 — строка в файле с кодом
    2. Продолжите выполнение BILLmanager:

      (gdb) c
      Continuing.
      CODE
    3. Откройте второе окно терминала и вызовите функцию из модуля:

      cd /usr/local/mgr5/ && sbin/mgrctl -m billmgr atest
      CODE
    4. Вернитесь в окно терминала с отладчиком gdb, где программа достигла точки останова:

      Breakpoint 1, aTest::List (this=0x37264a0, ses=...) at gdbtest.cpp:17
      17		}
      (gdb)
      CODE

      В точке останова вы можете посмотреть значение переменных следующей командой:

      (gdb) p a
      $1 = 0
      CODE
      • p — команда gdb для вывода значения
      • a — имя переменной, значение которой нужно вывести

Пример отладки платёжного модуляLink to Пример отладки платёжного модуля

Для примера использован модуль pmprivatbank, представленный в пакетах разработчика billmanager-devel/billmanager-corporate-devel.

Вы можете адаптировать данный пример для разрабатываемых модулей обработки услуг.

  1. Установите зависимости:

    yum -y install openssl-devel jsoncpp-devel
    CODE
  2. Соберите и установите модуль:

    cd /usr/local/mgr5/src/examples/privatbank/ && make install
    CODE
  3. Запустите отладчик gdb с указанием исполняемого файла:

    cd /usr/local/mgr5/ && gdb paymethods/pmprivatbank
    CODE

    Результат выполнения команды

    [root@gdb-bill mgr5]# cd /usr/local/mgr5/ && gdb paymethods/pmprivatbank
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
    Copyright (C) 2013 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 /usr/local/mgr5/libexec/wrapper...(no debugging symbols found)...done.
    (gdb)
    CODE
  4. Установите точку останова на нужном месте в исходном коде. Если ответ содержит "Make breakpoint pending on future shared library load?", отправьте "y".

    (gdb) b pmprivatbank.cpp:18
    No symbol table is loaded.  Use the "file" command.
    Make breakpoint pending on future shared library load? (y or [n]) y
    Breakpoint 1 (pmprivatbank.cpp:18) pending.
    CODE
    • b — команда gdb, устанавливающая точку останова
    • pmprivatbank.cpp — имя cpp-файла
    • 18 — строка в файле с кодом
  5. Запустите исполняемый файл с требуемыми параметрами:

    (gdb) run --command features
    Starting program: /usr/local/mgr5/paymethods/pmprivatbank --command features
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    process 7807 is executing new program: /usr/local/mgr5/libexec/wrapper
    Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64 libstdc++-4.8.5-44.el7.x86_64
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".gdbrun --command featuresё
    
    Breakpoint 1, payment::PrivatBank::PrivatBank (this=0x6473a0) at pmprivatbank.cpp:18
    18			feature_map[PAYMENT_FEATURE_REDIRECT] = true;
    Missing separate debuginfos, use: debuginfo-install coremanager-5.399.0-2307201251307784.el7.x86_64
    CODE

При успешном выполнении отладчик GDB остановится на строке 18 и будет ожидать ввода команд.

Пример отладки CGI-компонентов платёжного модуляLink to Пример отладки CGI-компонентов платёжного модуля

Для примера использован модуль pmprivatbank, представленный в пакетах разработчика billmanager-devel/billmanager-corporate-devel.

CGI-компоненты могут требовать дополнительные переменные окружения для своей работы:

  • HTTP_COOKIE — содержит различные cookie, в том числе cookie с сессией пользователя;
  • QUERY_STRING — содержит параметры запроса.
  1. Установите зависимости:

    yum -y install openssl-devel jsoncpp-devel
    CODE
  2. Соберите и установите модуль:

    sh cd /usr/local/mgr5/src/examples/privatbank/ && make install
    CODE
  3. Запустите отладчик gdb с указанием исполняемого файла:

    cd /usr/local/mgr5/ && gdb cgi/privatbankpayment
    CODE
  4. Укажите переменные окружения внутри отладчика gdb, необходимые для работы модуля:

    (gdb) set env HTTP_COOKIE=billmgrses5=57f5aa8ce144c9e664b11508 (gdb) set env QUERY_STRING=elid=1
    CODE
    • billmgrses5=57f5aa8ce144c9e664b11508 — сессия активного пользователя
    • elid=1 — ID платежа, в рамках которого производится отладка работы CGI
  5. Установите точку останова на нужном месте в исходном коде. Если ответ содержит "Make breakpoint pending on future shared library load?", отправьте "y".

    (gdb) b privatbankpayment.cpp:29
    No symbol table is loaded.  Use the "file" command.
    Make breakpoint pending on future shared library load? (y or [n]) y
    Breakpoint 1 (privatbankpayment.cpp:29) pending.
    CODE
    • b — команда gdb, устанавливающая точку останова
    • privatbankpayment.cpp — имя cpp-файла
    • 29 — строка в файле с кодом
  6. Запустите исполняемый файл:

    (gdb) run
    Starting program: /usr/local/mgr5/cgi/privatbankpayment
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    process 14507 is executing new program: /usr/local/mgr5/libexec/wrapper
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    [New Thread 0x7fffed2cc700 (LWP 14511)]
    [Thread 0x7fffed2cc700 (LWP 14511) exited]
    Content-Type: text/html
    Set-Cookie: paymentcgises5=db19b8d7648b77196003677f; path=/mancgi/; HttpOnly; max-age=86400
    
    
    Breakpoint 1, PrivatBankPayment::Process (this=0x646cc0) at privatbankpayment.cpp:29
    29			string payment = "amt=" + Payment("amount") + "&ccy=" + Currency("iso") + "&details=" + Payment("description") + "&ext_details=" + Payment("number") + "&pay_way=privat24&order=" + Payment("id") + "&merchant=" + Method("merchid");
    Missing separate debuginfos, use: debuginfo-install coremanager-5.399.0-2307201251307784.el7.x86_64
    CODE

При успешном выполнении отладчик GDB остановится на строке 29 и будет ожидать ввода команд. После остановки вы можете посмотреть:

  • backtrace:

    (gdb) bt
    #0  PrivatBankPayment::Process (this=0x646cc0) at privatbankpayment.cpp:29
    #1  0x00007ffff698ad55 in payment::PaymentCgi::Execute(int, char**) () from /usr/local/mgr5/lib/libpaymentcgi.so
    #2  0x00007ffff6bc713e in ispmain (argc=1, argv=0x7fffffffe438) at privatbankpayment.cpp:65
    #3  0x0000000000401af2 in main ()
    CODE
  • листинг:

    (gdb) list
    24
    25		virtual void Process() {
    26			string post_url = "https://api.privatbank.ua/p24api/ishop";
    27
    28			// “amt=15.25&ccy=UAH&details=книга Будь здоров!&ext_details=1000BDN01&pay_way=privat24&order=000AB1502ZGH&merchant= 75482”,
    29			string payment = "amt=" + Payment("amount") + "&ccy=" + Currency("iso") + "&details=" + Payment("description") + "&ext_details=" + Payment("number") + "&pay_way=privat24&order=" + Payment("id") + "&merchant=" + Method("merchid");
    30			string signature = str::hex::Encode(mgr_hash::sha1(str::hex::Encode(mgr_hash::md5(payment + Method("passwd")))));
    31
    32			string description = str::Trim(Payment("description"));
    33			if (description.empty())
    CODE
  • значение конкретной переменной:

    (gdb) p post_url
    $1 = "https://api.privatbank.ua/p24api/ishop"
    CODE

Подробнее см. документацию GDB: The GNU Project Debugger.