gdb调试命令的使用及总结_大锅安装调试指南

gdb调试命令的使用及总结_大锅安装调试指南写这篇文档的目的是对前面GDB的知识做一次总览,本文为GDB调试指南,参考GDB调试手册,目前已有的篇目:启动调试断点设置查看源码单步调试查看变量前言GDB是Linux下非常好用且强大的调试工具。GDB可以调试C、C++、Go、java、objective-c、PHP等语言。对于一名Linux下工作的c/c++程序员,GDB是必不可少的工具,本篇以C语言来调试。GDB简介U…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

写这篇文档的目的是对前面GDB的知识做一次总览,本文为GDB调试指南,参考GDB调试手册,目前已有的篇目:

启动调试
断点设置
查看源码
单步调试
查看变量

前言

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

在这里插入图片描述
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){ 
   

	printf("hello,程序猿编码 %d\n", i);
}

int main(int argc, char const *argv[]){ 
   
	
	int i = 0;
	for (i = 1; i < 3; i++){ 
   
		Print(i);
	}
	return 0;
}

Jetbrains全家桶1年46,售后保障稳定

编译:

gcc -g main.c -o main

下面“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[]){ 
   

	if (1 >= argc){ 
   
		printf("usage:hello name\n");
		return 0;
	}
	
	printf("hello,程序猿编码 %s\n", argv[1]);

	return 0;
}

编译:

gcc -g test.c -o test

这种情况如何启动调试呢?只需要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

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

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

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

我建立一个 /data/coredump 文件夹,在根目录data里的coredump文件夹。

在这里插入图片描述
调用如下命令:

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

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

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

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


