当前位置: 首页 > news >正文

GDB调试指北-启动调试或者附加到进程

文章目录

  • 前言
  • 测试样例
    • 代码内容
    • 代码编译
    • 运行程序
  • 使用gdb调试
    • 使用gdb调试core文件
      • 调试过程
    • 使用gdb直接启动程序
      • 调试过程
    • 使用gdb调试正在运行的文件
  • 语法对比
  • 总结

前言

要想使用 gdb 调试程序,必须让 gdb 程序和被调试程序建立联系,这种联系可以通过程序的可执行文件、core文件或者正在运行的进程来建立,具体调试的时候使用的选项不同,涉及到参数的传递,选项的顺序,多进程启动前的设置等等,接下来可以看一些常见用法。

测试样例

首先来写一段简单的但是会自动崩溃的代码,主要是为了展示core文件的调试方法,通过调试崩溃产生的core文件是一种很直接的查找问题的方法,可以帮助我们快速定位到问题的栈帧,进而找到具体的逻辑代码。

代码内容

新建文件 examplepro.cpp,编写代码内容如下:

#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    if (argc > 1)
        cout << "argv[1] = " << argv[1] << endl;

    int a = 3, b = 4;
    int c = a + b;

    cout << "c = " << c << endl;

    int *p = NULL;
    *p = c;

    return 0;
}

代码编译

g++ examplepro.cpp -o examplepro -g

运行程序

albert@home-pc:~/WorkSpace/cpp$ ./examplepro
c = 7
Segmentation fault (core dumped)

我们发现程序在运行之后发生了段错误,这是一种比较常见的BUG,通常由访问无效内存导致,查看程序目录下内容,多了一个叫 core 的文件。

albert@home-pc:~/WorkSpace/cpp$ ls
core  examplepro  examplepro.cpp

通过这一步你可能看不到这个 core 文件,需要检查两点,第一是编译的时候需要加 -g 选项,第二是使用 ulimit -c unlimited 命令设置core文件占用空间的最小限制,默认大小为0,也就是不产生 core 文件,需要改为 unlimited 才可以,如果你确定产生的 core 文件不会太大,也可以设置一个具体的数值。

使用gdb调试

有了上面的程序我们就可以进行调试了,因为已经产生了 core 文件,所以先来调试一下 core 文件,看下程序崩溃的原因。

使用gdb调试core文件

启动程序的语法如下,gdb 命令之后跟程序名,然后后面跟着 core 文件的名字:

gdb examplepro core

具体调试的时候需要换成自己的崩溃的程序名,而core文件大多数是 core.进程id 的形式。

调试过程

