首页 > 其他分享 >GDB 实验

GDB 实验

时间:2023-11-13 11:37:33浏览次数:31  
标签:core Core int gdb GDB num 实验 test

实验一:安装并简单使用 GDB

预备工作

安装
sudo apt install gdb build-essential gcc
配置
必做
# 格式配置
if ! grep -qi 'kernel.core_pattern' /etc/sysctl.conf; then
  sudo sh -c 'echo "kernel.core_pattern=core.%p.%u.%s.%e.%t" >> /etc/sysctl.conf'
  sudo sysctl -p
fi
ulimit -c unlimited

# 限制解除
sudo bash -c "cat << EOF > /etc/security/limits.conf
* soft core unlimited
* hard core unlimited
EOF"

cat /etc/security/limits.conf
# 出现下列提示时证明配置成功
#* soft core unlimited
#* hard core unlimited
选做
# 设置在当前目录下创建 core(当不能在当前目录生成 core 时使用,如果能正常生成 core 则无需额外配置)
sudo bash -c "echo core.%p.%u.%s.%e.%t > /proc/sys/kernel/core_pattern"
cat /proc/sys/kernel/core_pattern

# 解除 core 文件大小限制
ulimit -c unlimited
ulimit -a

# 下列数值为 unlimited 证明配置成功
#core file size              (blocks, -c) unlimited
知识补充:清屏指令
# 与其他 Linux 工具类似
# ^L,即 Ctrl + L 清屏

实验过程

编写测试文件
cd ~
mkdir gdb-test
cd gdb-test
mkdir test-01
cd test-01
vim test.c
int actual_calc(int a, int b){
  int c;
  c=a/b;
  return 0;
}

int calc(){
  int a;
  int b;
  a=13;
  b=0;
  actual_calc(a, b);
  return 0;
}

int main(){
  calc();
  return 0;
}
生成 Core Dump
# 编译,注意一定要有 --ggdb 否则生成的 Core Dump 中不带 GDB 可以分析的错误信息
# 可以缩写为 gcc -g test.c -o test.o
gcc -ggdb test.c -o test.o

# 执行 test.o
/test.o
知识补充:Core Dump
什么是 Core Dump?

Core Dump 指的是在程序发生严重错误时,操作系统将程序运行时的内存状态和其他相关信息保存到文件中的过程。

为什么要引入 Core Dump?

Core Dump 通常包含了程序执行时的内存快照、寄存器状态、堆栈信息等,用来帮助开发人员在发生错误时进行调试和排查问题。

Linux 什么时候由谁生成 Core Dump?

在Linux中,当一个程序因为诸如段错误、内存访问违例等严重错误而崩溃时,操作系统会生成一个Core Dump文件。这个文件通常会被命名为core,保存在程序崩溃的当前工作目录下。

生成Core Dump文件的操作是由操作系统处理的,通常是通过内核提供的相关机制来实现的。在Linux中,可以通过配置ulimit和/proc文件系统中的一些参数来控制Core Dump文件的生成行为。

怎么分析 Core Dump?

分析Core Dump文件通常需要使用调试工具,比如gdb(GNU调试器)。通过加载Core Dump文件到gdb中,可以查看程序崩溃时的堆栈信息、寄存器状态等,并尝试重现并解决问题。

使用 GDB 分析 Core Dump
# 注意参数是 .o 文件 和 Core Dump
gdb ./test.out core.<p>.<u>.<s>.<e>.<t>
Backtracing
# 列举所有帧信息
bt # bt 是 backtracing 的缩写
Frame Inspection
# 查看要分析的帧
f <n> # f 是 frame 的缩写

# 查看帧对应语句的源码附近的源码,默认显示 10 行
list # list 可简写为 l,容易与 1 看混,所以后续不用缩写

# 打印变量 a 的值
p a # p 是 print 的缩写
# 列举帧
bt
#0  0x0000559050d5e13b in actual_calc (a=13, b=0) at test.c:3
#1  0x0000559050d5e171 in calc () at test.c:12
#2  0x0000559050d5e18a in main () at test.c:17
# 查看帧 0 信息
f 0
#0  0x0000559050d5e13b in actual_calc (a=13, b=0) at test.c:3
3	  c=a/b;

