gdb调试指南

gdb入门指令

gcc -g hello.c //加入调试信息
gdb ./a.out

l           // list,显示函数
start		// 开始逮捕调试,显示即将运行的行
n			// next,运行到下一行,到函数时不会进入函数
s			// step,运行到下一行,到函数时进入函数
p a         // 显示函数内a的值
bt          // 查看函数堆栈,当前栈序号为0,main栈序号为1
f 1         // 切换到main的栈
p a			// 显示main中a的值
p &a  		// 打印a的地址
q			// 退出调试

gdb调试运行中的程序

gdb中忽略信号处理 SIGPIPE

GDB调试网络程序时,会遇到SIGPIPE信息,默认GDB会把程序停下来,用handle命令设置一下缺省的signal的处理行为即可:(在gdb模式下运行下面的命令)

handle SIGPIPE nostop print

如果连信息提示都不想看见,可以这样设置:

handle SIGPIPE nostop noprint

命令小记:

GDB进入正在运行的进程
1,基本操作
    gdb -p pid //  在线调试已经存在的进程
    gdb attach // 同上
    b fun // 设置断点函数 
    c // 继续执行程序,直到下个断点

2.断点管理
//设置断点
break n,break 函数名(b n, b 函数名)
//查看断点
info breakpoints(i breakpoints)
//删除断点,其中n为断点的序列号,可以用info breakpoints查看
delete breakpoints n
//使断点失效
disable breakpoints n
//使断点生效
enable breakpoints n

GDB提示符
1. 变量信息管理
    info 变量名(i 变量名)//查看一个变量的值
    info locals //查看所有局部变量的值
    info args

2. 查看、设置变量
    p 变量
    p 变量 = 新值
    set 变量 = 新值
    
3. 查看内存
    x/<n/f/u> <addr>
    x/nbx 变量名 //查看从变量名开始的n个字节,例x/7bx input 表示查看从变量input开始的7个内存单元的内容

4. 线程调试
    info thread
    thread n

gdb调试Core Dump

测试代码:

#include <stdio.h>  
  
int main()  
{  
        int *p = NULL;  
        *p = 0;  
  
        printf("bad\n");  
        return 0;  
}  

编译运行,会发生Segmentation fault (core dumped) 错误,使用gdb调试:

[taoge@localhost test]$ gcc -g main.c   
[taoge@localhost test]$ ./a.out   
Segmentation fault (core dumped)  
[taoge@localhost test]$ gdb a.out  
(gdb) r  
Starting program: /home/taoge/test/a.out   

Program received signal SIGSEGV, Segmentation fault.  
0x080483c9 in main () at main.c:6  
6               *p = 0;  

可以看到, 在gdb调试的时候, 用r命令让程序再跑起来, 可以定位到问题出在第6行。 我们再来看看bt命令:

(gdb) bt  
#0  0x080483c9 in main () at main.c:6  
(gdb)    

可以看到,通过bt查看函数堆栈, 也能定位到第6行。

我们知道,在实际中, 有很多问题是概率发生的, 很难重现。 此时, 如果用gdb的r命令(实际相当于重新运行程序)则是不可能的。 所以,对于概率性问题, 如果程序出现堆栈错误时, 产生了core文件, 我们一定要视之为宝贝, 记得保存, 否则很可能被冲掉。 拿到core文件后, 我们可以用gdb调试core。

1,什么是Core Dump?

Core的意思是内存, Dump的意思是扔出来, 堆出来.
开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考.
core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump.

2,怎么生成Core Dump?

在linux平台下,设置core dump文件生成的方法:

  1. 在终端中输入ulimit -c 如果结果为0,说明当程序崩溃时,系统并不能生成core dump。

  2. 使用ulimit -c unlimited命令,开启core dump功能,并且不限制生成core dump文件的大小。如果需要限制,加数字限制即可:ulimit - c 1024,如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文件的时候,gdb会提示错误。

永久设置, 修改/etc/security/limits.conf文件:

