GDB调式工具学习笔记---单步执行和跟踪函数调用

2023-05-16

GDB调式工具学习笔记---单步执行和跟踪函数调用

  • 简介
  • 1.单步执行和跟踪函数调用
    • 1.1 示例程序
    • 1.2 常用命令
      • 1.2.1 help
      • 1.2.2 list (l)
      • 1.2.3 quit
      • 1.2.4 start
      • 1.2.5 next(n)
      • 1.2.6 step(s)
      • 1.2.7 backtrace(bt)
      • 1.2.8 info(i)
      • 1.2.9 frame(f)
      • 1.2.10 print(p)
      • 1.2.11 set var
      • 1.2.12 finish
    • 1.3 命令小结

简介

在使用图形化ide进行程序开发时,通常编辑工具都会自带调试功能,可以打断点,一步一步的执行代码并随时查看每个变量的实时数值,但是在进行c和c++开发时,常常是在linux系统下进行,并且是通过vim或vi编辑器,没有图形化的界面,这是gdb调试工具就会派上了用场,它提供了我们日常调试程序时需要的大多功能,本篇文章是作者在阅读《Linux C编程:一站式学习》一书中关于GDB工具使用这一章节的学习笔记。

1.单步执行和跟踪函数调用

1.1 示例程序

首先阅读以下代码,该代码的主要功能是实现数的累加

#include <stdio.h>
int add_range(int low, int hight)
{
	int i, sum;
	for(i = low; i <= hight; i++)
	{
		sum += i;
	}
	return sum;
}

int main()
{
	int res1, res2;
	res1 = add_range(1, 10);
	res2 = add_range(1, 100);
	printf("res1 = %d, res2 = %d\n", res, res2);
	return 0;
	}

以下是书中给出的运行结果

res1 = 55, res2 = 5105

但是,有意思的是,作者亲自运行之后,发现并没有出现原书作者给出的输出结果,作者也知道不会出现,因为变量sum定义之后,没有初始化,书中的结果可能是作者为了将gdb调试专门设置的输出结果吧,不妨碍学习。以下是作者运行程序输出结果

zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 21911, res2 = 26961
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22009, res2 = 27059
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22012, res2 = 27062
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22051, res2 = 27101
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22155, res2 = 27205
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22001, res2 = 27051
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22016, res2 = 27066

可以看到,结果是一直变化的,这非常符合变量未初始化就被使用的结果,我们给sum赋值为0之后,程序会正常运行输出我们想要的结果。这里假设我们不知道错在哪,程序运行输出之后,我们假装一脸懵逼,这时候gdb就该上场了。

1.2 常用命令

运行以下命令

gcc -g demo1.c -o demo1
gdb demo1

在编译的时候加上编译选项-g表示是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。

1.2.1 help

帮助命令,可以查看命令的类别,也可以指定查看某一命令的具体说明
(gdb) help
List of classes of commands:

aliases -- Aliases of other commands.
breakpoints -- Making program stop at certain points.
data -- Examining data.
files -- Specifying and examining files.
internals -- Maintenance commands.
obscure -- Obscure features.
running -- Running the program.
stack -- Examining the stack.
status -- Status inquiries.
support -- Support facilities.
tracepoints -- Tracing of program execution without stopping the program.
user-defined -- User-defined commands.

Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Type "apropos -v word" for full documentation of commands related to "word".
Command name abbreviations are allowed if unambiguous.

1.2.2 list (l)

列出源代码内容,运行一次命令,显示10行,需要继续浏览,只需要按回车键,默认执行上次的命令
(gdb) list
1       #include <stdio.h>
2
3       int add_range(int low, int hight)
4       {
5               int i, sum;
6               for(i = low; i <= hight; i++)
7               {
8                       sum += i;
9               }
10              return sum;
(gdb)
11      }
12
13      int main()
14      {
15              int res1, res2;
16              res1 = add_range(1, 10);
17              res2 = add_range(1, 100);
18              printf("res1 = %d, res2 = %d\n", res1, res2);
19              return 0;
20      }
(gdb)