list
1	int actual_calc(int a, int b){
2	  int c;
3	  c=a/b;
4	  return 0;
5	}
6	
7	int calc(){
8	  int a;
9	  int b;
10	  a=13;

# 查看帧 1 信息
f 1
#1  0x0000559050d5e171 in calc () at test.c:12
12	  actual_calc(a, b);

list
7	int calc(){
8	  int a;
9	  int b;
10	  a=13;
11	  b=0;
12	  actual_calc(a, b);
13	  return 0;
14	}
15	
16	int main(){

# 查看帧 2 信息
 f 2
#2  0x0000559050d5e18a in main () at test.c:17
17	  calc();

list
12	  actual_calc(a, b);
13	  return 0;
14	}
15	
16	int main(){
17	  calc();
18	  return 0;
19	}

由此可见,帧序号体现调用顺序,帧序号越小,表示其所在的调用层次越深

参考文档

GDB 教程

core 生成

实验二:使用 GDB 进行单步调试

实验过程

编写测试文件
cd ~/gdb-test
mkdir test-02
vim test.c
#include <stdio.h>
int func02(int num){
    int ret = num * num;
    return ret;
}
int func01(int num){
    int i = 1;
    int sum = 0;
    while(i <= num){
        sum += func02(i);
        i++;
    }
    return sum;
}
int main(){
    int num =0;
    scanf("%d", &num);
    int result = func01(num);
    printf("%d", result);
    return 0;
}
编译
gcc -g test.c -o test
GDB 单步调试
进入 GDB
# 进入 gdb
gdb test -q
源码展示

默认一次显示 10 行,重复执行可以显示所有代码

(gdb) l
1	#include <stdio.h>
2	int func02(int num){
3	    int ret = num * num;
4	    return ret;
5	}
6	int func01(int num){
7	    int i = 1;
8	    int sum = 0;
9	    while(i <= num){
10	        sum += func02(i);
(gdb) l
11	        i++;
12	    }
13	    return sum;
14	}
15	int main(){
16	    int num =0;
17	    scanf("%d", &num);
18	    int result = func01(num);
19	    printf("%d", result);
20	    return 0;
(gdb) l
21	}
(gdb) l
Line number 22 out of range; test.c has 21 lines.
# 如果希望重新展示一次,则可以通过以下语句回退 21 行
l -21
完整执行
run
1
1[Inferior 1 (process 8549) exited normally] # 0 + 1*1 = 1

run
2
5[Inferior 1 (process 8550) exited normally] # 0 + 1*1 + 2*2 = 5

run
3
14[Inferior 1 (process 8552) exited normally] # 0 + 1*1 + 2*2 + 3*3 = 14
断点执行
  • next(可简写为n):大步,单个函数被视为一步
  • step(可简写为s):小步,每行代码被视为一步
  • stepi(可简写为si):小小步:每次执行一条机器指令
  • continue(可简写为c):继续执行程序,直到再次遇到断点
  • until(可简写为u):继续运行到指定位置
    u 29: 执行完前 28 行,显示第 29 行

代码整理

1	#include <stdio.h>
2	int func02(int num){
3	    int ret = num * num;
4	    return ret;
5	}
6	int func01(int num){
7	    int i = 1;
8	    int sum = 0;
9	    while(i <= num){
10	        sum += func02(i);
11	        i++;
12	    }
13	    return sum;
14	}
15	int main(){
16	    int num =0;
17	    scanf("%d", &num);
18	    int result = func01(num);
19	    printf("%d", result);
20	    return 0;
21	}
# 设置断点
b 16 # 输入前设置断点,下一步才能输入16
b 19 # 输出前设置断点,下一步才能输出
(gdb) run # run 直接执行完断点所在行的前一行,即执行完前 15 行,显示第 16 行
#Starting program: /home/xxx/gdb-test/test-02/test 3
#[Thread debugging using libthread_db enabled]
#Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
#
#Breakpoint 1, main () at test.c:16
#16	    int num =0;
(gdb) p num
#$1 = 4096 
# 分析:$1 = 4096,num 尚未初始化,证明第 16 行尚未执行

(gdb) next # 执行第 16 行,显示第 17 行
#17	    scanf("%d", &num);
(gdb) p num
#$2 = 0 
# 分析:$2 = 0,num 已经初始化,证明第 16 行已经执行

(gdb) next # 执行第 17 行,要求输入一个数字,此处输入 5,显示第 18 行
5
#18	    int result = func01(num);

(gdb) next # 执行第 18 行,显示第 19 行
#Breakpoint 2, main () at test.c:19
#19	    printf("%d", result);

(gdb) next # 执行第 19 行,显示第 20 行
20	    return 0;

(gdb) next # 执行第 20 行,显示第 21 行
21	}

