gdb 快速上手(附带测试案例)

在终端使用 gdb 对程序进行调试比较复杂,本文旨在帮助小白快速上手 gdb ,所以只介绍了一些比较重要的命令!

案例代码在文末!

一、gdb 调试

1、编译源文件

gcc -g test.c -o test

2、启动程序

gdb ./test

  结果如下:

gdb 快速上手(附带测试案例)_第1张图片

说明:结果中出现:Reading symbols from ./test03... 即成功启动调试程序! 

 3、设置断点

  方式一:执行命令

b main           //在入口函数出设置一个断点

  方式二:执行命令

b .c文件路径:行数

//在test03.c文件的123行设置一个断点
b /root/sql_test/test03.c:123          

  结果如下:

gdb 快速上手(附带测试案例)_第2张图片

4、查看断点

  执行命令:

info b             //查看断点情况及断点对应编号

  结果如下:

5、删除断点

  执行命令:

//删除指定编号(Num)的断点
d num1 num2…          

//删除1号断点
d 1        

  结果如下:

6、进入调试

  执行命令:

r              //进入调试,并到达第一个断点

  结果如下:

gdb 快速上手(附带测试案例)_第3张图片

7、单步调试

  方式一:执行命令

n             //单步调试但不进入具体函数内部

  结果如下:

gdb 快速上手(附带测试案例)_第4张图片

  说明:调试语法糖------直接回车会执行上一步调试操作;

  方式二:执行命令

s              //单步调试且进入具体函数内部

  结果如下: 

gdb 快速上手(附带测试案例)_第5张图片

8、从一个断点跳到下一个断点

  执行命令:

c             //从一个断点跳到下一个断点

  结果如下: 

gdb 快速上手(附带测试案例)_第6张图片

9、监视变量

  执行命令:

watch 变量名             //用于监视某个变量,一旦变量发生变化就会立即停止

  结果如下:

gdb 快速上手(附带测试案例)_第7张图片

说明:监视某个变量前,尽量关闭所有断点。在使用GDB进行调试时,当你使用watch命令监视某个变量时,最好将断点关闭或删除。这是因为watch命令会在每次变量的值发生变化时触发断点,以便你能够捕捉到变量的变化。如果你在设置了断点的情况下使用watch命令,那么每当变量的值发生变化时,GDB会首先触发断点,然后再触发watch命令。这可能会导致调试过程中出现不必要的中断,使得调试变得困难。因此,为了更好地使用watch命令,建议在使用它之前关闭或删除断点。

10、查看变量

  执行命令:

p 变量名             //查看变量的值

  结果如下:

gdb 快速上手(附带测试案例)_第8张图片

说明:通过上图可知,在查看变量i的值之前,设置了两个断点,分别为示例代码的第124、141行,第一个 p i 查看的是代码中全局变量i的定义值,第二个 p i 查看的是执行了第141行代码后i的值。 

11、查看源代码

  执行命令:

layout src             //弹出源码框且光标停留在第一个断点处,特别说明:快捷键Ctrl+X+A同样可以打开/关闭代码框

  结果如下:

gdb 快速上手(附带测试案例)_第9张图片

说明:此时如果使用键盘上下翻滚键或者鼠标是无法将代码中的光标移至下一行的。正确做法:在命令行输入:n,即可将光标移至下一行,并通过语法糖(回车键)继续执行命令n。    

  结果如下: 

gdb 快速上手(附带测试案例)_第10张图片

12、查看汇编代码

  执行命令:

layout asm            //打开汇编意义上的代码且光标停留在第一个断点处,特别说明:快捷键Ctrl+X+A同样可以打开/关闭代码框

  结果如下:

gdb 快速上手(附带测试案例)_第11张图片

说明:此时如果使用键盘上下翻滚键或者鼠标是无法将代码中的光标移至下一行的。正确做法:在命令行输入:si,即可将光标移至下一行,并通过语法糖(回车键)继续执行命令si。

  结果如下:
gdb 快速上手(附带测试案例)_第12张图片

13、从入口函数mian执行到断点,中间经历的函数

  执行命令:

bt            //从入口函数mian执行到断点,中间经历的函数(逆序看经历的函数)

  结果如下:

gdb 快速上手(附带测试案例)_第13张图片

14、查看寄存器

  执行命令:

info r             //查看寄存器的值

  结果如下:

gdb 快速上手(附带测试案例)_第14张图片

 15、结束当前程序

  执行命令:

