前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Linux】Linux调试器-gdb使用

【Linux】Linux调试器-gdb使用

作者头像
zxctscl
发布2024-04-10 08:48:00
1420
发布2024-04-10 08:48:00
举报
文章被收录于专栏:zxctscl个人专栏zxctscl个人专栏

个人主页zxctscl 如有转载请先通知

1. 前言

在前面的博客【Linux】编译器-gcc/g++使用已经分享了关于编译器的使用,而编译器的使用离不开调试,这次就来分享一下Linux调试器-gdb使用。

2. 调试前准备

要调试就得先有代码,先用C语言写一段简单的代码myprocess.c,再写好Makefile: myprocess.c代码:

代码语言:javascript
复制
  1 #include<stdio.h>
  2
  3   int AddToTarget(int start,int end)
  4 {
  5   int i=start;
  6   int sum=0;
  7   for(i=start;i<=end;i++)
  8   {
  9     sum+=i;
 10   }
 11   return sum;
 12
 13 }
 14 int main()
 15 {
 16   printf("run begin...\n");
 17
 18   int result=0;
 19   result=AddToTarget(1,100);
 20   printf("result:%d\n",result);
 21
 22   printf("run end...\n");
 23 }

Makefile:

代码语言:javascript
复制
  1 myprocess:myprocess.c
  2   gcc -o $@ $^
  3 .PHONY:clean
  4 clean:
  5   rm -f myprocess

make一下没有问题:

在vs发布软件有两种模式一种是debug,一种是release。 测试用的是debug,可以被跳绳,而开发出来的release版本,是不可以调试的。

在debug版本中,编译器形成可执行程序的时候,会给可执行程序添加调试信息。

gcc/g++默认编译,采用的是release模式

如果想让gcc/g++采用debug模式,就得再后面加上-g选项

怎么来判断是不是debug模式呢? 在debug模式下新加了调试信息,体积就会比release模式下的大,那么就确定debug模式会新增加东西。 来测试一下:在Makefile里面新加-g选项:

代码语言:javascript
复制
  1 myprocess-debug:myprocess.c
  2   gcc -o $@ $^ -g
  3 .PHONY:clean
  4 clean:
  5   rm -f myprocess

然后make一下: 发现两个程序都可以跑:

对比发现debug的体积比较大:

在这里插入图片描述
在这里插入图片描述

为了给用户更好的体验,发布release模式,减少了不必要的调试,也减小下载时带宽的浪费。 而程序员在写代码的时候需要调试,所以就有了release模式和debug模式。

读一下debug模式下的信息:

代码语言:javascript
复制
readelf -S myprocess-debug

发现下面有debug信息

忽略大小写信息,在debug下的调试信息:

代码语言:javascript
复制
readelf -S myprocess-debug | grep -i debug

用同样的方式来查看release版本下的调试信息:readelf -S myprocess | grep -i debug 发现没有debug信息

3. 使用

3.1 进入gdb

默认系统中会安装gdb,使用方法就是gdb后面直接加上调试的可执行程序名:

代码语言:javascript
复制
 gdb myprocess-debug

就会默认进入到调试模式

想要退出就直接输入quit或者q

代码语言:javascript
复制
quit/q

gdb本身就是一个进程,把程序启动起来

3.2 list

list来显示程序代码

代码语言:javascript
复制
list

list后面直接更程序名是查不了代码的:

为了方便list可以直接简写为l

如果想要从程序第一行开始查就用命令:

代码语言:javascript
复制
l 0

还可以使用l加程序名再加0的方式

代码语言:javascript
复制
l myprocess.c:0

不可以直接查文件,但是加上行号就可以查。 还可以查main函数:

代码语言:javascript
复制
l myprocess.c:main

想要查某一块代码可以加上行号,也可以加上对应的函数名就可以了。 发现gdb查代码只能默认查10行

如果想要全部打出来怎么办? gdb默认会记录用户最近的一条命令,直接按回车 就可以拿到全部的代码

如果查看第15行:

发现它并不是从15行开始,而15行差不多是在显示的代码中间的位置。 同样查看AddToTarget也是:

l查指定的行或者函数时候,会显示它的上下文。

3.3 run

run就是把程序运行起来,简写为r

这个run的功能就类似于VS里面的F5,直接运行不调试。

3.4 与断点有关操作

3.4.1 b打断点

gdb中用b来打断点 可以直接用b加程序名加函数 比如在main函数处打一个断点:

代码语言:javascript
复制
b myprocess.c:main

比较一下发现,代码断点并不是打在15行位置,而值17行,因为17行是main函数的入口位置:

在第20行打断点,直接这样:

代码语言:javascript
复制
b myprocess.c:20

因为每个断点都有自己的编号

想要连续打断点,怎么办呢? 如果加上“,”发现不能用。

试一下空格:发现也不行

所以断点不允许连续去打,而必须一个一个去打:

而这里的断点编号是3和4,因为1和2在前面已经用了。

所以断点的本质是一个线性增长的计数器。 代码运行到断点位置就会停下来:

