在编译程序时,使用 gcc 或者 g++ 时一定要加上 -g 选项,如

gcc -g -o hello hello.c

以便调试程序含有调试符号信息,从而能够正常调试程序。否则则会出现如下提示,导致不能调试。

Reading symbols from demo...(no debugging symbols found)...done.

除了不加 -g 选项,也可以使用 Linuxstrip 命令移除掉某个程序中的调试信息,我们这里对 hello_server 使用 strip 命令试试:

[root@localhost testclient]# strip hello_server
##使用 strip 命令之前
-rwxr-xr-x. 1 root root 12416 Sep 8 09:45 hello_server
##使用 strip 命令之后
-rwxr-xr-x. 1 root root 6312 Sep 8 09:55 hello_server

可以发现,对 hello_server 使用 strip 命令之后,这个程序明显变小了(由 12416 个字节减少为 6312 个字节)。我们通常会在程序测试没问题以后,将其发布到生产环境或者正式环境中,因此生成不带调试符号信息的程序,以减小程序体积或提高程序执行效率。

注意:

在实际生成调试程序时,一般不仅要加上 -g 选项,也建议 关闭编译器的程序优化选项。编译器的程序优化选项一般有五个级别,从 O0 ~ O4 ( 注意第一个 O0 ,是字母 O 加上数字 0 ), O0 表示不优化,从 O1 ~ O4 优化级别越来越高,O4 最高。这样做的目的是为了调试的时候,符号文件显示的调试变量等能与源代码完全对应起来。

使用 GDB 调试程序一般有三种方式:

  • gdb filename 直接调试目标程序
  • gdb attach pid 附加进程
  • gdb filename corename 调试 core 文件

1. 直接调试目标程序

假设已有二进制文件如下,其中 chapter_3 为可执行文件

$ ls
chapter_3  main.cpp  Makefile  student.cpp  student.h  teacher.cpp  teacher.h
$

执行 gdb 可执行文件名 即可以启动调试,如下图:

$ gdb chapter_3
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 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 chapter_3...done.
(gdb)

如上所示,表示启动调试 chapter_3 成功。这时 gdb 已经成功加载 chapter_3 ,并且可以使用一些 gdb 命令,比如设置断点、查看代码等。执行命令 list 的结果如下所示。