k             //结束当前程序,但不会结束调试

  结果如下:

gdb 快速上手(附带测试案例)_第15张图片

16、退出调试

  执行命令:

quit         //退出调试

  结果如下:

gdb 快速上手(附带测试案例)_第16张图片

 二、测试代码

#include 
#include 
#include 

// AST 节点类型枚举
typedef enum {
    NODE_SELECT_STATEMENT,
    NODE_SELECT_CLAUSE,
    NODE_COLUMN,
    NODE_FROM_CLAUSE,
    NODE_TABLE,
    NODE_WHERE_CLAUSE,
    NODE_BINARY_EXPRESSION,
    NODE_INTEGER_LITERAL,
    NODE_STRING_LITERAL
} NodeType;

// AST 节点结构体
typedef struct Node {
    NodeType type;
    union {
        struct Node* left;
        char* value;
        int intValue;
    };
    struct Node* right;
} Node;

// 创建 AST 节点
Node* createNode(NodeType type) {
    Node* node = malloc(sizeof(Node));
    node->type = type;
    node->left = NULL;
    node->right = NULL;
    return node;
}

// 创建列节点
Node* createColumnNode(char* columnName) {
    Node* node = createNode(NODE_COLUMN);
    node->value = strdup(columnName);
    return node;
}

// 创建表节点
Node* createTableNode(char* tableName) {
    Node* node = createNode(NODE_TABLE);
    node->value = strdup(tableName);
    return node;
}

// 创建整数字面量节点
Node* createIntegerLiteralNode(int value) {
    Node* node = createNode(NODE_INTEGER_LITERAL);
    node->intValue = value;
    return node;
}

// 创建字符串字面量节点
Node* createStringLiteralNode(char* value) {
    Node* node = createNode(NODE_STRING_LITERAL);
    node->value = strdup(value);
    return node;
}

//定义全局变量
int i = 1;

// 打印 AST
void printAST(Node* node, int indent) {
    if (node == NULL) {
        return;
    }

    for (int i = 0; i < indent; i++) {
        printf("  ");
    }

    switch (node->type) {
        case NODE_SELECT_STATEMENT:
            printf("SelectStatement\n");
            printAST(node->left, indent + 1);
            printAST(node->right, indent + 1);
            break;
        case NODE_SELECT_CLAUSE:
            printf("SelectClause\n");
            printAST(node->left, indent + 2);
            printAST(node->right, indent + 2);
            break;
        case NODE_COLUMN:
            printf("Column(%s)\n", node->value);
            break;
        case NODE_FROM_CLAUSE:
            printf("FromClause\n");
            printAST(node->left, indent + 2);
            break;
        case NODE_TABLE:
            printf("Table(%s)\n", node->value);
            break;
        case NODE_WHERE_CLAUSE:
            printf("WhereClause\n");
            printAST(node->left, indent + 2);
            printAST(node->right, indent + 2);
            break;
        case NODE_BINARY_EXPRESSION:
            printf("BinaryExpression(=)\n");
            printAST(node->left, indent + 3);
            printAST(node->right, indent + 3);
            break;
        case NODE_INTEGER_LITERAL:
            printf("IntegerLiteral(%d)\n", node->intValue);
            break;
        case NODE_STRING_LITERAL:
            printf("StringLiteral('%s')\n", node->value);
            break;
        default:
            printf("Unknown node type\n");
            break;
    }
}

int main() {
    // 构建示例 AST
    Node* ast = createNode(NODE_SELECT_STATEMENT);

    ast->left = createNode(NODE_SELECT_CLAUSE);
    ast->left->left = createColumnNode("column1");
    ast->left->right = createColumnNode("column2");

    ast->right = createNode(NODE_FROM_CLAUSE);
    ast->right->left = createTableNode("table");

    ast->right->right = createNode(NODE_WHERE_CLAUSE);
    ast->right->right->left = createNode(NODE_BINARY_EXPRESSION);
    ast->right->right->left->left = createColumnNode("column1");
    ast->right->right->left->right = createIntegerLiteralNode(1);
    ast->right->right->right = createNode(NODE_BINARY_EXPRESSION);
    ast->right->right->right->left = createColumnNode("column2");
    ast->right->right->right->right = createStringLiteralNode("value");

    i = 4;

    // 打印 AST
    printAST(ast, 0);

    // 释放内存
    // ...

    return 0;
}

你可能感兴趣的:(Linux,操作系统,CentOS,linux,运维,服务器,gdb)