• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

无信不立

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【c++】gdb的简单调试程序

一、如下是一段可以正常运行的C++代码

#include <iostream>
#include <stdio.h>
using namespace std;
int main ()
{
    unsigned long long int n, sum;
    n = 1;
    sum = 0;
    while (n <= 100)
    {
        sum = sum + n;
        n = n + 1;

        cout << "sxf test sum="+std::to_string(sum) <<endl;
        cout << "sxf test n="+std::to_string(n) <<endl;
    }
    return 0;
}

此源码的完整存储路径为 /data/home/xxshang/sxftest

 

二、使用GDB的前期准备

通过前面的学习我们知道,GDB 的主要功能就是监控程序的执行流程。这也就意味着,只有当源程序文件编译为可执行文件并执行时,GDB 才会派上用场。

Linux 发行版中,经常使用 GCC 编译 C、C++ 程序(有关 GCC 编译器,读者可猛击《GCC编译器》系统学习)。但需要注意的是,仅使用 gcc(或 g++)命令编译生成的可执行文件,是无法借助 GDB 进行调试的。

以 main.c 源文件为例,正常情况下,使用 GCC 编译该源代码的指令如下:

g++ sxf.cpp -o myapp

 可以看到,这里已经生成了 sxf.cpp 对应的执行文件 myapp,但值得一提的是,此文件不支持使用 GDB 进行调试。原因很简单,使用 GDB 调试某个可执行文件,该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),而上面生成的 mapp 则没有。

那么,如何生成符合 GDB 调试要求的可执行文件呢?很简单,只需要使用 g++ -g 选项编译源文件,即可生成满足 GDB 要求的可执行文件。仍以 sxf.cpp 源程序文件为例:

g++ sxf.cpp -o myapp -g

由此生成的 myapp,即可使用 GDB 进行调试

值得一提的是,GCC 编译器支持 -O(等于同 -O1,优化生成的目标文件)和 -g 一起参与编译。GCC 编译过程对进行优化的程度可分为 5 个等级,分别为 O0~O4,O0 表示不优化(默认选项),从 O1 ~ O4 优化级别越来越高,O4 最高。

所谓优化,例如省略掉代码中从未使用过的变量、直接将常量表达式用结果值代替等等,这些操作会缩减目标文件所包含的代码量,提高最终生成的可执行文件的运行效率。

而相对于 -O -g 选项,对 GDB 调试器更友好的是 -Og 选项,-Og 对代码所做的优化程序介于 O0 ~ O1 之间,真正可做到“在保持快速编译和良好调试体验的同时,提供较为合理的优化级别”。
解决了如何生成满足 GDB 调试器要求的可执行文件,接下来正式学习 GDB 调试器的使用。

 

 

三、启动GDB进行调试

在生成包含调试信息的 myapp 可执行文件的基础上,启动 GDB 调试器的指令如下:

[xxshang@VM-212-227-tencentos sxftest]$ g++ sxf.cpp -o myapp -g
[xxshang@VM-212-227-tencentos sxftest]$ ls
myapp  sxf.cpp
[xxshang@VM-212-227-tencentos sxftest]$ gdb myapp 
GNU gdb (GDB) Red Hat Enterprise Linux 9.2-4.tl3
Copyright (C) 2020 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".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from myapp...
(gdb) 

 注意,该指令在启动 GDB 的同时,会打印出一堆免责条款。通过添加 --silent(或者 -q、--quiet)选项,可将比部分信息屏蔽掉:

[xxshang@VM-212-227-tencentos sxftest]$ gdb myapp --silent
Reading symbols from myapp...
(gdb) 

无论使用以上哪种方式,最终都可以启动 GDB 调试器,启动成功的标志就是最终输出的 (gdb)。通过在 (gdb) 后面输入指令,即可调用 GDB 调试进行对应的调试工作。
GDB 调试器提供有大量的调试选项,可满足大部分场景中调试代码的需要。如表 1 所示,罗列了几个最常用的调试指令及各自的作用:

