【无标题】

前言

GDB是Linux下非常好用且强大的调试工具。GDB可以调试C、C++、Go、java、 objective-c、PHP等语言。对于一名Linux下工作的c/c++程序员,GDB是必不可少的工具,本篇以C语言来调试。

GDB简介

UNIX及UNIX-like下的调试工具。虽然它是命令行模式的调试工具,但是它的功能强大到你无法想象,能够让用户在程序运行时观察程序的内部结构和内存的使用情况。

一般来说,GDB主要帮助你完成下面四个方面的功能:

1、按照自定义的方式启动运行需要调试的程序。
2、可以使用指定位置和条件表达式的方式来设置断点。
3、程序暂停时的值的监视。
4、动态改变程序的执行环境。

基本命令的操作

GDB中的命令很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调试工作。

file <文件名>加载被调试的可执行程序文件
run重新开始运行文件
start单步执行,运行程序,停在第一执行语句
list查看原代码,简写l
set设置变量的值
next单步调试(逐过程,函数直接执行),简写n
step单步调试(逐语句:跳入自定义函数内部执行),简写s
backtrace查看函数的调用的栈帧和层级关系,简写bt
frame切换函数的栈帧,简写f
info查看函数内部局部变量的数值,简写i
finish结束当前函数,返回到函数调用点
continue继续运行,简写c
print打印值及地址,简写p
quit退出gdb,简写q

gdb命令拥有较多内部命令。在gdb命令提示符“(gdb)”下输入“help”可以查看所有内部命令及使用说明。

在这里插入图片描述
判断文件是否带有调试信息

要调试C/C++的程序,首先在编译时,要使用gdb调试程序,在使用gcc编译源代码时必须加上“-g”参数。保留调试信息,否则不能使用GDB进行调试。

有一种情况,有一个编译好的二进制文件,你不确定是不是带有-g参数,带有GDB调试,这个时候你可以使用如下的命令验证:

在这里插入图片描述
如果没有调试信息,则会出现:

Reading symbols from /home/minger/share/tencent/gdb/main…(no debugging symbols found)…done.

/home/minger/share/tencent/gdb/main是程序的路径。

如果带有调试功能,下面会提示:

在这里插入图片描述

Reading symbols from /home/minger/share/tencent/gdb/main…done.

说明可以进行GDB调试。

还有使用命令readlef查看可执行文件是否带有调试功能

readelf -S main|grep debug

在这里插入图片描述
如果有debug说明有调试功能,如果没有debug。说明没有带有调试功能,则不能被调试。

开始进入正题,GDB启动调试。

调试方式启动运行无参程序

以下是linux下GDB调试的一个实例,先给出一个示例用的小程序,C语言代码:

main.c

#include <stdio.h>

void Print(int i){

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello,程序猿编码 %d\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

int main(int argc, char const *argv[]){

<span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">3</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
	<span class="token function">Print</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

编译:

gcc -g main.c -o main

 
 
  • 1

下面“gdb”命令启动GDB,将首先显示GDB说明,不管它:
在这里插入图片描述上面最后一行“(gdb)”为GDB内部命令引导符,等待用户输入GDB命令。

下面使用“file”命令载入被调试程序 main(这里的 main 即前面gcc 编译输出的可执行文件):

如果最后一行提示Reading symbols from /home/minger/share/tencent/gdb/main…done. 表示已经加载成功。

下面使用“r”命令执行(Run)被调试文件,因为尚未设置任何断点,将直接执行到程序结束:

在这里插入图片描述
调试启动带参程序

假设有以下程序,启动时需要带参数:

#include <stdio.h>

int main(int argc, char const *argv[]){

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">&gt;=</span> argc<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
	<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"usage:hello name\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello,程序猿编码 %s\n"</span><span class="token punctuation">,</span> argv<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

编译:

gcc -g test.c -o test

 
 
  • 1

这种情况如何启动调试呢?只需要r的时候带上参数即可。
在这里插入图片描述
调试core文件

Core Dump:Core的意思是内存,Dump的意思是扔出来,堆出来(段错误)。开发和使用Unix程序时,有时程序莫名其妙的down了,却没有任何的提示(有时候会提示core dumped),这时候可以查看一下有没有形如core.进程号的文件生成,这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考,能够很大程序帮助我们定位问题。那怎么生成Core文件呢?

生成Core方法

产生coredump的条件,首先需要确认当前会话的ulimit –c,若为0,则不会产生对应的coredump,需要进行修改和设置。

在这里插入图片描述
即便程序core dump了也不会有core文件留下。我们需要让core文件能够产生,设置core大小为无限:

ulimit -c unlimied

 
 
  • 1

在这里插入图片描述
更改core dump生成路径

因为core dump默认会生成在程序的工作目录,但是有些程序存在切换目录的情况,导致core dump生成的路径没有规律,

所以最好是自己建立一个文件夹,存放生成的core文件。

我建立一个 /data/coredump 文件夹,在根目录data里的coredump文件夹。
在这里插入图片描述
调用如下命令:

echo /data/coredump/core.%e.%p> /proc/sys/kernel/core_pattern

 
 
  • 1

将更改core文件生成路径,自动放在这个/data/coredump文件夹里。

%e表示程序名, %p表示进程id

在这里插入图片描述
测试代码:


/*
#include <stdio.h>

int main(int argc, char const *argv[]){

if (1 &gt;= argc){
	printf("usage:hello name\n");
	return 0;
}

printf("hello,程序猿编码 %s\n", argv[1]);

return 0;

}

*/

#include <stdio.h>

int main(int argc, char const *argv[])
{
int i = 0;

<span class="token function">scanf</span><span class="token punctuation">(</span><span class="token string">"%d"</span><span class="token punctuation">,</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello,程序猿编码 %d\n"</span><span class="token punctuation">,</span>i <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

编译运行:

在这里插入图片描述
运行后结果显示段错误,该程序在主函数内部scanf的时候回崩溃,i前面应该加上&。

这个时候,进入/data/coredump文件夹可以查看生成的core

在这里插入图片描述

然后用gdb调试该core,命令为 gdb core.test.3591 ,显示如下

在这里插入图片描述
program terminated with signal 11 告诉我们信号中断了我们的程序,发生了段错误。

这个时候可以敲命令 backtrace(bt) 查看函数的调用的栈帧和层级关系。

这个一堆问号很多人遇到过,网上有些人说是没加载符号表,有人说是标准glibc版本不一致,不纠结这个问题。

可以通过如下命令调试:

gdb 可执行程序exe
进入gdb环境后
core-file core的名字
敲命令bt可以查看准确信息。

gdb 可执行程序
在这里插入图片描述
进入gdb环境后,core-file core的名字

在这里插入图片描述
敲bt命令,这是gdb查看back trace的命令,查看函数的调用的栈帧和层级关系。
在这里插入图片描述
可以看到最近的栈中存储的是调用了IO操作,可以看到main函数的26行出错。

到此为止,就是core文件配置生成和调试方法。

总结

至此,我们GDB启动调试方式完毕,和core文件配置生成和调试方法。后续接着讲断点设置、单步调试等。本人能力有限,欢迎留言补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值