(gdb) list
1   //main.cpp
2   #include <iostream>
3   #include "student.h"
4   #include "teacher.h"
5   int main(int argc,char ** argv)
6   {7       Student stu("Mike",20);
8       printf("Student's Name is %s,age is %d\n",stu.Name(),stu.Age());
9       Teacher teacher("John",2);
10      printf("Teacher's Name is %s,class number is %d\n",teacher.Name(),teacher.classNumber());
(gdb)

接着需要输入 run 命令或者 r ,程序才会真正的运行起来。

(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/chapter_3
Student's Name is Mike,age is 20
Teacher's Name is John,class number is 2
[Inferior 1 (process 24190) exited normally]
(gdb)

输入 q ,退出 gdb 调试。

(gdb) q
wohu@wohu-dev:~/cppProject/book_debug/chapter_3.1$

2. 添加参数

有些程序在启动时需要接收一些参数,如下所示:

#include <iostream>
#include <string>using namespace std;int main(int argc, char *argv[])
{for (int i = 0; i <= argc; i++){cout << "argc[" << i << "] is " << argv[i] << endl;}return 0;
}

使用 gdb 调试,则需要在 gdb 命令窗口中输入以下命令:

set args a b c d

完整命令如下所示:

wohu@wohu-dev:~/cppProject/book_debug/chapter_3.1$ gdb demo
....
Reading symbols from demo...(no debugging symbols found)...done.
(gdb) set args a b c d
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo a b c d
argc[0] is /home/wohu/cppProject/book_debug/chapter_3.1/demo
argc[1] is a
argc[2] is b
argc[3] is c
argc[4] is d
argc[5] is [Inferior 1 (process 24518) exited normally]
(gdb) q
wohu@wohu-dev:~/cppProject/book_debug/chapter_3.1$

可以通过 show args 查看命令行参数是否设置成功。如果单个命令行参数之间含有空格,可以使用引号将参数包裹起来。

(gdb) set args a b c "12  34"
(gdb) show ar
architecture  args
(gdb) show args
Argument list to give program being debugged when it is started is "a b c "12  34"".
(gdb) r
Starting program: /home/weirong/project/cpp/demo a b c "12  34"
argc[0] is /home/weirong/project/cpp/demo
argc[1] is a
argc[2] is b
argc[3] is c
argc[4] is 12  34
argc[5] is [Inferior 1 (process 16433) exited normally]
(gdb)

3. 附加到进程

很多情况下,程序出现问题时并不处于调试状态。也就是说,在我们想要调试程序时,程序已经开始运行,或者服务器代码出现故障时,重启会导致现象丢失,那就只能将 GDB 调试器附加到测试程序上。

如下代码demo.cpp 内容:

#include <iostream>int main()
{int a, b;std::cin >> a >> b;std::cout << a + b << std::endl;return 0;
}

通过 g++ -o demo demo.cpp 生成可执行文件 demo ,执行可执行文件如下:

$ ./demo

这时我们需要将 gdb 附加到进程的命令如下:

gdb attach pid

这里的 pid 就是我们程序运行的进程 ID ,可以通过命令 ps 来获取。在新会话 Shell 命令行中执行以下命令:

ps aux | grep demo

可以看到目标程序的 pid 为 1361,

$ ps aux | grep demo
wohu      1361  0.0  0.0  13996  1848 pts/0    S+   11:30   0:00 ./demo
wohu      1373  0.0  0.0  16180  1088 pts/1    S+   11:30   0:00 grep --color=auto demo

因此,在 Shell 中执行以下命令

gdb attach 1361

如果是普通用户执行可能报如下错误:

$ gdb attach 1361
...
For help, type "help".
Type "apropos word" to search for commands related to "word"...
attach: No such file or directory.
Attaching to process 1361
Could not attach to process.  If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
/home/wohu/cppProject/book_debug/chapter_3.1/1361: No such file or directory.
(gdb) q
$

切换 root 账号,再次执行

# gdb attach 1361
...
Type "apropos word" to search for commands related to "word"...
attach: No such file or directory.
Attaching to process 1361
Reading symbols from /home/wohu/cppProject/book_debug/chapter_3.1/demo...(no debugging symbols found)...done.
Reading symbols from /usr/lib/x86_64-linux-gnu/libstdc++.so.6...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.27.so...done.
done.
Reading symbols from /lib/x86_64-linux-gnu/libm.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libm-2.27.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.27.so...done.
done.
Reading symbols from /lib/x86_64-linux-gnu/libgcc_s.so.1...(no debugging symbols found)...done.
0x00007f4a0928f031 in __GI___libc_read (fd=0, buf=0x55eedbbede70, nbytes=1024)at ../sysdeps/unix/sysv/linux/read.c:27
27  ../sysdeps/unix/sysv/linux/read.c: No such file or directory.
(gdb) list
22  in ../sysdeps/unix/sysv/linux/read.c
(gdb) set args 3 2
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo 3 2r
32767
[Inferior 1 (process 1624) exited normally]
(gdb) q

当提示 Attaching to process 1361 时就说明我们已经成功地将 GDB 附加到目标进程了。

需要注意的是,程序使用了一些系统库(如 libgcc_s.so),由于这是发行版本的 Linux 系统,这些库是没有调试符号的,因而 GDB 会提示找不到这些库的调试符号。因为目的是调试 ./demo,对系统 API 调用的内部实现并不关注,所以这些提示可以不用关注,只要 ./demo 这个文件有调试信息即可。

当用 gdb attach 上目标进程后,调试器会暂停下来,此时可以在 gdb 中输入相关的命令,比如设置断点等,再继续运行程序,此时需要在 gdb 中输入命令 c 继续运行,程序才能恢复为正常状态。

当调试完程序想结束此次调试时,而且不对当前进程 ./demo 有任何影响,也就是说想让这个程序继续运行,可以在 GDB 的命令行界面输入 detach 命令让程序与 GDB 调试器分离,这样 ./demo 就可以继续运行了:

(gdb) detach
Detaching from program: /home/wohu/cppProject/book_debug/chapter_3.1/demo, process 1361

4. 调试 core 文件

有时候,程序运行一段时间后会突然崩溃,只要程序在崩溃的时候有 core 文件产生,就可以使用这个 core 文件来定位崩溃的原因。当然,Linux 系统默认是不开启程序崩溃产生 core 文件这一机制的,我们可以使用 ulimit -c 命令来查看系统是否开启了这一机制。

wohu@ubuntu:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7856
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7856
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
wohu@ubuntu:~$

其中 core file size 那一行默认是 0,表示关闭生成 core 文件,可以使用 ulimit 选项名 设置值 来修改。例如,可以将 core 文件生成改成具体某个值(最大允许的字节数),这里我们使用

ulimit -c unlimited

unlimited-c 选项值)直接修改成不限制大小。

这样修改以后,当我们关闭这个 Linux 会话,设置项的值就会被还原成 0,因此,我们希望这个选项永久生效,永久生效的方式是把 ulimit -c unlimited 这一行加到 /etc/profile 文件中去,放到这个文件最后一行即可。

生成的 core 文件的默认命名方式是 core.pid,举个例子,比如某个程序当时运行时其进程 ID 是 16663,那么它崩溃产生的 core 文件的名称就是 core.16663

通过下面的命令可以调试 core 文件

gdb filename corename

其中,filename 就是程序名,这里就是可执行文件 democorenamecore.16663,我们输入 gdb demo core.16663 来启动调试,然后输入 bt 命令可以看到错误信息。

  • 自定义 core 文件的名称和目录

/proc/sys/kernel/core_uses_pid 可以控制产生的 core 文件的文件名中是否添加 PID 作为扩展,如果添加则文件内容为 1,否则为 0;/proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名。修改方式如下:

echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

各个参数的说明如下:


假设现在的程序叫 test,我们设置该程序崩溃时的 core 文件名如下:

echo "/root/testcore/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

那么最终会在 /root/testcore/ 目录下生成的 testcore 文件名格式如下:

-rw-------. 1 root root 409600 Jan 14 13:54 core-test-13154-1547445291

需要注意的是,您使用的用户必须对指定 core 文件目录具有写权限,否则生成时会因为权限不足而导致无法生成 core 文件。

gdb 笔记(02)— gdb 调试执行(启动调试、添加参数、附加到进程、调试 core 文件)相关推荐

  1. 《netty入门与实战》笔记-02:服务端启动流程

    为什么80%的码农都做不了架构师?>>>    1.服务端启动流程 这一小节,我们来学习一下如何使用 Netty 来启动一个服务端应用程序,以下是服务端启动的一个非常精简的 Demo ...

  2. ant学习笔记之(ant执行命令的详细参数和Ant自带的系统属性)

    2019独角兽企业重金招聘Python工程师标准>>> 一:ant执行命令的详细参数 -buildfile<file>,-file<file>,-f<f ...

  3. Visual Studio附加到进程调试

    转载:http://blog.sina.com.cn/s/blog_557194c30100y7nv.html 当程序发布到服务器上后因环境不完全一致结果可能和我们在开发机器上测试时不一致.这时我们可 ...

  4. 【Android 逆向】代码调试器开发 ( 等待进程状态改变 | detach 脱离进程调试 PTRACE_DETACH | 调试中继续运行程序 PTRACE_CONT )

    文章目录 一.等待进程状态改变 二.detach 脱离进程调试 PTRACE_DETACH 三.调试中继续运行程序 PTRACE_CONT 一.等待进程状态改变 上一篇博客 [Android 逆向]代 ...

  5. 使用 VS 附加到进程 调试发布的网站

    适用场景:调试已发布的网站. 1.把项目 bin 目录下的 pdb 文件复制到服务器上相应网站的 bin 目录下. 2.把VS的调试工具中的 x64 文件夹复制到服务器任意位置. 3.服务器中打开调试 ...

  6. ASP.NET Core Web 应用程序开发期间部署到IIS自定义主机域名并附加到进程调试

    想必大家之前在进行ASP.NET Web 应用程序开发期间都有用到过将我们的网站部署到IIS自定义主机域名并附加到进程进行调试. 那我们的ASP.NET Core Web 应用程序又是如何部署到我们的 ...

  7. VS2017之附加到进程调试

    一.下载Visual Studio 最新版本的VS下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/ 二.部署程序到IIS 1.用vs ...

  8. electron 打开调试_Electron教程:菜鸟学Electron 主进程调试

    浏览器窗口的开发工具仅能调试渲染器的进程脚本(比如 web 页面).为了提供一个可以调试主进程的方法,Electron 提供了 --debug 和 --debug-brk开关. 命令行开关 使用如下的 ...

  9. php学习笔记02:流程控制if、switch、循环、系统函数、文件路径

    流程控制:三大结构即顺序结构.分支结构.循环结构. 流程控制参考 一.顺序结构: 基本结构.代码依次顺序执行. 二.分支结构: 含if分支.switch分支 1.if分支: if分支基本语法: ①最简 ...

  10. ionic+vue+capacitor系列笔记--02项目中集成Capacitor,添加android,ios平台,真机运行项目

    Capacitor是什么? Capacitor是由ionic团队开发的一款跨平台移动应用构建工具,可轻让我们轻松的构建Android.iOS.Electron和Web应用程序. Capacitor是A ...

最新文章

  1. SCCM 2012 SP1系列(十)配置补丁更新-3
  2. C# MemoryStream先写后读的奇怪现象
  3. c#中关于协变性和逆变性(又叫抗变)帮助理解
  4. php 加密保存mysql_PHP及MYSQL中字符串加密函数
  5. Java基础---认识多态
  6. 【我的物联网成长记1】如何进行端到端开发?
  7. 干掉13个区块链最常见的Bug!
  8. 刚刚,贺建奎回应一切:如果是我孩子,我会第一个去试验
  9. 小希的迷宫(HDU 1272 并查集判断生成树)
  10. [译]反射(Reflection)和动态(dynamic)
  11. stm32无源蜂鸣器定时器_【STM32H7教程】第20章 STM32H7的GPIO应用之无源蜂鸣器...
  12. 数字图像处理-直方图均衡化,直方图规定化
  13. crossApp初级-CAView类-5
  14. mysql删除命令历史记录_MySQL历史命令记录清除
  15. html 5 游戏 脚本,HTML 5开发RPG游戏之四(游戏脚本化)(2)
  16. 好看的充电宝有哪些?好看的充电宝推荐
  17. 分析肖特基二极管的优势与结构应用
  18. 手机抓包+注入黑科技HttpCanary——最强大的Android抓包注入工具
  19. 安卓虎牙云游戏 无限畅玩3A大作
  20. GBDT/xgboost总结

热门文章

  1. 按键精灵/触控精灵 多点找怪,多点找色算法思路,附带动态分析图,以及算法代码
  2. 传奇登录器自动获取服务器,gom引擎配置登录器补丁读取规则的说明
  3. 小红书数据监测,品牌方必看的笔记投放技巧!
  4. css米奇,屹立48年不倒的IP,机械姬为什么能火这么多年?
  5. linux 怎么看浏览器,Linux下浏览器比比看
  6. Ubuntu无法重启:教你用u盘系统修复ubuntu
  7. mac中怎么打摄氏度的圆点
  8. 歪唱《七里香》——致敬杰伦
  9. 群辉DSM6.2下载 Transmission中文版介绍以及出现 syntax error near unexpected token 问题解决
  10. UVA - 10286