3.4.2 info显示断点位置

info(或i) breakpoints:参看当前设置了哪些断点 info(i) locals:查看当前栈帧局部变量的值 在vs下打断点就会有红点

那么在gdb下怎么知道哪些地方打了断点呢? 这里就要用到一个命令info

代码语言:javascript
复制
info b

或者写成:

代码语言:javascript
复制
i b

就能显示出来在哪些地方打了断点:

这里的Enb表示使能,代表一定有断点,但不一定打开。而这里的y表示断点打了能用。

info查当前变量的值:

3.4.3 d去断点

在vs里面要取消断点直接点一下或者按F9。 在gdb下用的是d加文件名加行号,发现不能用

删断点就要用这里的Num:

删除一号断点:

代码语言:javascript
复制
d 1

再删除2号断点

此时已经没有断点了。

3.4.4 disable使能

在vs中在断点位置右击可以禁用断点:

在调试的时候就会跳过禁用的断点:

也就是把这个断点使能了。

而在gdb中也想这样做,那么就用下面这个命令:

代码语言:javascript
复制
disable Num

试一下myprocess.c里面的3号断点:

代码语言:javascript
复制
disable 3

发现3号断点的Enb就变为n了:

重新运行一下代码:发现停在了19行,因为17行的断点使能已经关闭,而18行是空行,就直接到了19行:

空行是不做调试的,打了断点也没用。

在vs里面要想启动断点,直接右击就会出现

而在gdb中重新启动,想要用到命令:

代码语言:javascript
复制
enable Num

重新启动3号断点:

代码语言:javascript
复制
enable 3

发现这里的3号断点的Enb就变为y了

3.5 next/n逐过程

在vs里面的F10就是逐过程,就是在调试时候单步往下走时,如果碰见当前行的代码是函数,就直接把这个函数执行完,把这个函数当成一条语句直接执行完。 在gdb中想要实现逐过程就得用到命令:

代码语言:javascript
复制
next/n

打了一个断点在17行:

然后用来实现逐过程调试:发现并没有进入到AddToTarget函数里面:

3.6 step/s逐语句

在在vs里面的F11就是逐语句,在调试的时候,遇到函数就要进到这个函数里面,把这个函数里面的代码一行一行运行完。

在gdb中想要进入到函数的内部就用命令:

代码语言:javascript
复制
step/s

打了一个断点在17行:

然后用来实现逐语句调试:发现进入到AddToTarget函数里面:

发现这个代码就在7和9行之间反复执行:

3.7 print/p查看变量内容及地址

print/p查看变量内容及地址 在vs里面常用的监视窗口:

而在gdb中用到的命令就是:

代码语言:javascript
复制
 print/p

来试一下: 这时就能看到i对应的值了:

查里面的地址就加上取地址符就行:

3.8 display常显示

每次都先输入p才能查看监视的内容,太麻烦,就用display来进行常显示,每次都自动变化:

代码语言:javascript
复制
display

它也可以来查看地址:

3.9 undisplay

发现每一次常显示前面都会有一个编号:

如果不想常显示,就用到undisplay去掉常显示

代码语言:javascript
复制
undisplay+编号

去掉5号和4号监视:

3.10 continue/c运行到下一个断点处

一般在vs里面可以直接从一个断点处运行到下一个断点处,就是执行中间那一部分。 而在gdb中想要一个部分一个部分的调试,从而方便找出代码的问题,就用到命令:

代码语言:javascript
复制
continue/c

先打一些断点;

此时运行的时候就发现在17行就停下来了:

想要直接从一个断点运行到下一个断点处就直接:c

3.11 finish

finish运行结束所在函数,就停下来 如果函数里面有问题,在不进入函数里面,就想知道函数有没有问题,就用到命令:

代码语言:javascript
复制
finish

finish就是把指定的函数跑完 来测试一下:

3.12 until

until:跳转到指定行,中间的代码都是运行了的。 进入到函数体里面就退不出来

如果想要跳转到某一行,就用到命令:

代码语言:javascript
复制
until

试一下跳转到12行:

总结一下gdb使用就是:

set var:修改变量的值 把指定变量直接修改为目标值,然后检测等于这个目标值时会不会执行对应代码。 举个例子:把i值改为100

3.13 bt

bt就相当于调用堆栈

有问题请指出,大家一起进步!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 前言
  • 2. 调试前准备
  • 3. 使用
    • 3.1 进入gdb
      • 3.2 list
        • 3.3 run
          • 3.4 与断点有关操作
            • 3.4.1 b打断点
            • 3.4.2 info显示断点位置
            • 3.4.3 d去断点
            • 3.4.4 disable使能
          • 3.5 next/n逐过程
            • 3.6 step/s逐语句
              • 3.7 print/p查看变量内容及地址
                • 3.8 display常显示
                  • 3.9 undisplay
                    • 3.10 continue/c运行到下一个断点处
                      • 3.11 finish
                        • 3.12 until
                          • 3.13 bt
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档