【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解

这篇具有很好参考价值的文章主要介绍了【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

目录

🌞1. 整体思路

🌞2. 准备内容

🌼2.1 配置.c文件

🌼2.2 准备测试程序

🌼2.3 GDB调试基础

🌞3. GDB调试四层二叉树

🌼3.1 测试程序分析

🌼3.2 gdb分析

🌻1. 设置断点

🌻2. 启动程序并执行到断点处

🌻3. 打印变量的值

🌻4. 单步执行 s 进入buildTree函数内部

a. 第一层:根节点赋值

b. 第二层:节点赋值

c. 第三层:节点赋值

d. 第四层:节点赋值

e. 退出buildTree函数

🌻5. 单步执行 s 进入traverseTree函数内部:跟踪输出结果

🌻6. 跟踪错误

a. 查看指针 ptr 的值

b. 查看 ptr 所指向的地址

c. 回溯调用堆栈

d. 查看核心转储文件

🌞4. gdb技巧

🌼4.1 打印输出指定地址的值

🌼4.2 查看当前执行到哪行代码+代码内容


🌞1. 整体思路

在案例中我使用c语言编写了一个简单的四层二叉树进行 GDB 调试练习。这个程序故意在后面引发了一个段错误,导致程序崩溃。文章将使用 GDB 来诊断这个问题。


🌞2. 准备内容

建议阅读前先查看gdb的技巧
传送门:【GDB调试技巧】提高gdb的调试效率-CSDN博客

🌼2.1 配置.c文件

建议先配置一下.c文件使其显示行数【方便后续快速定位bug】。默认情况下,GDB 不会在每次调试时自动显示行号。

编辑 Vim 的配置文件 ~/.vimrc(如果不存在则创建它),并添加以下行:set number

详细步骤如下:

打开配置文件 ~/.vimrc

nano ~/.vimrc

文件内容添加

set number

效果图如下:

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

然后运行以下命令使其生效:

source ~/.bashrc

这样使用vim 打开文件就会显示行数了

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


🌼2.2 准备测试程序

使用vim文本编辑器新建一个.c文件

vim tree3_01.c

输入测试程序:

#include <stdio.h>
#include <stdlib.h>
 
// 定义树节点
typedef struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;
 
// 创建一个新的树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode == NULL) {
        fprintf(stderr, "Memory allocation failed.\n");
        exit(EXIT_FAILURE);
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}
 
// 构建四层树
TreeNode* buildTree() {
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);
    root->left->left->left = createNode(8);
    root->left->left->right = createNode(9);
    return root;
}
 
// 递归遍历树并打印节点数据
void traverseTree(TreeNode* root) {
    if (root != NULL) {
        printf("%d ", root->data);
        traverseTree(root->left);
        traverseTree(root->right);
    }
}
 
int main() {
    // 构建树
    TreeNode* root = buildTree();
 
    // 打印树的结构
    printf("Tree Structure:\n");
    traverseTree(root);
    printf("\n");
 
    // 故意制造一个段错误,导致core dump
    int* ptr = NULL;
    *ptr = 10; // 这里将会产生段错误
 
    return 0;
}
 

gcc编译:

gcc -g -o tree3_01 tree3_01.c

此时ls查看会出现可执行文件tree3_01

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


🌼2.3 GDB调试基础

在使用GNU调试器(GDB)时,以下是一些常用的命令:

  • run (或 r): 启动程序并开始调试。
  • break (或 b): 在指定的位置设置断点。
  • continue (或 c): 继续执行程序直到下一个断点。
  • step (或 s): 单步执行程序,进入到函数中。
  • next (或 n): 单步执行程序,跳过函数内部的细节。
  • print (或 p): 打印变量的值。
  • backtrace (或 bt): 打印函数调用栈。
  • list (或 l): 显示源代码。
  • info (或 i): 显示调试信息,比如当前位置、变量类型等。
  • quit (或 q): 退出调试器。

🌞3. GDB调试四层二叉树

🌼3.1 测试程序分析

测试程序是一个简单的打印四层二叉树的c语言程序。

对于树TreeNode结构体和创建树节点createNode函数属于常规操作【不做分析】。

程序中的buildTree函数构建了一颗四层二叉树,并使用traverseTree函数先序遍历打印二叉树的数据结构:1 2 4 8 9 5 3 6 7

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