1.2.3 quit

退出命令,推出gdb调试环境

1.2.4 start

程序开始运行命令
(gdb) start
Temporary breakpoint 1 at 0x1176: file demo1.c, line 14.
Starting program: /home/zz/Project/gdb_study/demo1

Temporary breakpoint 1, main () at demo1.c:14
14      {

运行该命令之后可以发现,自动跳转到了main函数的开头部分,同时表明了所在行号。

1.2.5 next(n)

继续执行命令,控制程序执行下一行
(gdb) next
16              res1 = add_range(1, 10);
(gdb)
17              res2 = add_range(1, 100);
(gdb)
18              printf("res1 = %d, res2 = %d\n", res1, res2);
(gdb)
res1 = 21900, res2 = 26950
19              return 0;
(gdb)
20      }
(gdb)

1.2.6 step(s)

跟踪进入执行的函数

在一路调用next命令之后我们发现,并没有发现任何异常,可能程序出错点并不在主函数,而是实在主函数中调用的函数中,但是执行next命令,系统会自动跳过该函数,想要进入该函数一步一步跟踪程序就需要step命令了。

(gdb) start
Temporary breakpoint 2 at 0x555555555176: file demo1.c, line 14.
Starting program: /home/zz/Project/gdb_study/demo1

Temporary breakpoint 2, main () at demo1.c:14
14      {
(gdb) next
16              res1 = add_range(1, 10);
(gdb) step
add_range (low=21845, hight=1431654941) at demo1.c:4
4       {

从上面看到,进入add_range函数之后,形参都被赋予了乱七八糟的数值,和我们预料的不一样,和书上的说的也不一样,这里先不做说明,后面作者会有一些个人猜想。

1.2.7 backtrace(bt)

查看函数调用的栈帧
(gdb) bt
#0  add_range (low=21845, hight=1431654941) at demo1.c:4
#1  0x0000555555555191 in main () at demo1.c:16

1.2.8 info(i)

查看参数的值
  1. info locals 查看局部参数
  2. info arg 查看函数形参
(gdb) i locals
i = 1431654864
sum = 21845
(gdb) info locals
i = 1431654864
sum = 21845
(gdb) info arg
low = 21845
hight = 1431654941

可以看到函数的局部参数和形参都是乱起八糟的值,作者猜想,此时函数刚被压入栈中,内存刚刚被分配,形参和局部参数被创建,实参对形参的赋值还未完成,我们在往下执行一步。

(gdb) n
6               for(i = low; i <= hight; i++)
(gdb) info locals
i = 1431654864
sum = 21845
(gdb) info arg
low = 1
hight = 10
(gdb)

可以看到,当函数执行到第六行,局部参数是乱码是因为未被初始化也被被赋值,但是形参可以看到已经是正确的值了,说明实参成功为形参赋值。

1.2.9 frame(f)

函数栈帧切换

此时此刻,程序已经在add_range函数中,如果此时想要查看主函数中的参数信息该怎么办?使用frame命令可以机型函数栈帧的切换

(gdb) bt
#0  add_arrange (low=1, hight=10) at demo1.c:6
#1  0x0000555555555191 in main () at demo1.c:16
(gdb) frame 1
#1  0x0000555555555191 in main () at demo1.c:16
16              res1 = add_arrange(1, 10);
(gdb) i locals
res1 = 0
res2 = 0
(gdb) f 0
#0  add_arrange (low=1, hight=10) at demo1.c:6
6               for(i = low; i <= hight; i++)

可以看到,使用backtrace命令,查看当前函数栈帧信息,使用frame 函数栈帧编号命令切换到制定的函数栈帧,此时使用info locals命令查看当前主函数中的局部参数的值,查看完之后,使用frame命令切换到add_range函数,可以看到此时还是处于之前函数运行的地方。

1.2.10 print§

打印变量的值
(gdb) print sum
$1 = 21845

这里的$1表示gdb保存着这些中间结果,$1后面的编号会自动增长,在命令中可以用$1$2$3等编号代替相应的值。

1.2.11 set var

设置变量为指定值

咳咳,心机之娃一直摸你肚子,凶手就是sum变量未初始化,为了验证我们的想法,我们将sum手动初始化,查看结果是否为我们所期待的结果。

(gdb) set var sum=0
(gdb) print sum
$4 = 0

1.2.12 finish

连续运行到当前函数返回为止,然后停下来等待命令
(gdb) finish
Run till exit from #0  add_arrange (low=1, hight=10) at demo1.c:6
0x0000555555555191 in main () at demo1.c:16
16              res1 = add_arrange(1, 10);
Value returned is $5 = 55

可以看到,函数成功运行到最后,同时返回值为55,说明我们的想法完全正确,程序出错是因为sum变量未初始化的原因。

1.3 命令小结

命令描述
backtrace(bt)查看各级函数调用及参数
finish连续运行到当前函数返回为止,然后停下来等待命令
frame(f)选择函数栈帧
info(i)查看当前参数信息(locals:查看局部变量参数;arg:查看函数形参数值;registers:查看当前寄存器数据)
list(l)列出源代码,每次列出10行,有记忆性,接上次列出之后往下列出(后面加行号,从该行号开始列出代码;后面加函数名:列出该函数的代码)
next(n)执行下一条语句
print§打印表达式的值,通过表达式可以修改变量的值或者调用函数
quit(q)退出gdb调试环境
set var修改变量的值
start开始执行程序,停留在main函数的第一行语句前面等待命令
step(s)执行下一条语句,如果有函数则进入到函数中
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GDB调式工具学习笔记---单步执行和跟踪函数调用 的相关文章

随机推荐

  • ubuntu中安装比较工具meld及其使用

    在ubuntu中需要比较配置文件的差异 xff0c 于是安装meld apt get install meld 安装完后 xff0c 在 usr bin 下找到meld 然后发送到桌面上 xff0c 打开后选择 xff1a file gt
  • 混合A*算法---Hybrid A Star

    文章目录 0 Lattice Graph1 Hybrid A Star2 Hybrid A Star伪代码3 启发式函数选择4 One Shot5 Application6 总结 0 Lattice Graph 考虑机器人运动模型下的路径规
  • RRT算法原理和代码详解(快速扩展随机树)

    文章目录 优缺点伪代码具体流程效率问题代码 优缺点 优缺点先明说 xff0c 优点RRT Star适用于任何地图 xff0c 不像A Star xff0c Dijkstra那样受限于栅格地图 缺点 xff1a 1 找到的路径可能不是最优的
  • 基于智能算法(遗传算法、蚁群算法)的路径规划

    文章目录 思路实例种群初始化选择交叉变异 总结 思路 模拟生物进化过程 xff0c 物竞天择 xff0c 适者生存 首先就是要产生一些种群 xff0c 进行种群的初始化主要有以下三步 xff1a 选择交叉变异 实例 假设现在为栅格图形进行编
  • 基于软约束的轨迹(路径)优化原理公式推导详解

    文章目录 0 回顾1 软约束的轨迹优化1 1 方法描述1 2 顺滑性目标函数的构建及其梯度1 3 碰撞目标函数的构建及其梯度 2 软约束轨迹优化方法的优缺点3 Code 0 回顾 回顾 M i n i m
  • 哈工大李治军老师操作系统笔记【10】:内核级线程实现(Learning OS Concepts By Coding Them !)

    文章目录 0 回顾1 实现1 1 int 0x80 fork xff08 中断入口 xff09 1 2 进入核心态1 3 system call xff08 中断切换中间三段 xff09 1 4 中断出口1 3 switch to1 4 T
  • 计算机网络知识点总结(每日更新)

    文章目录 0 计算机网络概述0 1 计算机网络在信息时代的作用0 2 计算机网络的重要功能0 3 因特网概述0 3 1 理论0 3 2 三个阶段 0 4 多层次的ISP结构0 5 因特网的组成0 6 三种交换的比较0 7 性能指标0 7 1
  • 每日一题:20. 有效的括号

    文章目录 0 概览1 题解2 Code3 结果 0 概览 经典的括号问题 1 题解 栈是一种先进后出的数据结构 xff0c 处理括号问题的时候尤其有用 遇到左括号就入栈 xff0c 遇到右括号就去栈中寻找最近的左括号 xff0c 看是否匹配
  • 每日一题:915. 分割数组

    文章目录 0 概览1 题解2 题解3 结果 0 概览 最近有点忙 xff0c 没怎么更新哈哈哈 1 题解 其实我们的目的 xff0c 就是找到左边数组最大的 xff0c 以及右边数组最小的 xff0c 如果能得到的结果是左边数组最大的全部都
  • 每日一题:200. 岛屿数量

    文章目录 0 题目概览1 题解2 Code3 结果 0 题目概览 1 题解 岛屿系列问题可以用 DFS BFS 算法或者 Union Find 并查集算法 来解决用 DFS 算法解决岛屿题目是最常见的 xff0c 每次遇到一个岛屿中的陆地
  • aruco二维码

    1 二维码的生成 简单方式 xff1a 直接在下面的网站上选择 xff0c 操作简单https chev me arucogen 网站界面如下 xff1a
  • STM8S 功耗总结

    http blog sina com cn s blog 542bad910101ral2 html STM8S103 STM8S003 PA1脚虽可以用外部中断唤醒CPU xff0c 但功耗过大 xff0c 有300uA电流 xff0c
  • ESP32四轴飞控硬件设计

    一 前言 目前许多入门级开源飞控都是基于STM32系列的 xff0c 基于此系列的有非常严重的短板 xff0c 例如说通信方面 xff0c 需要外置通信模块 ESP32本身带有WIFI和蓝牙 xff0c 在通信方面有着一定的优势 xff0c
  • C++弹窗拦截程序,弹窗广告怎么关闭?不用问,我教你怎么屏蔽!

    现在大家使用电脑的频率越来越高 xff0c 上课写作业 上班做工作 娱乐生活 在家购物等 xff0c 我们使用电脑的时间越来越长 相信很多人都和小编一样 xff0c 经常遇到电脑的右下角出现出现弹窗广告的问题 要去叉掉就很麻烦 而且有时候想
  • VNC远程桌面使用方法

    参考 xff1a https blog csdn net weixin 41803874 article details 81233789 一共两台电脑 xff0c 分别为服务端和客户端 xff0c 为与场景联系方便 xff0c 我们将需要
  • 激光雷达闭环检测/地点识别算法OverlapTransformer/SeqOT(2022)

    最新激光雷达闭环检测 地点识别算法 OverlapTransformer已经完整开源 xff0c 相关论文已经被RAL IROS 2022收录 https github com haomo ai OverlapTransformer Ove
  • 我的创作纪念日

    初心未改 xff0c 继续向前
  • 最新激光雷达闭环检测/地点识别算法CVTNet(2023)

    CVTNet以激光点云多类投影生成的二维图为输入 xff0c 利用cross transformer将多类信息交叉融合 xff0c 为激光点云提取强特异性描述子 xff0c 实现SLAM闭环检测或全局定位功能 此外 xff0c CVTNet
  • python使用ffmpeg推流出现OSError: [Errno 2] No such file or directory

    python使用ffmpeg推流出现OSError Errno 2 No such file or directory 具体错误如下 xff1a Traceback span class token punctuation span mos
  • GDB调式工具学习笔记---单步执行和跟踪函数调用

    GDB调式工具学习笔记 单步执行和跟踪函数调用 简介1 单步执行和跟踪函数调用1 1 示例程序1 2 常用命令1 2 1 help1 2 2 list l 1 2 3 quit1 2 4 start1 2 5 next xff08 n xf