Linux gdb命令介绍
gdb是GNU Debugger的缩写,它是一个用来调试程序的工具,可以让你检查程序运行时的内部状态,设置断点,单步执行,修改变量值等,从而帮助你发现和修复程序的错误。gdb支持多种编程语言,如C,C++,Java,Fortran等,也可以调试多线程,多进程,远程程序等。
Linux gdb命令适用的Linux版本
gdb命令在大多数Linux发行版中都是默认安装的,你可以使用gdb --version
命令来查看你的系统中的gdb版本。如果你的系统中没有安装gdb,你可以使用以下命令来安装:
- 在基于Debian的系统中(如Ubuntu),使用
sudo apt-get install gdb
命令 - 在基于Red Hat的系统中(如CentOS,Fedora),使用
sudo yum install gdb
命令(CentOS 7及以下版本)或sudo dnf install gdb
命令(CentOS 8及以上版本) - 在基于Arch的系统中(如Manjaro),使用
sudo pacman -S gdb
命令
安装完成后,你可以使用gdb
命令来启动gdb调试器,或者使用gdb program
命令来调试一个可执行文件program。
Linux gdb命令的基本语法
gdb命令的基本语法如下:
gdb [options] [program] [core] [pid]
其中,options是一些可选的参数,用来控制gdb的行为,如-q
表示安静模式,不显示版权信息和警告信息,-tui
表示使用文本用户界面,-x file
表示从文件中执行gdb命令等。program是要调试的可执行文件的名称,如果没有指定,可以在gdb中使用file
命令来加载。core是一个core dump文件,用来分析程序崩溃时的状态,如果没有指定,可以在gdb中使用core
命令来加载。pid是一个进程的ID,用来附加到一个正在运行的进程上,如果没有指定,可以在gdb中使用attach
命令来附加。
Linux gdb命令的常用选项或参数说明
gdb命令有很多选项或参数,这里只列举一些常用的:
选项或参数 | 说明 |
---|---|
-q | 安静模式,不显示版权信息和警告信息 |
-tui | 使用文本用户界面,可以在终端中显示源代码和寄存器等信息 |
-x file | 从文件中执行gdb命令,file是一个包含gdb命令的文本文件 |
-ex command | 在启动gdb后执行一条gdb命令,command是一个gdb命令,可以使用多个-ex选项来执行多条命令 |
-args args | 将args作为要调试的程序的参数,args是一个或多个参数,用空格分隔 |
-p pid | 附加到一个正在运行的进程上,pid是一个进程的ID |
-c core | 使用一个core dump文件,core是一个core dump文件的名称 |
-s symbols | 使用一个符号表文件,symbols是一个符号表文件的名称,通常是一个.o文件 |
-d directory | 将directory添加到源代码搜索路径中,directory是一个目录的名称,可以使用多个-d选项来添加多个目录 |
-n | 不读取任何初始化文件,如~/.gdbinit |
-h | 显示帮助信息 |
Linux gdb命令的实例
实例1:启动gdb并加载一个可执行文件
如果你有一个可执行文件,比如hello,你可以使用以下命令来启动gdb并加载该文件:
gdb hello
这样,你就可以在gdb中使用各种命令来调试hello程序了。
实例2:在gdb中运行一个程序
如果你已经在gdb中加载了一个可执行文件,比如hello,你可以使用以下命令来运行该程序:
(gdb) run
这样,你就可以看到程序的输出,如果程序正常结束,你会看到类似这样的信息:
[Inferior 1 (process 1234) exited normally]
如果程序遇到错误,你会看到类似这样的信息:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005f4 in main () at hello.c:10
10 *p = 0;
这表示程序在第10行发生了段错误,你可以使用backtrace
命令来查看函数调用栈,或者使用print
命令来查看变量的值等。
实例3:在gdb中设置断点
如果你想在程序运行到某个位置时暂停,你可以使用break
命令来设置断点,断点可以是一个函数名,一个源代码文件名和行号,一个地址等。比如,你可以使用以下命令来设置断点:
(gdb) break main
Breakpoint 1 at 0x4005ed: file hello.c, line 6.
这表示在main函数的第6行设置了一个断点,当程序运行到这里时,会停下来,你可以使用continue
命令来继续运行,或者使用delete
命令来删除断点等。
实例4:在gdb中单步执行
如果你想逐行执行程序,你可以使用next
命令或step
命令,区别在于,next
命令会将函数调用作为一条语句执行,而step
命令会进入函数内部执行。比如,你可以使用以下命令来单步执行:
(gdb) next
7 int *p = NULL;
(gdb) step
8 foo();
(gdb) step
foo () at hello.c:3
3 printf("Hello, world!\n");
这表示先执行了第7行,然后执行了第8行,由于使用了step
命令,所以进入了foo函数内部,执行了第3行。
实例5:在gdb中修改变量的值
如果你想在调试过程中修改变量的值,你可以使用set
命令或print
命令,区别在于,set
命令只修改变量的值,而print
命令还会显示变量的值。比如,你可以使用以下命令来修改变量的值:
(gdb) print x
$1 = 10
(gdb) set x = 20
(gdb) print x
$2 = 20
(gdb) print x = 30
$3 = 30
(gdb) print x
$4 = 30
这表示先打印了变量x的值,然后使用set
命令将x的值改为20,再打印了x的值,然后使用print
命令将x的值改为30,并显示了x的值,再打印了x的值。
实例6:在gdb中查看寄存器的值
如果你想查看程序运行时的寄存器的值,你可以使用info registers
命令或print
命令,区别在于,info registers
命令会显示所有的寄存器的值,而print
命令只会显示一个寄存器的值。比如,你可以使用以下命令来查看寄存器的值:
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x0 0
rbp 0x0 0x0
rsp 0x7fffffffe1f0 0x7fffffffe1f0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x4005f4 0x4005f4 <main+7>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) print $rax
$1 = 0
这表示先显示了所有的寄存器的值,然后显示了rax寄存器的值,你可以使用$
符号来引用寄存器的名称。
实例7:在gdb中查看内存的内容
如果你想查看程序运行时的内存的内容,你可以使用x
命令,它的语法如下:
x/nfu address
其中,n是一个数字,表示要显示的内存单元的个数,f是一个格式字符,表示要显示的内存单元的格式,u是一个单位字符,表示要显示的内存单元的大小,address是一个内存地址,可以是一个变量名,一个寄存器名,一个表达式等。比如,你可以使用以下命令来查看内存的内容:
(gdb) x/4xb &x
0x7fffffffe1ec: 0x0a 0x00 0x00 0x00
(gdb) x/1dw $rsp
0x7fffffffe1f0: 0x0000000000000000
这表示先显示了变量x的地址开始的4个字节的内容,以十六进制和字节为单位,然后显示了rsp寄存器的值开始的一个双字的内容,以十进制和双字为单位。
实例8:在gdb中使用条件断点
如果你想在程序运行到满足某个条件的位置时暂停,你可以使用break
命令的if
子句来设置条件断点,条件可以是一个表达式,一个变量的值,一个寄存器的值等。比如,你可以使用以下命令来设置条件断点:
(gdb) break 10 if i == 5
Breakpoint 2 at 0x4005f7: file hello.c, line 10.
这表示在第10行设置了一个条件断点,当变量i的值等于5时,程序会停下来。你可以使用info breakpoints
命令来查看所有的断点信息,或者使用condition
命令来修改或删除断点的条件等。
实例9:在gdb中使用观察点
如果你想在程序运行时监视一个变量或一个表达式的值的变化,你可以使用watch
命令来设置观察点,当变量或表达式的值发生变化时,程序会停下来。比如,你可以使用以下命令来设置观察点:
(gdb) watch x
Hardware watchpoint 3: x
这表示设置了一个观察点,当变量x的值发生变化时,程序会停下来。你可以使用info watchpoints
命令来查看所有的观察点信息,或者使用delete
命令来删除观察点等。
实例10:在gdb中使用信号
如果你想在程序运行时发送或处理一个信号,你可以使用signal
命令或handle
命令,区别在于,signal
命令会向程序发送一个信号,而handle
命令会设置对一个信号的处理方式。比如,你可以使用以下命令来使用信号:
(gdb) signal SIGINT
Continuing with signal SIGINT.
Program received signal SIGINT, Interrupt.
0x00007ffff7aef9d0 in __GI___nanosleep (requested_time=requested_time@entry=0x7fffffffe1f0, remaining=remaining@entry=0x7fffffffe1f0) at ../sysdeps/unix/sysv/linux/nanosleep.c:28
28 ../sysdeps/unix/sysv/linux/nanosleep.c: No such file or directory.
(gdb) handle SIGINT nostop
Signal Stop Print Pass to program Description
SIGINT No Yes Yes Interrupt
(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7aef9d0 in __GI___nanosleep (requested_time=requested_time@entry=0x7fffffffe1f0, remaining=remaining@entry=0x7fffffffe1f0) at ../sysdeps/unix/sysv/linux/nanosleep.c:28
28 in ../sysdeps/unix/sysv/linux/nanosleep.c
这表示先向程序发送了一个SIGINT信号,程序收到信号后停下来,然后使用handle
命令将SIGINT信号的处理方式设置为不停止,继续运行,再次向程序发送了一个SIGINT信号,程序收到信号后不停止,继续运行。
Linux gdb命令的注意事项
- gdb命令需要在编译时使用
-g
选项来生成调试信息,否则无法显示源代码和变量等信息。 - gdb命令在调试多线程或多进程的程序时,需要使用一些特殊的命令,如
info threads
,thread
,info inferiors
,inferior
等,来切换或控制不同的线程或进程。 - gdb命令在调试远程程序时,需要使用
target
命令来连接到远程目标,远程目标可以是一个串口,一个网络接口,一个仿真器等,具体的连接方式取决于远程目标的协议和配置。 - gdb命令在调试动态库时,需要使用
set solib-search-path
命令来设置动态库的搜索路径,或者使用set sysroot
命令来设置系统根目录,否则无法加载动态库的符号表和源代码等信息。 - gdb命令在调试程序时,可能会遇到一些错误或警告信息,如
No symbol table is loaded. Use the "file" command.
,No source file named hello.c.
,No line 10 in the current file.
等,这些信息通常表示gdb无法找到相应的文件或符号,需要检查文件的路径和名称,或者重新编译程序等。 - 如果在调试过程中,出现
bash: gdb: command not found
的错误信息,表示系统中没有安装gdb,需要根据系统的类型和版本,使用相应的命令来安装gdb。
评论区