<<<<<<< HEAD
Linux调试器-gdb
1. 背景
程序的发布方式有两种,Debug模式和release模式
为什么要存在两种?
Debug模式通常用于开发阶段,它会保留所有的调试信息,包括符号表、断点和日志,以便开发人员可以轻松地调试和定位问题。此外,Debug模式通常会关闭一些优化选项,以便在开发过程中能够更快地构建和运行程序。这样可以加快开发人员的迭代速度,提高开发效率
release模式则用于最终发布产品的版本。它会启用各种优化选项,以提高程序的性能和减小体积。同时,release模式会删除所有的调试信息,从而减小程序的体积和保护源代码不被泄露。这样可以确保最终发布的产品具有更好的性能和安全性
Linux gcc/g++编译程序默认是什么模式?
在默认的情况下,Linux gcc/g++出来的二进制程序,默认是release模式
gcc的默认行为:
默认动态链接
默认release发布
如何以Debug模式下发布?
在使用gcc/g++编译时加上 -g选项 比如:
gcc -o mytest test.c -g
可执行程序也有格式!
格式为:ELF
查看可执行程序添加的调试信息:
readelf指令(elf为可执行程序的格式)
readelf -S mytest | grep -i debug
[27] .debug_aranges PROGBITS 0000000000000000 00001069[28] .debug_info PROGBITS 0000000000000000 00001099[29] .debug_abbrev PROGBITS 0000000000000000 00001181[30] .debug_line PROGBITS 0000000000000000 000011fd[31] .debug_str PROGBITS 0000000000000000 00001260
2. 使用
在此之前需要先确保Linux机器上是否安装gdb,安装指令:
sudo yum install -y gdb
进入调试:
gdb binFile
在此之前我们先来看一下Windows版本基本调试功能:
- 运行起来才能调试
- 调试时可以看到代码
- 打断点
- 局部调试
- 看到局部变量的内容和地址
- 看到调用栈
- 单步
- 进入函数
Linux调试器gdb:
- l 行号:显示指定行之后的代码(gdb自动记录最近一条指令)
(gdb) l 0#include<stdio.h>int Sum (int n){int i = 1;int sum = 0;for(; i <= n; i++){sum +=i;}(gdb)
点击回车可以继续查看后边的代码
- 打断点:在指定位置打断点
b 行号
(gdb) b 20Breakpoint 1 at 0x4005e5: file test.c, line 20.
b 文件名:行号
(gdb) b test.c:30Breakpoint 2 at 0x400649: file test.c, line 30.
b 函数名
(gdb) b SumBreakpoint 3 at 0x400584: file test.c, line 5.
- 查看断点:info b
(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
- 关闭断点:disable 断点编号
(gdb) disable 1(gdb) info bNum Type Disp Enb Address What1 breakpoint keep n 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
此时编号为1的断点已被关闭,keep后边属性显示n(no)
- 开启断点:enable 断点编号
(gdb) enable 1(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
- r开始调试:直接跳到断点位置
(gdb) rStarting program: /home/test/git仓库/note-warehouse/gdbtest/mytesthello world!hello world!hello world!hello world!hello world!
Breakpoint 1, main () at test.c:2020 printf("hello world!\n");Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
直接跳转到了第一个断点位置
- 逐语句 s(可进入函数)
- 逐过程 n(逐行执行)
- quit:退出gdb
- display 变量的内容和地址:跟踪查看一个变量,每次停下来都显示它的值
(gdb) display i1: i = 1
(gdb) display sum2: sum = 4195472
(gdb) s7 for(; i <= n; i++)2: sum = 01: i = 1(gdb)9 sum +=i;2: sum = 01: i = 1(gdb)7 for(; i <= n; i++)2: sum = 11: i = 1
每次逐语句执行时都输出了sum和i的值
- undisplay 编号:取消常显示变量的内容和地址
(gdb) undisplay 2(gdb) s9 sum +=i;1: i = 2(gdb)7 for(; i <= n; i++)1: i = 2(gdb)
c 直接跳到下一个断点
(gdb) rStarting program: /home/test/git仓库/note-warehouse/gdbtest/mytesthello world!hello world!hello world!hello world!hello world!
Breakpoint 1, main () at test.c:2020 printf("hello world!\n");(gdb) cContinuing.hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!
Breakpoint 2, main () at test.c:3131 int ret = Sum(100);
重新开始调试,r直接执行到第一个断点位置,c执行到下个断点
d 断点编号:删除断点
(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:20breakpoint already hit 1 time2 breakpoint keep y 0x0000000000400649 in main at test.c:30breakpoint already hit 1 time3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5(gdb) d 1(gdb) info bNum Type Disp Enb Address What2 breakpoint keep y 0x0000000000400649 in main at test.c:30breakpoint already hit 1 time3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5(gdb)
- finish:执行完当前函数并返回,然后停下来
(gdb) s
Breakpoint 3, Sum (n=100) at test.c:55 int i = 1;1: i = 0(gdb)6 int sum = 0;1: i = 1(gdb)7 for(; i <= n; i++)1: i = 1(gdb) finishRun till exit from #0 Sum (n=100) at test.c:70x0000000000400653 in main () at test.c:3131 int ret = Sum(100);Value returned is $1 = 5050
我们调试进入Sum函数,可以通过finish指令检查Sum函数,finish指令让Sum函数立即执行完毕,并返回返回值
- breaktrace(或bt):查看各级函数调用及参数
(gdb) bt#0 0x0000000000400653 in main () at test.c:31
- until 行号:跳至对应行(范围执行)
(gdb) s
Breakpoint 3, Sum (n=100) at test.c:55 int i = 1;1: i = 0(gdb)6 int sum = 0;1: i = 1(gdb)7 for(; i <= n; i++)1: i = 1(gdb)9 sum +=i;1: i = 1
重新调试进入Sum函数的循环,我们发现代码一直卡在9行和7行,我们又不想立即执完函数,就要求立即执行完循环,这时就可以使用until
(gdb) until 11Sum (n=100) at test.c:1111 return sum;1: i = 101
直接跳到11行,这样就可以直接执行完循环
- p 变量:打印变量值。
(gdb) p sum$2 = 5050
- set var 变量:修改变量的值(不用修改代码,测试其他分支)
比如我们在测试if语句分支时
if(flag==1)……
else ……
如果代码中以及规定flag值为1,但是又不想重新打开代码进行修改,这时就可以使用set var
比如:
set var flag=0
就可以直接修改flag的值来测试另一条分支
=======
Linux调试器-gdb
1. 背景
程序的发布方式有两种,Debug模式和release模式
为什么要存在两种?
Debug模式通常用于开发阶段,它会保留所有的调试信息,包括符号表、断点和日志,以便开发人员可以轻松地调试和定位问题。此外,Debug模式通常会关闭一些优化选项,以便在开发过程中能够更快地构建和运行程序。这样可以加快开发人员的迭代速度,提高开发效率
release模式则用于最终发布产品的版本。它会启用各种优化选项,以提高程序的性能和减小体积。同时,release模式会删除所有的调试信息,从而减小程序的体积和保护源代码不被泄露。这样可以确保最终发布的产品具有更好的性能和安全性
Linux gcc/g++编译程序默认是什么模式?
在默认的情况下,Linux gcc/g++出来的二进制程序,默认是release模式
gcc的默认行为:
默认动态链接
默认release发布
如何以Debug模式下发布?
在使用gcc/g++编译时加上 -g选项 比如:
gcc -o mytest test.c -g
可执行程序也有格式!
格式为:ELF
查看可执行程序添加的调试信息:
readelf指令(elf为可执行程序的格式)
readelf -S mytest | grep -i debug
[27] .debug_aranges PROGBITS 0000000000000000 00001069[28] .debug_info PROGBITS 0000000000000000 00001099[29] .debug_abbrev PROGBITS 0000000000000000 00001181[30] .debug_line PROGBITS 0000000000000000 000011fd[31] .debug_str PROGBITS 0000000000000000 00001260
2. 使用
在此之前需要先确保Linux机器上是否安装gdb,安装指令:
sudo yum install -y gdb
进入调试:
gdb binFile
在此之前我们先来看一下Windows版本基本调试功能:
- 运行起来才能调试
- 调试时可以看到代码
- 打断点
- 局部调试
- 看到局部变量的内容和地址
- 看到调用栈
- 单步
- 进入函数
Linux调试器gdb:
- l 行号:显示指定行之后的代码(gdb自动记录最近一条指令)
(gdb) l 0#include<stdio.h>int Sum (int n){int i = 1;int sum = 0;for(; i <= n; i++){sum +=i;}(gdb)
点击回车可以继续查看后边的代码
- 打断点:在指定位置打断点
b 行号
(gdb) b 20Breakpoint 1 at 0x4005e5: file test.c, line 20.
b 文件名:行号
(gdb) b test.c:30Breakpoint 2 at 0x400649: file test.c, line 30.
b 函数名
(gdb) b SumBreakpoint 3 at 0x400584: file test.c, line 5.
- 查看断点:info b
(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
- 关闭断点:disable 断点编号
(gdb) disable 1(gdb) info bNum Type Disp Enb Address What1 breakpoint keep n 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
此时编号为1的断点已被关闭,keep后边属性显示n(no)
- 开启断点:enable 断点编号
(gdb) enable 1(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:202 breakpoint keep y 0x0000000000400649 in main at test.c:303 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
- r开始调试:直接跳到断点位置
(gdb) rStarting program: /home/test/git仓库/note-warehouse/gdbtest/mytesthello world!hello world!hello world!hello world!hello world!
Breakpoint 1, main () at test.c:2020 printf("hello world!\n");Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
直接跳转到了第一个断点位置
- 逐语句 s(可进入函数)
- 逐过程 n(逐行执行)
- quit:退出gdb
- display 变量的内容和地址:跟踪查看一个变量,每次停下来都显示它的值
(gdb) display i1: i = 1
(gdb) display sum2: sum = 4195472
(gdb) s7 for(; i <= n; i++)2: sum = 01: i = 1(gdb)9 sum +=i;2: sum = 01: i = 1(gdb)7 for(; i <= n; i++)2: sum = 11: i = 1
每次逐语句执行时都输出了sum和i的值
- undisplay 编号:取消常显示变量的内容和地址
(gdb) undisplay 2(gdb) s9 sum +=i;1: i = 2(gdb)7 for(; i <= n; i++)1: i = 2(gdb)
c 直接跳到下一个断点
(gdb) rStarting program: /home/test/git仓库/note-warehouse/gdbtest/mytesthello world!hello world!hello world!hello world!hello world!
Breakpoint 1, main () at test.c:2020 printf("hello world!\n");(gdb) cContinuing.hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!hello world!
Breakpoint 2, main () at test.c:3131 int ret = Sum(100);
重新开始调试,r直接执行到第一个断点位置,c执行到下个断点
d 断点编号:删除断点
(gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e5 in main at test.c:20breakpoint already hit 1 time2 breakpoint keep y 0x0000000000400649 in main at test.c:30breakpoint already hit 1 time3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5(gdb) d 1(gdb) info bNum Type Disp Enb Address What2 breakpoint keep y 0x0000000000400649 in main at test.c:30breakpoint already hit 1 time3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5(gdb)
- finish:执行完当前函数并返回,然后停下来
(gdb) s
Breakpoint 3, Sum (n=100) at test.c:55 int i = 1;1: i = 0(gdb)6 int sum = 0;1: i = 1(gdb)7 for(; i <= n; i++)1: i = 1(gdb) finishRun till exit from #0 Sum (n=100) at test.c:70x0000000000400653 in main () at test.c:3131 int ret = Sum(100);Value returned is $1 = 5050
我们调试进入Sum函数,可以通过finish指令检查Sum函数,finish指令让Sum函数立即执行完毕,并返回返回值
- breaktrace(或bt):查看各级函数调用及参数
(gdb) bt#0 0x0000000000400653 in main () at test.c:31
- until 行号:跳至对应行(范围执行)
(gdb) s
Breakpoint 3, Sum (n=100) at test.c:55 int i = 1;1: i = 0(gdb)6 int sum = 0;1: i = 1(gdb)7 for(; i <= n; i++)1: i = 1(gdb)9 sum +=i;1: i = 1
重新调试进入Sum函数的循环,我们发现代码一直卡在9行和7行,我们又不想立即执完函数,就要求立即执行完循环,这时就可以使用until
(gdb) until 11Sum (n=100) at test.c:1111 return sum;1: i = 101
直接跳到11行,这样就可以直接执行完循环
- p 变量:打印变量值。
(gdb) p sum$2 = 5050
- set var 变量:修改变量的值(不用修改代码,测试其他分支)
比如我们在测试if语句分支时
if(flag==1)……
else ……
如果代码中以及规定flag值为1,但是又不想重新打开代码进行修改,这时就可以使用set var
比如:
set var flag=0
就可以直接修改flag的值来测试另一条分支
99979c712fd11d94018724310fb0f2e6ad89546e