Linux调试器-gdb

<<<<<<< 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版本基本调试功能:

  1. 运行起来才能调试
  2. 调试时可以看到代码
  3. 打断点
  4. 局部调试
  5. 看到局部变量的内容和地址
  6. 看到调用栈
  7. 单步
  8. 进入函数

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 20
Breakpoint 1 at 0x4005e5: file test.c, line 20.

b 文件名:行号

(gdb) b test.c:30
Breakpoint 2 at 0x400649: file test.c, line 30.

b 函数名

(gdb) b Sum
Breakpoint 3 at 0x400584: file test.c, line 5.

  • 查看断点:info b

(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

  • 关闭断点:disable 断点编号

(gdb) disable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep n 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

此时编号为1的断点已被关闭,keep后边属性显示n(no)

  • 开启断点:enable 断点编号

(gdb) enable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

  • r开始调试:直接跳到断点位置

(gdb) r
Starting program: /home/test/git仓库/note-warehouse/gdbtest/mytest
hello world!
hello world!
hello world!
hello world!
hello world!

Breakpoint 1, main () at test.c:20
20 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 i
1: i = 1

(gdb) display sum
2: sum = 4195472

(gdb) s
7 for(; i <= n; i++)
2: sum = 0
1: i = 1
(gdb)
9 sum +=i;
2: sum = 0
1: i = 1
(gdb)
7 for(; i <= n; i++)
2: sum = 1
1: i = 1

每次逐语句执行时都输出了sum和i的值

  • undisplay 编号:取消常显示变量的内容和地址

(gdb) undisplay 2
(gdb) s
9 sum +=i;
1: i = 2
(gdb)
7 for(; i <= n; i++)
1: i = 2
(gdb)

c 直接跳到下一个断点

(gdb) r
Starting program: /home/test/git仓库/note-warehouse/gdbtest/mytest
hello world!
hello world!
hello world!
hello world!
hello world!

Breakpoint 1, main () at test.c:20
20 printf("hello world!\n");
(gdb) c
Continuing.
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:31
31 int ret = Sum(100);

重新开始调试,r直接执行到第一个断点位置,c执行到下个断点

d 断点编号:删除断点

(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
breakpoint already hit 1 time
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
breakpoint already hit 1 time
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
(gdb) d 1
(gdb) info b
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
breakpoint already hit 1 time
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
(gdb)

  • finish:执行完当前函数并返回,然后停下来

(gdb) s

Breakpoint 3, Sum (n=100) at test.c:5
5 int i = 1;
1: i = 0
(gdb)
6 int sum = 0;
1: i = 1
(gdb)
7 for(; i <= n; i++)
1: i = 1
(gdb) finish
Run till exit from #0 Sum (n=100) at test.c:7
0x0000000000400653 in main () at test.c:31
31 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:5
5 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 11
Sum (n=100) at test.c:11
11 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版本基本调试功能:

  1. 运行起来才能调试
  2. 调试时可以看到代码
  3. 打断点
  4. 局部调试
  5. 看到局部变量的内容和地址
  6. 看到调用栈
  7. 单步
  8. 进入函数

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 20
Breakpoint 1 at 0x4005e5: file test.c, line 20.

b 文件名:行号

(gdb) b test.c:30
Breakpoint 2 at 0x400649: file test.c, line 30.

b 函数名

(gdb) b Sum
Breakpoint 3 at 0x400584: file test.c, line 5.

  • 查看断点:info b

(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

  • 关闭断点:disable 断点编号

(gdb) disable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep n 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

此时编号为1的断点已被关闭,keep后边属性显示n(no)

  • 开启断点:enable 断点编号

(gdb) enable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5

  • r开始调试:直接跳到断点位置

(gdb) r
Starting program: /home/test/git仓库/note-warehouse/gdbtest/mytest
hello world!
hello world!
hello world!
hello world!
hello world!

Breakpoint 1, main () at test.c:20
20 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 i
1: i = 1

(gdb) display sum
2: sum = 4195472

(gdb) s
7 for(; i <= n; i++)
2: sum = 0
1: i = 1
(gdb)
9 sum +=i;
2: sum = 0
1: i = 1
(gdb)
7 for(; i <= n; i++)
2: sum = 1
1: i = 1

每次逐语句执行时都输出了sum和i的值

  • undisplay 编号:取消常显示变量的内容和地址

(gdb) undisplay 2
(gdb) s
9 sum +=i;
1: i = 2
(gdb)
7 for(; i <= n; i++)
1: i = 2
(gdb)

c 直接跳到下一个断点

(gdb) r
Starting program: /home/test/git仓库/note-warehouse/gdbtest/mytest
hello world!
hello world!
hello world!
hello world!
hello world!

Breakpoint 1, main () at test.c:20
20 printf("hello world!\n");
(gdb) c
Continuing.
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:31
31 int ret = Sum(100);

重新开始调试,r直接执行到第一个断点位置,c执行到下个断点

d 断点编号:删除断点

(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e5 in main at test.c:20
breakpoint already hit 1 time
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
breakpoint already hit 1 time
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
(gdb) d 1
(gdb) info b
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000400649 in main at test.c:30
breakpoint already hit 1 time
3 breakpoint keep y 0x0000000000400584 in Sum at test.c:5
(gdb)

  • finish:执行完当前函数并返回,然后停下来

(gdb) s

Breakpoint 3, Sum (n=100) at test.c:5
5 int i = 1;
1: i = 0
(gdb)
6 int sum = 0;
1: i = 1
(gdb)
7 for(; i <= n; i++)
1: i = 1
(gdb) finish
Run till exit from #0 Sum (n=100) at test.c:7
0x0000000000400653 in main () at test.c:31
31 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:5
5 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 11
Sum (n=100) at test.c:11
11 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

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