soft    core            0
修改成:
soft    core            unlimited
  1. 默认情况下,core dump生成的文件名为core,而且就在程序当前目录下。新的core会覆盖已存在的core。通过修改/proc/sys/kernel/core_uses_pid文件,可以将进程的pid作为作为扩展名,生成的core文件格式为core.xxx,其中xxx即为pid。为0则表示生成的core文件统一命名为core。可通过以下命令修改此文件:
echo "1" > /proc/sys/kernel/core_uses_pid

注意 proc 是内存文件,使用vi 是不能 编译的,所有只能使用append 的方式

/proc 这个目录是虚拟在内存中的,不在硬盘保存,
proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。

  1. 通过修改/proc/sys/kernel/core_pattern可以控制core文件保存位置和文件格式。例如:
# 将所有core文件生成到/corefile下,格式为core-命令名-pid-时间戳.

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

# 以下是参数列表:

%%	单个%字符
%p	dump进程的进程ID
%u	dump进程的用户ID
%g	dump进程的组ID
%s	导致core dump的信号
%t	core dump的时间
%h	主机名
%e	程序文件名

永久设置, 修改/etc/sysctl.conf配置文件,添加:

kernel.core_pattern = /corefile/core-%e-%p-%t
kernel.core_uses_pid = 1 #即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID

/* 执行以下命令立即生效 */
# sysctl -p

3,如何使用core文件?

gdb [exec file] [core file]

在编译程序的时候加入选项-g,下面我们可以在发生运行时信号引起的错误时发生core dump了。发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行。比如:

gdb /usr/sbin/ovs-vswitchd vat/log/idump/core-3219-1512819153 
bt //查看其调用函数的信息
frame n (f n)//n为栈的层次,然后可以用其他命令(info)查看此级别的变量信息

补充:

// 查看core生成详细时间
date --date='@1512819153'

在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件->行.
进去后输入where回车, 也可以显示程序在哪一行down掉的, 在哪个函数中.

如果不知道coredump对应的执行文件,可以使用以下方式查找:

gdb -c corefile  # 使用gdb调试core文件
info auxv        # 索引31对应的是core文件的应用程序exec_file
find / -name exec_file

core dump原因分析

造成程序core dump的原因很多,这里根据以往的经验总结一下:

1 内存访问越界

a) 由于使用错误的下标,导致数组访问越界
b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。

2 多线程程序使用了线程不安全的函数。

应该使用下面这些可重入的函数,尤其注意红色标示出来的函数,它们很容易被用错:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c) getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)

3 多线程读写的数据未加锁保护。

对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump

4 非法指针

a) 使用空指针
b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump.

5 堆栈溢出

不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gdb是一款功能强大的调试器,可以用于调试C和C++程序,也可以用于调试Python程序。当我们使用python虚拟环境中的python解释器来执行Python程序时,gdb也可以正常调试,没有什么使用上的差异。 使用gdb调试Python的过程可以分为以下几个步骤: 1. 首先,确保你已经安装了gdb和Python解释器。 2. 在命令行中进入到你的Python程序所在的目录,并使用gdb启动Python解释器。例如,可以使用以下命令启动gdb调试器: ``` gdb python ``` 3. 接下来,设置一些gdb调试选项,例如设置断点、监控变量等。你可以使用gdb命令来完成这些设置。更多关于gdb的命令和选项可以在gdb的文档中找到。 4. 当你设置好调试选项后,可以运行你的Python程序。你可以使用gdb的`run`命令来运行程序,并在需要时暂停程序的执行。 5. 当程序暂停时,你可以使用gdb的命令来查看变量的值、执行相关的操作,并逐步执行程序。你可以使用gdb的`next`命令来执行下一行代码,`step`命令来进入函数调用,`continue`命令来继续程序的执行等等。 6. 在调试过程中,你还可以使用gdb的其他功能,例如查看堆栈信息、查找内存错误等等。 总之,使用gdb调试Python程序可以帮助我们定位和解决程序中的问题,提高程序的可靠性和稳定性。具体的使用方法可以参考相关文档和教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用gdb调试Python程序](https://blog.csdn.net/weixin_30230009/article/details/125383399)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值