albert@home-pc:~/WorkSpace/cpp$ gdb examplepro core
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 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-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 examplepro...done.
[New LWP 19786]
Core was generated by `./examplepro'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000400932 in main (argc=1, argv=0x7ffd23cc3a18) at examplepro.cpp:15
15      *p = c;
(gdb)

从调试信息来看一下就定位到了问题,在代码的第15行发生了段错误,也就是我们刚刚给野指针赋值的代码。

使用gdb直接启动程序

这种情况就是调试运行,相当于在 gdb 的监控下启动程序,一旦发生错误,gdb 会给出响应的提示,启动方式很简单,gdb 命令之后直接跟着程序名字就可以了。

gdb examplepro

调试过程

albert@home-pc:~/WorkSpace/cpp$ gdb examplepro
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 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-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 examplepro...done.
(gdb) run
Starting program: /home/albert/WorkSpace/cpp/examplepro
c = 7

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400932 in main (argc=1, argv=0x7fffffffdd18) at examplepro.cpp:15
15      *p = c;
(gdb)

这种情况下,启动之后需要输入 run 命令才可以运行程序,这时发现程序又崩溃了。

如果被调试的程序有参数的话,需要将启动的命令进行修改,写成 gdb --args examplepro testparam1,加上 --args 选项,然后将参数罗列在后面就好了,因为看这些声明很麻烦,我们利用之前学过的 -q 选项来屏蔽启动说明,测试如下:

albert@home-pc:~/WorkSpace/cpp$ gdb -q --args examplepro NB
Reading symbols from examplepro...done.
(gdb) run
Starting program: /home/albert/WorkSpace/cpp/examplepro NB
argv[1] = NB
c = 7

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400932 in main (argc=2, argv=0x7fffffffdd08) at examplepro.cpp:15
15      *p = c;
(gdb)

还有一种写法就是启动 gdb 之后再传参数,具体操作方法如下:

albert@home-pc:~/WorkSpace/cpp$ gdb -q examplepro
Reading symbols from examplepro...done.
(gdb) run NB
Starting program: /home/albert/WorkSpace/cpp/examplepro NB
argv[1] = NB
c = 7

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400932 in main (argc=2, argv=0x7fffffffdd08) at examplepro.cpp:15
15      *p = c;
(gdb)

这种情况是先启动 gdb,然后在执行 run 命令的时候传递参数。

使用gdb调试正在运行的文件

这时需要获得被套是程序的进程id,可以使用 pstop 或者 pidof 命令来获取进程id,然后通过 attch 的方式附加到进程。

比如查到需要调试的 examplepro 程序进程号是 3598,那么可以直接启动 gdb 附加到这个进程:

gdb examplepro 3598

也可以先启动 gdb,然后使用 attach 命令附加到进程:

albert@home-pc:~/WorkSpace/cpp$ gdb -q examplepro
Reading symbols from examplepro...done.
(gdb) attach 3598

如果此时提示进程拒绝被附加通常是权限问题,可以使用所属账号调试,或者可以尝试 sudo 命令。

语法对比

常见的调试方式就文中提到的这几种,特整理成表格方便对比和查找:

语法解释
gdb examlepro直接 gdb 调试启动
gdb examlepro core.3598调试崩溃的 core 文件
gdb examlepro 3598
gdb -p 3598
附加到正在运行的程序进程上
gdb
attach 3598
先启动gdb,后附加到程序上

总结

  • gdb 不但可以调试 core 文件,还可以调试正在运行的程序,这对于难重现的 bug 来说非常有帮助
  • 在调试正在运行的程序时可以使用 pidof 命令来直接获取被调试程序的进程号
  • gdb 调试附加的进程的时候要注意权限问题,如果不成功可以尝试 sudo 命令

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

兜兜转转又换了一个住所,匆匆忙忙如蝼蚁般迁徙,路程短了,可选的路却少了。回头看看,一个窝、一段事、一群人而已~

2020-8-25 00:24:01

相关文章:

  • Python中时间戳、时间字符串、时间结构对象之间的相互转化
  • git log根据特定条件查询日志并统计修改的代码行数
  • C++中优先队列priority_queue的基础用法
  • C++求解组合数的具体实现
  • 东拉西扯01世界的沧海桑田
  • Go语言在解决实际问题时的优点与不便
  • 使用Spreadsheet Compare工具对比Excel文件差异
  • linux环境下使用sort命令完成常见排序操作
  • 关于数据一致性的思考
  • linux环境下sed命令的基础用法
  • 学习cmake从成功编译一个小程序开始
  • linux环境下使用netstat命令查看网络信息
  • 简单聊聊01世界中编码和解码这对磨人的小妖儿
  • C/C++中有符号数隐式类型转换成无符号数需注意的问题
  • system_clock::now()和time()时间函数混用带来的踩坑经历
  • hexo+github搭建个人博客
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 「译」Node.js Streams 基础
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Brief introduction of how to 'Call, Apply and Bind'
  • C++入门教程(10):for 语句
  • Electron入门介绍
  • flask接收请求并推入栈
  • Hibernate【inverse和cascade属性】知识要点
  • jdbc就是这么简单
  • JS函数式编程 数组部分风格 ES6版
  • Node 版本管理
  • Node项目之评分系统(二)- 数据库设计
  • PHP的类修饰符与访问修饰符
  • webgl (原生)基础入门指南【一】
  • windows下mongoDB的环境配置
  • 机器学习中为什么要做归一化normalization
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 坑!为什么View.startAnimation不起作用?
  • 码农张的Bug人生 - 见面之礼
  • 面试遇到的一些题
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 区块链技术特点之去中心化特性
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 思维导图—你不知道的JavaScript中卷
  • 微信支付JSAPI,实测!终极方案
  • 追踪解析 FutureTask 源码
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​插件化DPI在商用WIFI中的价值
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • $$$$GB2312-80区位编码表$$$$
  • $forceUpdate()函数
  • (2.2w字)前端单元测试之Jest详解篇
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (ZT)出版业改革:该死的死,该生的生
  • (一)插入排序
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建