gdb调试

默认情况下,gcc在编译时不会将调试符号加到生成的二进制代码中,因为这样会增加可执行文件的大小。如果需要在编译时生成调试信息,需要使用gcc的-g或者-ggdb选项

gcc的调试信息同样采用分级(跟优化一样)的思想,分为g1、g2、g3,默认是g2

g1:只能够用于回溯跟踪和堆栈转储

g2:除了g1,还有拓展的符号表、行表、局部或外部变量信息

g3:除了g2, 还有源代码中定义的宏

生成调试信息

gcc efficient.c -g -o efficient

可以对比带不带调试信息的文件大小

用 ls -l efficient命令查看

gdb的功能

1.设置断点(断点可以是条件表达式)。

2.单步执行

3.查看程序中变量值的变化

4.动态改变程序的执行环境

5.分析崩溃程序产生的core文件

开始调试

gdb filename (这个可执行文件必须是带了gdb文件的)

输入quit 退出gdb

gdb常用命令

1.file 装入要调试的可执行文件

2.run 执行被调试的程序

  1. kill 终止正在调试的程序

  2. step 单步进入

  3. next 下一步

6.break 设置断点

  1. print 打印表达式或变量的值,或打印内存中某个变量开始的一段连续区域的值。还可以用来赋值。

8.dispaly 设置自动显示的表达式或变量,当程序停住或者单步跟踪的时候,这些变量会显示。

  1. list 列出可执行文件源代码的一部分

  2. quit 退出

  3. watch 监控一个变量,不管它何时改变。

  4. backtrace 回溯跟踪

  5. frame n 定位到发现错误的代码段,n为backtrace命令的输出结果的行号

  6. examine 查看内存地址中的值

  7. jump 使程序跳转执行

  8. signal 产生信号量

  9. return 强制函数返回

  10. call 强制调用函数

  11. make 使用户不退出gdb就可以重新产生可执行文件

  12. shell 使用户不离开gdb就可以执行linux的shell命令。

break命令的用法

break 在进入指定函数时停住.c++中可以使用class::function或function(type, type)格式来指定函数名

break在指定行号停住

break + offset 在当前行号前面的offset行停住

break - offset 在当前行号后面的offset行停住

break filename::linenum 在源文件filename的第多少行停住

break filename::function 在源文件的function函数的入口处停住

break *address 在该内存地址处停住

break 表示在下一条指令处停住

break if 条件停住

查看运行数据的命令

主要是print和display命令

print命令的格式是

print

print /

是表达式,是输出的格式,比如16进制的格式输出 /X

display

它可以设置自动显示的变量,当程序停住,或者单步跟踪时,这些变量会自动显示

display

display /

display /

fmt同样表示格式

undisplay <dnums…> 或 delete display <dnums…>

擅除自动显示,dnums为已设置好的自动显示的编号。如果要同时删除几个编号,可以用空格分割;如果要删除一个范围内的变量,可以用2-5这样表示。

disable display <dnums…> enable display <dnums…>

不删除自动显示的设置,而只是让其失效或恢复

info display

查看所有自动显示的信息。

gdb查看源程序

查看源代码

用list命令

list 行号 显示第几行周围的源代码

list 函数名 显示该函数的源代码

list 显示当前行后面的源代码

list - 显示当前行前面的源程序。默认显示10行,一般为上5和后5行

set listsize 设置一次显示原代码的行数

show listsize 显示一次显示的行数

list , 显示first行到last行之间的源代码

list , 显示当前行到last行之间的源代码

list + 向后显示源代码

查看源代码的内存

info line + …来查看源代码在内存中的地址,跟list一样,它可以加行号,函数名,文件名

disassemble 查看源程序的当前执行时的机器码。这个命令会把目前内存中的指令dump出来。

gdb改变程序的运行

1.改变变量的值

print x = 8 这样可以把变量的值改变(不仅仅可以打印)

2.跳转执行(乱序执行的功能)

jump

可以是文件的行号,可以是file::line格式,可以是+num这种偏移格式,表示下一条语句从哪里开始。

jump

跳转到相应的内存地址

3.产生信号量

使用signal命令可以产生一个信号量给被调试的程序。如中断信号Ctrl + C

signal

4.强制函数返回

如果断点在某个函数中,还有语句没有执行完,可以用return语句。

return

return

指定了 那么该表达式的值会被当做函数的返回值

5.强制调用函数

call 表达式可以是一个函数

print 加函数跟call是一样的,区别是如果返回值是void,call不显示,print会显示返回值,并把该值存到历史数据中

gdb调试代码1

#include<stdio.h>

int main()
{
	int input = 0;
	printf("Input an integar:"):
	scanf("%d", input);
	return 0;
}

1.产生带gdb的可执行文件

gcc -ggdb3 simple_gdb.c -o simple_gdb

2.开始调试

gdb simple_gdb

3.先run一下

提示发生了segment fault

4.backtrace(回溯一下)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rhERKt9-1624455331452)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a2432e92-95fe-46c5-a03c-362396d343e3/__20210623110033.png)]

看到错误已经定位到第7行了。

5.进入这一行

frame 2(注意不是第7行,而是前面那个行号)

gdb调试代码2

#include<stdio.h>
int calculate(intx, int y);
int main()
{
	int num1 = 0, num2 = 0, result = 0;
	while(1)
	{
		print("Enter two integers, or use 0 0 to exit:";
		scanf("%d %d", &num1, &num2);
		if(num1 == 0 && num2 == 0)
			exit(0);
		result = calculate(num1, num2);
		print("This result is: %d\n", result);
	}
	return 0;
}

int calculate(int x, int y)
{
	int res = 0;
	res = x * x + y * y;
	return res;
}

1.产生带gdb的可执行文件

gcc -ggdb3 calculate.c -o calculate

2.开始调试

gdb calculate

3.在main设一个断点

break main

4.运行

run

5.单步进入(一直单步进入,可以简写成s)

step

6下一步(配合单步进入用,可以简写成n,进入函数以后就下一步)

next

7.查看变量值

print num1

print num2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NiLA8RPN-1624455331458)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7d673ee9-3558-45a4-9427-2c63910edd88/__20210623165937.png)]

print $1也是可以的

display num1

8查看源代码

set listsize 15

show main

show 5

9显示内存信息

info line calculate

10查看机器码

disassemble calculate

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值