您现在的位置是:网站首页>技术百科技术百科

Linux 下 GDB 调试方法

小大寒2024-01-01[技术百科]博学多闻

Linux 下 GDB 调试方法 ‌GDB是GNU项目的调试器,可让你在程序执行时查看其内部运行情况,或在程序崩溃时了解其当时状态。GDB主要功能包括启动程序、设置条件停止程序、检查程序停止时的状态、修改程序以实验性修复错误。它支持本地、远程和模拟环境,并可在大多数UNIX、Windows和macOS系统上运行。

Linux 下 GDB 调试方法

GDB(GNU 调试器)是一个强大的调试工具,它可以帮助开发者在程序运行时分析问题。以下内容将结合 C 语言代码,详细讲解如何在 Linux 下使用 GDB 进行调试。

1. 安装 GDB

如果系统没有安装 GDB,可以使用以下命令进行安装:

sudo apt-get install gdb

2. 使用 GDB 调试 C 语言代码

首先,我们编写一个简单的 C 语言代码,使用 GDB 来调试。

示例代码:


#include <stdio.h>

void greet(char *name) {
printf("Hello, %s!\n", name);
}

int main() {
char *name = "World";
greet(name);
return 0;
}

以上代码定义了一个 greet 函数,用于打印欢迎信息。

3. 编译代码

为了使用 GDB 进行调试,我们需要在编译时加上调试符号。使用 -g 参数来生成调试信息:

gcc -g -o greet greet.c

该命令将生成一个名为 greet 的可执行文件,并包含调试信息。

4. 启动 GDB

要启动 GDB 调试,我们可以使用以下命令:

gdb ./greet

进入 GDB 后,您将看到类似于下面的提示:

(gdb) 

5. 设置断点

在 GDB 中,我们可以设置断点来暂停程序的执行并进行检查。假设我们想在 greet 函数的开始处设置一个断点,可以使用如下命令:

(gdb) break greet

此命令会在 greet 函数的第一行设置一个断点。

6. 运行程序

设置好断点后,使用 run 命令来启动程序:

(gdb) run

程序会在断点处暂停,这时我们可以检查程序的状态。

7. 查看变量值

当程序暂停时,我们可以使用 print 命令查看变量的值。例如,查看 name 变量的值:

(gdb) print name

这将显示 name 变量的当前值:

$1 = 0x5555555562c0 "World"

8. 单步执行

要逐行执行代码,可以使用 next 命令:

(gdb) next

这会执行当前行,并在下一行暂停。您还可以使用 step 命令进入函数调用:

(gdb) step

9. 查看调用栈

当程序在断点处暂停时,可以使用 backtrace 命令查看调用栈:

(gdb) backtrace

这将显示函数调用的层次结构:

#0  greet (name=0x5555555562c0 "World") at greet.c:5
#1  0x000055555555517d in main () at greet.c:10

10. 继续执行程序

如果想继续执行程序直到下一个断点,可以使用 continue 命令:

(gdb) continue

11. 退出 GDB

调试完成后,使用 quit 命令退出 GDB:

(gdb) quit

GDB 是一个强大的调试工具,支持多种调试功能,例如设置断点、查看变量、单步执行、查看调用栈等。通过结合实际的 C 语言代码,您可以在 Linux 环境中有效地调试您的程序。

上面是给GDB零基础的人看的,下面的才是正餐

一、多线程调试

多线程调试通常是最常见的问题之一。其实,关键的命令如下:

  • info thread: 显示当前进程中的线程。
  • thread <ID>: 切换到指定线程ID进行调试。
  • break file.c:100 thread all: 在file.c文件的第100行,为所有经过该行的线程设置断点。
  • set scheduler-locking off|on|step: 这也是最常被提问的命令。当你在使用step或continue命令调试当前线程时,其他线程仍会继续执行。通过这个命令,你可以控制是否锁定其他线程。
    • off: 不锁定任何线程,所有线程都执行(默认值)。
    • on: 只有当前调试的线程会继续执行。
    • step: 单步调试时,除非是next跳过一个函数,否则只有当前线程会执行。

