Linux友人帐之调试器--gdb的使用

一、debug和realease版本的区别

区别

debug是给程序员用的版本,添加了调试信息,用于解决软件或程序中出现的问题,realease是发行给客户使用的版本,并未添加调试信息,只需要给客户提供优越的产品使用环境即可,至于是否能够debug调试,这是程序员才应该关心的主要问题。

可以看到debug版本的字节大小是要大于realease版本的,这是因为其中添加了调试信息。

通过指令可以读取可执行程序的二进制构成,显示出具体的二进制软件的内部所形成的特定格式。

值得注意的是:每一个二进制程序不仅仅只是一堆二进制代码,他们内部都是有特定格式的,Linux中形成的可执行程序是elf格式。

readelf命令

readelf命令是一个可以读取ELF(Executable and Linkable Format)文件头部信息的Linux命令。ELF文件是一种可执行文件和共享库的标准格式,包含了代码段、数据段、符号表和动态链接信息等。通过readelf命令,用户可以查看这些信息,如ELF文件的类型、入口地址、节区信息、符号表、重定位信息、动态链接信息等。

常用的readelf命令选项包括:

  • -a或--all:显示所有信息,默认选项;
  • -h或--file-header:显示文件头(包括ELF文件类型、入口地址等);
  • -S或--sections:显示节区信息;
  • -s或--symbols:显示符号表信息;
  • -r或--relocs:显示重定位信息;
  • -d或--dynamic:显示动态链接信息。

下面就是debug中所添加的调试信息,而realease版本是没有这些调试信息的

二、 调试器gdb

3.1gdb介绍

gdb是GNU开源组织发布的一个用于Unix/Linux的程序调试工具。

与其它调试器一样,gdb可以在程序中设置断点、查看变量值,跟踪程序执行的过程。

利用调试器的这些功能可以方便地找出程序中存在的非语法错误。

3.2环境配置

安装

编写一个用于测试的程序test.c

cpp 复制代码
#include <stdio.h>

int get_sum(int n)
{
  int sum = 0, i;
  for (i = 1; i <= n; i++)
    sum += i;
  return sum;
}

int main()
{
  int j = 100, res;
  res = get_sum(j);
  printf("1+2+...+%d = %d\n", j, res);
  return 0;
}

编译并运行该程序

gcc -g test.c -o test

需要-g参数

./test

几点注意:

  • 默认情况下,gdb无法进行对gcc现在发布的程序进行调试,因为gcc默认生成的软件是realease版本的,没有调试信息,无法被调试器gdb调试,并且gcc是默认动态链接的,如果想静态链接还需要加static选项,所有gcc是有两种默认行为的。
  • gcc编译时添加-g选项可以使得gcc发布的程序软件为debug版本,这样就可以通过gdb对程序进行调试

3.3gdb的启动和退出

启动:

  1. gdb [程序名]

gdb test

  1. gdb --quiet

(gdb)file test

退出

(gdb)quit

3.4gdb常用命令

help命令

其他命令

显示程序源代码list

list: 输出从上次调用list命令开始向后的10行程序代码

list -: 输出从上次调用list命令处向前10行代码

list n: 输出n行附近的10行代码

list [函数名]: 输出函数附近的10行代码

list n1,n2: 显示第n1行到n2行的代码

搜索字符串

forward/search [字符串]: 从当前位置向后查找指定的字符串所在的程序行,查找时不包括当前行,可以用list n,n将当前行设置为n

reverse-search [字符串]: 从当前行向前查找第一个匹配的字符串

执行程序

在shell环境下使用gdb test,或在gdb环境下使用file test只是载入了程序,但是程序是没有运行的

运行:

(gdb)run

3.5断点的设置和管理

设置断点

1 以行数设置断点

格式: break n

功能: 当程序运行到指定行时,会暂停执行,指定行的代码不执行

例如:

(gdb)break 15

(gdb)run

2 以函数设置断点

格式: break [函数名]

例如:

(gdb)break get_sum

(gdb)run

3 以条件表达式设置断点

格式: break [行号或函数名] if [条件]

功能: 程序在运行过程中,满足设定条件时,程序在所设置处中断

例如:

(gdb)break 7 if i==99

含义: 当程序执行到第7行时,判断条件i==99是否成立,若成立则中断

4 以条件表达式变化设置断点

格式: watch [条件表达式]

功能: 程序在运行过程中,当满足设定条件时,程序中断

注意:watch必须在程序运行的过程中设置观察点,即运行run之后,并且要保证条件表达式中的变量已经使用过。

例1

(gdb)break 13

(gdb)run

(gdb)watch sum==3

例2

(gdb)break 5

(gdb)run

(gdb)watch sum==3

查看断点

查看当前设置的断点

格式: info breakpoints(info b

例如:

(gdb)break 7

(gdb)break 15 if res==5050

(gdb)info breakpoints

管理断点

1. 使中断失效或有效

失效: disable [断点编号]

有效: enable [断点编号]

2. 删除断点

clear [行号]: 删除此行的断点

delete [断点编号]: 删除指定编号的断点, 若有一次删除多个断点,各断点编号以空格分开。

delete: 删除程序中所有的断点

3. 取消断点 d + 断点编号

查看和设置变量的值

当程序执行到中断点暂停时,往往需要查看变量或表达式的值,借此了解程序的执行状态,进而发现问题。

1 print

功能: 打印变量或表达式的值,还可以用来对某个变量进行赋值。

print [变量或表达式]: 打印变量或表达式的值

print [变量]=[值]: 对变量进行赋值

例如:

(gdb)break 7

(gdb)run

(gdb)print i < n

(gdb)print i

(gdb)print sum

(gdb)print i=200

(gdb)continue

2 whatis

功能: 用于显示某个变量或表达式的数据类型

格式: whatis [变量或表达式]

例如:

(gdb)break 7

(gdb)run

(gdb)whatis i

(gdb)whatis sum

(gdb)whatis sum+0.5

3 set

功能: 给变量赋值

格式: set variable [变量]=[值]

4.临时查看变量或地址的值:p + 变量或地址

控制程序的执行

当程序执行到指定的中断点时,完成相关的debug操作后,可以让程序继续运行

1 continue

程序继续运行,直到下一个断点或运行完毕(运行至下一个断点处**:c(**continue))

2 kill

结束当前程序的调试

3 next/step

功能: 一次一条执行程序代码(逐过程:n(next),逐过程:n(next)

区别: next把函数调用当做一条语句来执行;step追踪进入函数,一次一条地执行内部代码。

4.跳转到指定行:until+行号

可以利用until来跳出循环

相关推荐
程序员南飞35 分钟前
ps aux | grep smart_webrtc这条指令代表什么意思
java·linux·ubuntu·webrtc
StrokeAce35 分钟前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
热爱嵌入式的小许4 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风8 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学8 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO8 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu79 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我9 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、9 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程9 小时前
Linux中环境变量
linux