🌼3.2 gdb分析

现在,启动 GDB 并加载程序:

gdb ./tree3_01

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

进入 GDB,可以执行下列步骤来逐步调试:


🌻1. 设置断点

在程序出错的地方设置断点以停止程序执行,并检查变量。

break main

break mainb main等价。

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

这段输出是在 GDB 中设置断点的结果:

  • (gdb): 这是 GDB 的提示符,表示它正在等待用户输入命令。
  • break main: 这是用户输入的命令,表示在程序的 main 函数的起始处设置了一个断点。
  • Breakpoint 1 at 0x1398: 这一行显示了断点的信息。Breakpoint 1 表示这是第一个断点。0x1398 是断点的地址,表示断点被设置在程序代码的内存地址 0x1398 处。
  • file tree3_01.c, line 49: 这一行显示断点被设置位置在文件 tree3_01.c 的第 49 行处【还未执行】。

🌻2. 启动程序并执行到断点处

run

run和r等价

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

这个输出表明程序已经成功启动,并且停在了之前设置的断点处,也就是在 main 函数的第 49 行:

  • Starting program: /root/host/my_program/tree3_01: 这是 GDB 启动程序时的输出,指示程序已经开始执行。
  • [Thread debugging using libthread_db enabled]: 这个消息表明 GDB 正在使用 libthread_db 库进行线程调试,这是针对多线程程序的。
  • Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1": 这条消息表明 GDB 正在使用指定的线程库进行调试。

接着,输出显示了程序停在了 main 函数的第 49 行:

  • Breakpoint 1, main () at tree3_01.c:49: 这表示断点 1 已经触发,程序停在了 tree3_01.c 文件的第 49 行的 main 函数处。
  • 49            TreeNode* root = buildTree();:表示tree3_01.c 文件的第 49 行的代码【此时该行代码未执行】。

现在可以使用 GDB 的其他命令来查看程序状态,比如打印变量的值、单步执行等。


🌻3. 打印变量的值

可以使用 print 命令,后跟想要打印的变量名。

print root

print root和p root等价

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

这会打印 root 变量的值,即指向树根节点的指针。在这里,我们期望 root 指向一个已经创建好的二叉树的根节点。

打印 root 变量的结果显示为 (TreeNode *) 0x0,这意味着 root 指针当前指向了内存地址 0x0,即空指针【也证明了run之后到达断点的第49行代码未执行】。


🌻4. 单步执行 s 进入buildTree函数内部

step

step和s等价

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

step 命令进入 buildTree() 函数后,GDB 显示了当前所在的位置和执行的下一行代码。

  • buildTree () at tree3_01.c:26: 这行显示了当前所在的函数是buildTree以及函数参数为空。而 tree3_01.c:26 则表示这是在源文件 tree3_01.c 的第 26 行。
  • 当前程序执行到了 buildTree() 函数的开头,即第 26 行【未执行】

buildTree函数内部单步执行用到的还是n,除非需要进入buildTree函数里面的其他函数才用到s。


a. 第一层:根节点赋值

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

此时树结构如下:
【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


b. 第二层:节点赋值

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

 此时树结构如下:【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


c. 第三层:节点赋值

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

 此时树结构如下:

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


d. 第四层:节点赋值

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

 此时树结构如下:

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置


e. 退出buildTree函数

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

连续多次单步执行 n 即可


🌻5. 单步执行 s 进入traverseTree函数内部:跟踪输出结果

next

next和n等价。

跟踪输出的详细过程如下:

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

跟踪递归输出显示的输出结果为:1 2 4 8 9 5 3 6 7

这和预期输出的结果保持一致。


🌻6. 跟踪错误

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

单步执行 n 内容显示:

Program received signal SIGSEGV, Segmentation fault.
0x00005555555553d7 in main () at tree3_01.c:58
58        *ptr = 10; // 这里将会产生段错误