二、调试宏

调试宏是一个常见的问题。在GDB中,我们无法直接打印宏定义,因为宏在编译前就已经展开了。然而,通过GCC的帮助,我们依然能够调试宏。

在GCC编译时加上-ggdb3选项,你就可以调试宏了。

此外,你还可以使用以下命令来调试宏:

  • info macro: 查看宏在哪些文件中被引用及其定义。
  • macro: 查看宏展开后的内容。

三、源文件

关于源文件的问题也非常常见。很多人经常会遇到找不到源文件的情况。此时,你可以检查以下几点:

  1. 编译时是否加上了-g选项以包含调试信息。
  2. 路径设置是否正确。可以使用GDB的directory命令设置源文件目录。

下面是一个调试/bin/ls的示例(在Ubuntu系统上):

$ apt-get source coreutils
$ sudo apt-get install coreutils-dbgsym
$ gdb /bin/ls
GNU gdb (GDB) 7.1-ubuntu
(gdb) list main
1192    ls.c: No such file or directory.
in ls.c
(gdb) directory ~/src/coreutils-7.4/src/
Source directories searched: /home/tom/src/coreutils-7.4:$cdir:$cwd
(gdb) list main
1192        }
1193    }
1194
1195    int
1196    main (int argc, char **argv)
1197    {
1198      int i;
1199      struct pending *thispend;
1200      int n_files;
1201

四、条件断点

条件断点的语法为:break [where] if [condition],这种断点非常有用,特别是在循环或递归中,或者当你需要监控某个变量时。请注意,这个条件检查是在GDB中的,每次经过断点时,GDB都会检查条件是否满足。

五、命令行参数

有时,我们需要为调试的程序传递命令行参数,很多人可能不知道如何设置。其实,有两种方法:

  1. 在gdb命令行中使用 --args 参数。
  2. 使用GDB中的 set args 命令设置。

六、GDB中的变量

在调试过程中,除了查看运行时变量外,我们还可以直接修改程序中的变量,这样有助于模拟一些特殊的情境,尤其是当遇到错误或需要跳过特定分支时。使用set命令,你可以修改程序中的变量。

另外,GDB也有类似于shell的变量,变量名前缀为$。比如,你可以通过下面的方式打印数组中的元素:

(gdb) set $i = 0

(gdb) p a[$i++]

...  # 然后继续按回车即可查看数组元素

这表明程序变量和GDB变量可以互相交互。

七、x命令

你可能习惯使用p命令来查看变量值。但是,当你不知道变量名时,可能会陷入困境,因为p命令需要提供变量名。此时,你可以使用x命令查看内存内容。在GDB中,输入“help x”可以查看更多帮助。

  • x/x: 以十六进制格式显示。
  • x/d: 以十进制格式显示。
  • x/c: 以字符形式显示。
  • x/i: 反汇编,通常你可以使用 x/10i $ip-20 来查看当前的汇编($ip是指令指针寄存器)。
  • x/s: 以字符串形式显示。

八、command命令

很多朋友问我如何实现自动化调试。这里我向大家介绍GDB的command命令,简单来说,它可以把一组GDB命令打包执行,有点像字处理软件中的“宏”功能。以下是一个示例:

(gdb) break func
Breakpoint 1 at 0x3475678: file test.c, line 12.
(gdb) command 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>print arg1
>print arg2
>print arg3
>end
(gdb)

当断点命中时,GDB会自动执行command中的三个命令,打印出func函数的三个参数值。

上面的GDB技巧应该足够你在绝大多数情况下使用了,如果你觉得不够用,请移步GDB官网继续深入。GDB官网

阅读完毕,很棒哦!

文章评论

站点信息

  • 网站地址:www.xiaodahan.com
  • 我的QQ: 3306916637