赞
踩
在前文 基于vscode 打造Linux C++编码环境 一期中,讲解了如何基于vscode搭建Linux c++的编码环境,但是还没有讲解如何基于vscode搭建调试环境。本期,主要有两个任务:
- 本文更好的阅读体验,可以点击: 手把手教你学会gdb,适应Linux调试环境
- 更多硬核知识,vx搜一搜:
look_code_art
,更多硬核等你发现,- 也可以添加个人 vx:
fibonaccii_
在 深入了解C++系列中,我经常使用如下的格式进行编译、执行demo:
$ g++ -g -O0 main.cc -o main && ./main
下面,我们来看看常用的gcc编译选项有哪些。
选项 | 作用 |
---|---|
-E | 生成预处理文件 |
-S | 生成汇编文件 |
-c | 生成可目标文件 |
-o | 指定生成文件的文件名 |
-On | 指定代码优化等级 |
-g | 用于gdb调试、objdump |
-Wall | 显示代码中的所有warning行为 |
-w | 禁止显示代码中的warning行为 |
-Werror | 将代码中的warning行为视为为error |
-D | 设置预定义宏 |
-l | 链接(link)指定的函数库 |
-std=c++11 | 指定编译代码的C++标准为C++11 |
对于这些编译选项,简单的解释下。
-E
、 -S
、-c
三个选项直接对应着编译的前三个基本阶段
将源文件main.cc
经过预处理后,生成文件预处理所得文件main.i
g++ -E main.cc -o main.i
将 main.i
文件翻译成一个汇编文件 main.s
;
g++ -S main.i -o main.s
运行汇编器,将 main.s
翻译成一个可重定位目标文件 main.o
;
g++ -c main.s -o main.o
运行链接器,将 main.o
中使用到的目标文件组合起来,并创建一个可执行的文件 main
。由于main.cc
代码没有额外的依赖,因此可以直接输出main
文件。
g++ main.o -o main
实际上,一步就能完成上面所有的操作:
g++ main.cc -o main
比如,对于下面的一段demo,如果定义了宏DEBUG
,则输出hello cpp
。
int main(int argc, char const *argv[]) {
#ifdef DEBUG
std::cout<<"Hello Cpp" <<std::endl;
#endif
return 0;
}
下面在gcc
编译时基于-D
选项设置DEBUG
宏,来控制程序执行。
$ g++ -DDEBUG main.cc -o main && ./main
Hello Cpp
对于GCC的编译选项,没有必要全部记住,记住常用的即可,其他用到了再去官网查询:
https://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html
本期主要讲解下我常用的gdb指令、以及怎么去学习gdb。希望能通过本期博客,能帮助你摆脱对gdb恐惧,并熟悉下gdb的常用指令,对于没有讲解到的指令,在本期之后,可以去官方网站自行学习,那里有着详细且为全面的介绍:
https://sourceware.org/gdb/current/onlinedocs/gdb/
为了方便后面基于gdb调试REDIS源码的讲解,可以先下载REDIS6.0的源码,并在编译代码的时候,加上-g -O0
选项,生成调试信息。比如,我学习REDIS的时候,编译指令如下:
$ git clone https://github.com/redis/redis.git # 下载redis源码
$ cd redis/src # 进入源代码
$ make FLAGS="-g -O0" -j 16 # 编译
$ ./redis-server # 运行REDIS服务器
关于启动gdb的方式,下面介绍下常用的三种启动gdb方式:
gdb [program]
:这种方式最常用,比如使用gdb调试上面编译生成的main
文件,那么就直接 gdb main
。gdb [program] core
:用于调试导致coredump
的错误,此时需要在program
后面加上因为coredump生成的core文件路径。gdb -p [pid]
:使用gdb调试正在运行的pid
进程以如下的main
程序为例:
// main.cc
#include <iostream>
int main(int argc, char const *argv[])
{
int cnt =0;
for(int idx=0; idx < 10; ++idx) {
cnt++;
}
std::cout<<cnt<<std::endl;
return 0;
}
编译指令:
$ g++ -g -O0 main.cc -o main
在终端输入gdb main
,会从main
文件中加载符号表,便于设置断点等信息:
$ gdb main GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 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-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"... # 以上都是关于gdb的开源信息,为便于描述,下面的教程中会省略这部分信息 Reading symbols from main... (gdb)
输入gdb main
后,会首先显示关于gdb
的一大串的开源信息,而且每次启动都会显示。因此,在后文的讲解中,每次启动gdb会省略掉这部分信息。
如果某个程序正在运行出现故障,比如服务器程序,无法被中止,如何使用gdb来调试它?
比如,此刻我电脑正在运行REDIS服务器程序,其pid是1607:
gdb
attach pid
命令来调试正在运行的REDIS服务器程序示例如下:
$ sudo gdb # 先以root权限启动gdb
# ...关于gdb的开源声明省略
(gdb) attach 1607 # 再使当前gdb环境去调试redis服务器
Attaching to process 1607
[New LWP 1608]
[New LWP 1609]
[New LWP 1610]
[New LWP 1611]
[New LWP 1612]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f2d694925ce in epoll_wait (epfd=5, events=0x7f2d68ede980, maxevents=10128, timeout=100)
at ../sysdeps/unix/sysv/linux/epoll_wait.c:30
30 in ../sysdeps/unix/sysv/linux/epoll_wait.c
(gdb)
当使用attach
命令调试完服务器程序,可以使用detach
指令退出。
(gdb) detach
Detaching from program: /home/szza/redis-6.0.5/redis-6.0.5/src/redis-server, process 1607
[Inferior 1 (process 1607) detached]
当然,也可以直接使用gdb -p pid
指令,来调试正在运行的REDIS服务器程序,其效果和attach
一致:
$ sudo gdb -p 1607 # 也要使用root权限
Attaching to process 1607
[New LWP 1608]
[New LWP 1609]
[New LWP 1610]
[New LWP 1611]
[New LWP 1612]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
--Type <RET> for more, q to quit, c to continue without paging--
0x00007f2d694925ce in epoll_wait (epfd=5, events=0x7f2d68ede980, maxevents=10128, timeout=100)
at ../sysdeps/unix/sysv/linux/epoll_wait.c:30
30 in ../sysdeps/unix/sysv/linux/epoll_wait.c
毫无疑问,这也是可以由detach
命令,退出调试环境:
(gdb) detach
Detaching from program: /home/szza/redis-6.0.5/redis-6.0.5/src/redis-server, process 1607
[Inferior 1 (process 1607) detached]
其他启动gdb的方式,可以参考官方文档:
https://sourceware.o
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。