这个输出是 GDB 在程序运行时遇到段错误时所提供的信息:

  1. Program received signal SIGSEGV, Segmentation fault.

    这表示程序接收到了 SIGSEGV 信号,即段错误(Segmentation fault)信号。段错误通常发生在试图访问未分配给程序的内存或者访问已释放的内存时。

  2. 0x00005555555553d7 in main () at tree3_01.c:58

    这部分提供了造成段错误的代码位置信息。其中:

    • 0x00005555555553d7 是导致段错误的指令的地址。
    • main () 表示段错误发生在 main 函数内部。
    • tree3_01.c:58 指明了出错的源文件以及代码所在的行数,即在文件 tree3_01.c 的第 58 行。
  3. *58 ptr = 10; // 这里将会产生段错误

    这是在发生段错误的位置处的代码。具体地,这行代码尝试将值 10 写入指针 ptr 所指向的内存地址,但是 ptr 指向了一个空地址,因此导致了段错误。

现在我们需要进一步分析,为什么会发生段错误。可以使用以下几种方法:


a. 查看指针 ptr 的值

在发生段错误之前,可以查看指针 ptr 的值,看它是否为 NULL。

p ptr

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

这个输出表示指针 ptr 的值是 0x0,即空指针。

  • (int *) 表示这是一个指向整型数据的指针。
  • 0x0 是十六进制表示的地址,通常表示空指针。

因此,(int *) 0x0 表示指针 ptr 当前指向内存地址为 0x0,即空指针,那么后续执行的 *ptr = 10; 就会引发段错误。


b. 查看 ptr 所指向的地址

x ptr 查看指针 ptr 所指向的地址中的内容。

x ptr

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

输出表示 GDB 尝试查看指针 ptr 所指向的内存地址上的内容时出现了问题:

  • 0x0: 表示要查看的内存地址为 0x0
  • Cannot access memory at address 0x0 意味着 GDB 无法访问内存地址 0x0

说明:

  1. GDB 无法访问内存地址 0x0 是因为这个地址通常被操作系统保留为无效地址,用来表示空指针或者未分配的内存。因此,当 GDB 尝试访问地址 0x0 时,操作系统会阻止这种访问,因为这个地址不属于程序的有效内存范围。
  2. 通常情况下,访问空指针会导致程序出现段错误(Segmentation fault),这是因为试图在未分配的内存地址上读取或写入数据会导致操作系统干预并终止程序的执行,以保证系统的稳定性和安全性。

综合这些信息,由于 ptr 是空指针,即其指向的内存地址为 0x0,会导致错误。


c. 回溯调用堆栈

可以使用 backtrace (或bt)命令来查看调用堆栈,确定是从哪个函数调用了 main 函数并传递了一个空指针。

bt

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

输出表示了当前的函数调用堆栈情况,其中:

  • #0:表示当前所在的调用堆栈帧的索引,从 0 开始计数。
  • 0x00005555555553d7 in main () at tree3_01.c:58:说明当前位于 main 函数内,位于文件 tree3_01.c 的第 58 行。

输出表明程序在 main 函数的第 58 行出现了段错误(Segmentation fault),导致程序终止。


d. 查看核心转储文件

如果程序产生了核心转储文件,可以使用 GDB 打开它并查看导致段错误的堆栈跟踪信息。

gdb program core

  • program是可执行文件
  • core是coredump文件
gdb tree3_01 /tmp/dump/cores/core_tree3_01.50497_1712891407

其中gdb tree3_01 /tmp/dump/cores/core_tree3_01.50497_1712891407等价于
gdb ./tree3_01 /tmp/dump/cores/core_tree3_01.50497_1712891407

然后使用 backtrace(或bt) 命令来查看堆栈跟踪信息。

bt

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

这是 bt 命令的输出,表明当前程序执行时的函数调用栈:

  • #0: 表示当前栈帧的序号,这里是第一个栈帧。

  • 0x0000564e4be613d7: 这是当前正在执行的函数 main 的内存地址。

  • main (): 表示当前执行的函数是 main

  • at tree3_01.c:58: 表示 main 函数位于 tree3_01.c 文件中,并且是在第 58 行开始的。这里的 tree3_01.c 是源代码文件名,而 58 则是指示了具体的行号。


🌞4. gdb技巧

【GDB调试技巧】提高gdb的调试效率-CSDN博客

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解,# gdb调试详解,GDB调试,Ubuntu环境,四层二叉树,数据结构,断点设置文章来源地址https://www.toymoban.com/news/detail-854361.html