/* #include <stdio.h> int main(int argc, char const *argv[]){ if (1 >= 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;
	
	scanf("%d",i);
	printf("hello,程序猿编码 %d\n",i );
	return 0;
}


编译运行:

在这里插入图片描述
运行后结果显示段错误,该程序在主函数内部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文件配置生成和调试方法。后续接着讲断点设置、单步调试等。本人能力有限,欢迎留言补充。

断点设置与查看源码

前言

上篇GDB启动调试我们讲到了GDB启动调试的多种方式,在 Linux 环境软件开发中,GDB 是主要的调试工具,用来调试 C 和 C++ 程序。这一篇主要讲GDB的断点设置与查看源码。

为什么要设置断点呢?

当我们想查看变量内容,堆栈情况等等,可以指定断点。程序执行到断点处会暂停执行。break 命令用来设置断点,缩写形式为b。设置断点后,以便我们更详细的跟踪断点附近程序的执行情况。

设置断点有很多方式。下面我们举例说明下常用的几种方式。

通过行号设置断点

格式:

break [行号]

break 行号,断点设置在该行开始处,注意:该行代码未被执行

如果你的程序是用c或者c++写的,那么你可以使用“文件名:行号”的形式设置断点。示例如下:

//test.c
#include <stdio.h>
 
void judge_sd(int num){ 
   

	if ((num & 1) == 0){ 
   
		printf("%d is even\n",num);
		return;
	}else{ 
   
		printf("%d is odd\n",num);
		return;
	}
}
 
int main(int argc, char const *argv[]){ 
   
	

	judge_sd(0);
	judge_sd(1);
	judge_sd(4);

	return 0;
}


编译:

gcc -g test.c -o test

在这里插入图片描述
gdb test

在这里插入图片描述

break 文件名 : 行号,适用于有多个源文件的情况。

示例中的(gdb) b test.c:18是设置了断点。断点的位置是test.c文件的18行。使用r命令执行脚本时,当运行到18行时就会暂停。注意:该行代码未被执行

通过函数设置断点

格式:

break [函数名]

break 函数名,断点设置在该函数的开始处,断点所在行未被执行:

同样可以将断点设置在函数处:

b judge_sd

在这里插入图片描述
设置条件断点

如果按上面的方法设置断点后,每次执行到断点位置都会暂停。有时候非常讨厌。我们只想在指定条件下才暂停。这时候根据条件设置断点就有了用武之地。设置条件断点的形式,就是在设置断点的基本形式后面增加 if条件。示例如下:

break test.c:6 if num>0

在这里插入图片描述
当在num>0时,程序将会在第6行断住。

查看断点

语法:

info breakpoints

可以使用info breakpoints查看断点的情况。包含都设置了那些断点,断点被命中的次数等信息。示例如下:

在这里插入图片描述
它将会列出所有已设置的断点,每一个断点都有一个标号,用来代表这个断点。

删除断点

语法:

delete breakpoint

对于无用的断点我们可以删除。删除的命令格式为 delete breakpoint 断点编号。info breakpoint命令显示结果中的num列就是编号。删除断点的示例如下:

在这里插入图片描述
查看源码

断点设置完后,当程序运行到断点处就会暂停。暂停的时候,我们可以查看断点附近的代码。查看代码的子命令是list,缩写形式为l。

在这里插入图片描述
指定行号查看代码

语法:

list first,last

例如,要列出6到21行之间的源码:
在这里插入图片描述
列出指定文件的源码

前面执行l命令时,默认列出test.c的源码,如果想要看指定文件的源码呢?可以

list 【文件名加行号或函数名】

在这里插入图片描述
总结

本文介绍了GDB调试中的断点设置、源码查看。断点设置可以便于我们后期观察变量,堆栈等信息,为进一步的定位与调试做准备。源码查看可以通过指定行号或者方法名来查看相关代码。

单步调试与查看变量

前言

前面两篇已经对GDB启动调试,GDB调试断点设置与查看源码我们已经了解了GDB基本的启动调试,设置断点,查看源码等,如果这些内容你还不知道,建议先回顾一下前面的内容。

断点附近的代码你了解后,这时候你就可以使用单步执行一条一条语句的去执行。可以随时查看执行后的结果。接下来你可能会想知道程序运行的一些情况,就需要查看变量的值。下面介绍单步调试与设置变量。

单步调试

居然是调试代码,还是老规矩,先上代码:

//test.c
#include <stdio.h>
 
void judge_sd(int num){ 
   

	if ((num & 1) == 0){ 
   
		printf("%d is even\n",num);
		return;
	}else{ 
   
		printf("%d is odd\n",num);
		return;
	}
}
 
int main(int argc, char const *argv[]){ 
   
	

	judge_sd(0);
	judge_sd(1);
	judge_sd(4);

	return 0;
}


编译:

gcc -g test.c -o test

程序的功能比较简单,这里不多做解释。断点附近的代码你了解后,这时候你就可以使用单步执行一条一条语句的去执行。可以随时查看执行后的结果。单步执行有两个命令,分别是step和next。我们可能打了多处断点,或者断点打在循环内,这个时候,可以使用continue命令。这三个命令的区别在于:

1、next命令(可简写为n)用于在程序断住后,继续执行下一条语句。
2、step命令(可简写为s),它可以单步跟踪到函数内部。
3continue命令(可简写为c)或者fg,它会继续执行程序,直到再次遇到断点处。

单步进入-step

step 一条语句一条语句的执行。它有一个别名,s。它可以单步跟踪到函数内部。

先用list(可简写为l)将源码列出来,例如:

在这里插入图片描述

先启动调试,然后把源码列出来。

在这里插入图片描述
从上面的过程可以看到,在5行设置断点,运行程序,可见,step命令进入到了被调用函数中judge_sd。使用step命令也会在这个方法中一行一行的单步执行。但是如果没有该函数源码,需要跳过该函数执行,可使用finish命令,继续后面的执行。

单步执行-next

next命令示例:

在这里插入图片描述
next命令(可简写为n)用于在程序断住后,继续执行下一条语句。上面的信息在5行处打断点,然后运行到6行,然后输入 运行n 2,则会单步执行两行。可见,使用next命令只会在本方法中单步执行。

继续执行到下一个断点-continue

我们可能打了多处断点,或者断点打在循环内,这个时候,想跳过这个断点,甚至跳过多次断点继续执行该怎么做呢?可以使用continue命令。它的作用就是从暂停处继续执行。命令的简写形式为c。继续执行过程中遇到断点或者观察点变化依然会暂停。示例代码如下:

在这里插入图片描述

跳过执行–skip

在这里插入图片描述
根据上面的信息可以看到,使用skip之后,将不会进入judge_sd函数。好处就是skip可以在step时跳过一些不想关注的函数或者某个文件。

如果想删除skip,使用skip delete [num] 。

查看变量

现在你已经会设置断点,查看断点附近的代码,并可以单步执行和继续执行。接下来你可能会想知道程序运行的一些情况,如查看变量的值。print命令正好满足了你的需求。以帮助我们进一步定位问题。

格式:

print[变量名]

print(可简写为p)打印变量内容。示例代码如下:

//test.c
#include <stdio.h>
#include <stdlib.h> //malloc,free,rand

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

	printf("Please enter the length of the string:");

    scanf("%d",&input);

    char *buf = (char *) malloc(input + 1);//字符最后包含'\0'
    if (buf == NULL)
    { 
   
    	printf("malloc failed!\n");
    	return -1;
    }

	//随机生成字符串

	for ( i = 0; i < input; i++)
	{ 
   
		buf[i] = rand()%26 +'a';
	}

	buf[i] = '\0';

	printf("A randomly generated string: %s\n",buf);
	free(buf);

	return 0;
}

编译:

gcc -g test.c -o test

先用list(可简写为l)将源码列出来,例如:

在这里插入图片描述
print命令的简写形式为p,使用它打印出变量的值。

在这里插入图片描述

打印出的变量i的值为80。

当然,多个函数或者多个文件会有同一个变量名,这个时候可以在前面加上文件名或者函数名来区分:

p 'testfile.c'::i
p 'sum'::i

在看看指针。

在这里插入图片描述
注意到了没有,如果使用上面的方式打印指针指向的内容,那么打印出来的只是指针地址而已。那怎么打印出指针指向的内容呢?

需要解引用,如下:

在这里插入图片描述
仅仅使用*只能打印第一个值,如果要打印多个值,后面跟上@并加上要打印的长度。
或者@后面跟上变量值:如下:

在这里插入图片描述
另外值得一提的是,$可表示上一个变量,在调试链表时时经常会用到的,它有next成员代表下一个节点,则可使用下面方式不断打印链表内容,举例:

p *linkNode  #这里显示linkNode节点内容
p *$.next #这里显示linkNode节点下一个节点的内容

设置变量

使用print命令查看了变量的值,如果感觉这个值不符合预期,想修改下这个值,再看下执行效果。这种情况下,我们该怎么办呢?通常情况下,我们会修改代码,再重新执行代码。使用gdb的set命令,一切将变得更简单。

set命令可以直接修改变量的值。

设置观察点

设置观察点的作用就是:当被观察的变量发生变化后,程序就会暂停执行,并把变量的原值(Old)和新值(New)都会显示出来。设置观察点的命令是watch。

watch num

这个时候,让程序继续运行,如果num的值发生变化,则会打印相关内容,如:

Hardware watchpoint 3: num
Old value = 1
New value = 10

总结

通过上面的例子演示,我相信读者已经对于通过GDB调试C/C++程序有了基本的理解,如果你想获取更多的调试技巧请参考官方网站的GDB调试手册,还有GDB官方网站的手册。

参考:GDB TutorialA Walkthrough with Examples

在这里插入图片描述
欢迎关注公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料,网盘资料有如下:

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/206659.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • ImageMagick 的安装及使用

    ImageMagick 的安装及使用一、什么是Imagemagick?ImageMagick是一款免费开源的图片编辑软件。既可以通过命令行使用,也可以通过C/C++、Perl、Java、PHP、Python或Ruby调用库编程来完成。

  • linux系统下怎么安装.deb文件?

    linux系统下怎么安装.deb文件?

  • 业务架构师如何进阶成长[通俗易懂]

    业务架构师如何进阶成长[通俗易懂]一、前言接触业务架构工作之后,除了单位提供的方法论外,为了做好这项工作,认真学习了软件过程、系统分析与设计、架构设计、设计模式、Java语言等内容,并研读了敏捷开发、领域驱动设计、工作流分析等方面的书籍,为了拓展对新技术的理解,在人工智能和区块链两方面也阅读了一些著作,总体而言,不够系统,都是为了能够更好地理解企业级业务架构的方法论及其向技术端的传导。除了恶补基础知识,更重要的当然是实践,珍惜每一个设计任务,珍惜每一次与业务人员、技术人员的沟通机会…

    2022年10月12日
  • php 容器_php依赖注入容器库

    php 容器_php依赖注入容器库原标题:PHP容器——Pimple运行流程浅析需要具备的知识点闭包闭包和匿名函数在PHP5.3.0中引入的。闭包是指:创建时封装周围状态的函数。即使闭包所处的环境不存在了,闭包中封装的状态依然存在。理论上,闭包和匿名函数是不同的概念。但是PHP将其视作相同概念。实际上,闭包和匿名函数是伪装成函数的对象。他们是Closure类的实例。闭包和字符串、整数一样,是一等值类型。创建闭包:$closure…

    2022年10月24日
  • 屏蔽(禁止)鼠标右键代码「建议收藏」

    屏蔽(禁止)鼠标右键代码「建议收藏」屏蔽鼠标右键禁止鼠标右键onselectstart="returnfalse"禁止选择,ondragstart="returnfalse"禁止拖放,o

  • 记一次 Centos7 安装使用 PostWoman

    记一次 Centos7 安装使用 PostWoman一、简介官网:https://www.worldlink.com.cn/osdir/postwoman.htmlDEMO:https://postwoman.io/GITHUB下载:https://github.com/liyasthomas/postwoman二、使用工具1、操作系统Centos7.4x64Minimal1708安装1台虚拟机:2G内存1…

    2022年10月28日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号