(gdb) next # 执行第 21 行,显示奇怪信息
#__libc_start_call_main (main=main@entry=0x5555555551df <main>, argc=argc@entry=2, argv=argv@entry=0x7fffffffdfa8) at ../sysdeps/nptl/libc_start_call_main.h:74
#74	../sysdeps/nptl/libc_start_call_main.h: No such file or directory.

(gdb) next # 输出结果
55[Inferior 1 (process 8606) exited normally]

(gdb) next # 本次执行已完成
The program is not being run.

-q 参数说明

gdb test # 显示完整信息
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
gdb test -q # -q: 只显示关键信息,introductory 和 copyright 等无用信息不显示
Reading symbols from test...

参考文档

GDB 单步调试

GDB 调试基础

GDB 使用详解

标签:core,Core,int,gdb,GDB,num,实验,test
From: https://www.cnblogs.com/ba11ooner/p/17828759.html

相关文章

  • 大型数据库实验六
    实验六--熟悉Hive的基本操作1、创建一个内部表,字段分隔符为英文逗号2、创建一个外部分区表dividends(分区字段为exchange和symbol),字段分隔符为英文逗号3、从stocks.csv向stocks导入数据4、创建一个未分区的外部表dividends_unpartitioned,并从dividends.csv向其中导入数据......
  • 大数据实验二
    实验环境:(1)操作系统:Linux(2)Hadoop版本:3.1.3;(3)JDK版本:1.8;(4)JavaIDE:实验内容与完成情况:(一)编程实现以下功能,并利用Hadoop提供的Shell命令完成相同任务:(1) 向HDFS中上传任意文本文件,如果指定的文件在HDFS中已经存在,则由用户来指定是追加到原有文件末尾还是覆盖原有的文件; ......
  • 实验3
        ......
  • 实验十二
    在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on()),即可调用其他硬件设备和软件的启动方法,如内存(Memory)的自检(check())、CPU的运行(run())、硬盘(HardDisk)的读取(read())、操作系统(OS)的载入(load()),如果某一过程发生错误则计算机启动失败。实验要求:1.提交类图;2.......
  • 实验12:外观模式
    [实验任务一]:计算机开启在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on()),即可调用其他硬件设备和软件的启动方法,如内存(Memory)的自检(check())、CPU的运行(run())、硬盘(HardDisk)的读取(read())、操作系统(OS)的载入(load()),如果某一过程发生错误则计算机启动失败。......
  • 实验13:享元模式
    [实验任务一]:围棋设计一个围棋软件,在系统中只存在一个白棋对象和一个黑棋对象,但是它们可以在棋盘的不同位置显示多次。  packagerjsj.no13;/** *客户端测试类 * */publicclassClient{   publicstaticvoidmain(String[]args){       IgoCh......
  • 实验十三
    设计一个围棋软件,在系统中只存在一个白棋对象和一个黑棋对象,但是它们可以在棋盘的不同位置显示多次。实验要求:1.提交类图;2.提交源代码;3.注意编程规范;4.要求用简单工厂模式和单例模式实现享元工厂类的设计。类图publicclassBlackChessimplementsChessPiece{publi......
  • 软件设计实验10:组合模式
    实验10:组合模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:1、理解组合模式的动机,掌握该模式的结构;2、能够利用组合模式解决实际问题。 [实验任务一]:组合模式用透明组合模式实现教材中的“文件夹浏览”这个例子。实验要求:1. 文件的执行不需真正实现,只需简单......
  • 软件设计实验11:装饰模式
    实验11:装饰模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容: 1、理解装饰模式的动机,掌握该模式的结构;2、能够利用装饰模式解决实际问题。 [实验任务一]:手机功能的升级用装饰模式模拟手机功能的升级过程:简单的手机(SimplePhone)在接收来电时,会发出声音提醒主人;而......
  • 高飞实验12和13
    packageshiyan12;publicclassClient{publicstaticvoidmain(String[]args){MainFramemainframe=newMainFrame();mainframe.on();}}Clientpackageshiyan12;publicclassCPU{publicbooleanrun(){System.out.......