到了这里,关于【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TCP/IP协议栈源代码分析:GDB调试环境搭建及源码分析

    Ubuntu 22.04 LTS Linux-5.4.34 busybox-1.36.0 2.1 安装相关工具 axel是一款多线程下载工具,用于下载Linux内核源代码及其他大文件;build-essential软件包里面包含了很多开发必要的软件工具,比如make、gcc等;QEMU是一种通用的开源计算机仿真器和虚拟器,为自己编译构建的Linux系统运行提供

    2024年02月03日
    浏览(47)
  • VSCode 默认在DEBUG CONSOLE调试无法输入输出 gdb调试 解决方案 及Windows上C/C++环境配置

            从零重新安装的VSCode,无设置和其他插件,Win10系统,MinGW g++及gdb在环境变量中,发现VSCode调试C/C++程序时永远启用DEBUG CONSOLE而不是集成终端TERMINAL:         TERMINAL中只有launch.json中提供的参数启动debug的只读内容,无法进行输入输出,而cout输出的内容在DEBU

    2024年03月20日
    浏览(32)
  • 使用gdb调试Python进程

    有时我们会想调试一个正在运行的Python进程,或者一个Python进程的coredump。例如现在遇到一个mod_wsgi的进程僵死了,不接受请求,想看看究竟是运行到哪行Python代码呢?这时就需要祭出gdb了。 主要是三步: 1)确保你的gdb版本=7 2)安装python-debuginfo包(如:python-debuginfo-2.6.6-2

    2024年02月12日
    浏览(25)
  • 调试工具_gdb使用教程

    目录 一. 环境介绍 二. gdb指令 1. 启动调试 2. 退出调试 3. 查看代码  4. 运行程序  5. 打断点 6. 查看断点 7.  删除断点 8.  逐过程调试 9. 逐语句调试 10.  查看变量 11. 常显示变量(监视) 12. 取消常显示变量 13. 运行到指定行 14. 执行完当前函数的剩余部分 15. 执行到下一个断点

    2024年02月15日
    浏览(42)
  • 程序调试利器——GDB使用指南

    GDB是GNU Debugger的简称,其作用是可以在程序运行时,检测程序正在做些什么。GDB程序自身是使用C和C++程序编写的,但可以支持除C和C++之外很多编程语言的调试。GDB原生支持调试的语言包含: •C •C++ •D •Go •Object-C •OpenCL C •Fortran •Pascal •Rust •Modula-2 •Ada 此外,通过

    2024年02月04日
    浏览(34)
  • 【Linux】gdb调试器的使用

    文章目录 一、gdb简介 二、调试前的准备 1、生成调试文件 2、启动 gdb  三、gdb 使用方法  1、查看源代码 2、设置 / 查看断点(多种方式设置断点) 方法一 方法二 方法三 3、run  4、删除断点、断点无效 5、逐过程调试(以函数为单位) 6、逐语句调试 7、查看调用链 8、查看变

    2024年02月02日
    浏览(38)
  • 【Linux】——调试器-gdb的使用

    序言: 本期,我将带领大家学习的关于linux下的 调试器gdb 的使用,废话不多说跟着我一起去看看吧!! 目录 前言 (一)背景介绍 1、debug模式和release模式 2、为什么Release不能调试但DeBug可以调试 3、初步见识 1️⃣readelf (二)调试代码 1、命名大全 2、具体演示 0️⃣行号显

    2024年02月07日
    浏览(29)
  • Linux 使用gdb调试C程序

    一、gdb的一些基础命令 l :显示代码 l n :跳转到当前代码页的第n行的代码 l filename.c :n :跳转到filename.c文件的第n行代码 b 行号 :加断点 info break :查看断点信息 delete 断点编号 :删除断点 r ,运行程序 n ,单步执行 c ,继续执行,遇到断点停止执行 p ,打印 s ,进入函数

    2024年02月13日
    浏览(28)
  • 【Linux】调试器:gdb 的基本使用

    gdb 全称 GNU symbolic debugger,是 Linux 下常用的程序调试器。 调试器的核心工作,主要是为了定位问题。废话不多说。 gdb 的安装 另外: gcc、g++ 默认形成的版本是 release,不是 debug 版本!所以想要在 Linux 下调试程序,需要在 Makefile 文件 中,添加 -g 选项 指定以 dubug 方式编译程

    2024年02月16日
    浏览(30)
  • 【Linux】Linux调试器-gdb使用

    程序的发布方式有两种,debug模式和release模式 Linux gcc/g++出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项 退出:  调试命令: list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。 list/l 函数名:列出某

    2024年02月21日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包