调试指令作 用
(gdb) break xxx
(gdb) b xxx
在源代码指定的某一行设置断点,其中 xxx 用于指定具体打断点的位置。
(gdb) run
(gdb) r
执行被调试的程序,其会自动在第一个断点处暂停执行。
(gdb) continue
(gdb) c
当程序在某一断点处停止运行后,使用该指令可以继续执行,直至遇到下一个断点或者程序结束。
(gdb) next
(gdb) n
令程序一行代码一行代码的执行。
(gdb) print xxx
(gdb) p xxx
打印指定变量的值,其中 xxx 指的就是某一变量名。
(gdb) list
(gdb) l
显示源程序代码的内容,包括各行代码所在的行号。
(gdb) quit
(gdb) q
终止调试。

如上所示,每一个指令既可以使用全拼,也可以使用其首字母表示。另外,表 1 中罗列的指令仅是冰山一角,GDB 还提供有大量的选项,可以通过 help 选项来查看。有关 help 选项的具体用法,读者可阅读《GDB查看命令》一节,这里不再做具体赘述。

仍以myapp 可执行程序为例,接下来为读者演示表 1 中部分选项的功能和用法:

[xxshang@VM-212-227-tencentos sxftest]$ gdb myapp --silent
Reading symbols from myapp...
(gdb) l  //用 l指令查看当前的代码行数(gdb新增的)
1       #include <iostream>
2       #include <stdio.h>
3       using namespace std;
4       int main ()
5       {
6           unsigned long long int n, sum;
7           n = 1;
8           sum = 0;
9           while (n <= 100)
10          {
(gdb)  //如果展示不完,则直接按 回车Enter键, 就会继续展示 (默认gdb只会展示10行的内容)
11              sum = sum + n;
12              n = n + 1;
13
14              cout << "sxf test sum="+std::to_string(sum) <<endl;
15              cout << "sxf test n="+std::to_string(n) <<endl;
16          }
17          return 0;
18      }
(gdb) b 11 //给第11行代码设置了一个端点
Breakpoint 1 at 0x4013bd: file sxf.cpp, line 11.
(gdb) r  //开始运行程序
Starting program: /data/home/xxshang/sxftest/myapp 

Breakpoint 1, main () at sxf.cpp:11  //端点在11行停住了
11              sum = sum + n;
Missing separate debuginfos, use: dnf debuginfo-install bash-4.4.20-4.tl3.tencentos.x86_64 glibc-2.28-225.tl3.6.x86_64 libgcc-8.5.0-18.tl3.x86_64 libstdc++-8.5.0-18.tl3.x86_64
(gdb) p sum  //打印变量sum的值
$1 = 0
(gdb) p n  //打印变量 n的值
$2 = 1
(gdb) b 15  //在代码第15行,再新设置一个端点
Breakpoint 2 at 0x401431: file sxf.cpp, line 15.
(gdb) c   //直接将代码跳转到下一个端点(或继续运行)
Continuing.
sxf test sum=1

Breakpoint 2, main () at sxf.cpp:15
15              cout << "sxf test n="+std::to_string(n) <<endl;
(gdb) p sum //打印p的值
$3 = 1
(gdb) p n //打印n的值
$4 = 2
(gdb) 
$5 = 2
(gdb) c  //直接运行到下一个断点
Continuing.
sxf test n=2

Breakpoint 1, main () at sxf.cpp:11
11              sum = sum + n;
(gdb) c
Continuing.
sxf test sum=3

Breakpoint 2, main () at sxf.cpp:15
15              cout << "sxf test n="+std::to_string(n) <<endl;
(gdb) p sum  //打印sum的值
$6 = 3
(gdb) p n //打印n的值
$7 = 3
(gdb) q  //退出监听
A debugging session is active.

        Inferior 1 [process 116448] will be killed.

Quit anyway? (y or n) y  //  <-- 确实是否退出调试,y 为退出,n 为不退出

 

posted on 2024-07-25 11:34  无信不立  阅读(47)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3