基于linux命令行的gdb总结
基本使用
首先使用gdb的前提是编译的时候加上-g参数。例如有一下代码
/* bugging.c */
#include <stdio.h>
int foo(int n)
{
int sum;
int i;
for (i=0; i<=n; i++)
{
sum = sum+i;
}
return sum;
}
int main(int argc, char** argv)
{
int result = 0;
int N = 100;
result = foo(N);
printf("1+2+3+...+%d= %d\n", N, result);
return 0;
}
首先编译文件,如果gdb没安装的自行sudo安装下
g++ bugging.c -g
1,敲击run
执行程序,结果如下,退出为quit
(gdb) run
Starting program: /home/cwl/Desktop/code/gdb/gdbtest/a.out
1+2+3+...+100= 26895
[Inferior 1 (process 6322) exited normally]
其他相关命令
命令 | 简写形式 | 说明 |
---|---|---|
list | l | 查看源码 |
backtrace | bt、where | 打印函数栈信息 |
next | n | 执行下一行 |
step | s | 一次执行一行,遇到函数会进入 |
finish | 运行到函数结束 | |
continue | c | 继续运行 |
break | b | 设置断点 |
info breakpoints | 显示断点信息 | |
delete | d | 删除断点 |
p | 打印表达式的值 | |
run | r | 启动程序 |
until | u | 执行到指定行 |
info | i | 显示信息 |
help | h | 帮助信息 |
在 gdb 命令行界面,输入 help command
可以查看命令的用法,command 是你想要查询的命令。
在 gdb 命令行界面可以执行外部的 Shell 命令:!shell 命令
例一,查看源代码
list 行号
list 文件名:行号
list 函数名
例二,断点调试
- 设置断点
break 行号,断点设置在该行开始处,注意:该行代码未被执行
break 文件名 : 行号,适用于有多个源文件的情况。
break 函数名,断点设置在该函数的开始处,断点所在行未被执行:
break 文件名 : 函数名,适用于有多个源文件的情况。
- 查看断点信息
info breakpoints 命令用于显示当前断点信息。
其中
---
Num 列代表断点编号,该编号可以作为 delete/enable/disable 等控制断点命令的参数
Type 列代表断点类型,一般为 breakpoint
Disp 列代表断点被命中后,该断点保留(keep)、删除(del)还是关闭(dis)
Enb 列代表该断点是 enable(y) 还是 disable(n)
Address 列代表该断点处虚拟内存的地址
What 列代表该断点在源文件中的信息
- 删除断点
delete Num,删除指定断点,断点编号可通过 info breakpoints 获得:
delete,不带任何参数,默认删除所有断点:
- 关闭和启用断点
disable 命令和 enable 命令分别用于关闭和启用断点:
disable 命令用于关闭断点,有些断点可能暂时不需要但又不想删除,便可以 disable 该断点。
enable 命令用于启用断点。
disable Num,关闭指定断点,断点编号可通过 info breakpoints 获得:
disable,不带任何参数,默认关闭所有断点。
enable Num,启用指定断点,断点编号可通过 info breakpoints 获得。
enable,不带任何参数,默认启用所有断点。
disable 和 enable 命令影响的是 info breakpoints 的 Enb 列,表示该断点是启用还是关闭
- 打印变量
调试的过程中需要观察变量或者表达式的值,所以先介绍两个基本的显示变量值的命令:
info locals
打印当前断点处所在函数的所有局部变量的值,不包括函数参数。
print 变量或表达式
打印表达式的值,可显示当前函数的变量的值、全局变量的值等
print/FMT
可以控制打印的格式,常见的有x(十六进制)、t(二进制)、c(显示为字符)等。
- 启动程序
run 命令用于启动待调试程序,并运行到断点处停下。
run
不带任何参数,启动待调试程序,不传递参数。
run 参数
有些程序需要跟参数,直接带上参数列表即可,会传递给 main 函数的 argc、argv 变量。
- 单步命令
next, step, finish, continue, until 用于控制整个调试过程中,程序执行的流程。
next
next 单步执行,函数调用当做一条指令,不会进入被调用函数内部
next N,表示单步执行N次
step
step 单步执行,会进入到函数调用内部
step N,表示单步执行N次
finish
执行程序到当前函数结束
continue
执行程序到下个断点
until
until N,执行程序到源代码的某一行
例三,查看函数栈
gdb bugging
> (gdb) break foo
> (gdb) info breakpoints
run
info proc mappings #查看待调试进程的内存分布情况
下面[STACK]就是进程栈空间了
process 12217
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x555555554000 0x555555555000 0x1000 0x0 /home/cwl/Desktop/code/gdb/gdbtest/a.out
0x555555754000 0x555555755000 0x1000 0x0 /home/cwl/Desktop/code/gdb/gdbtest/a.out
0x555555755000 0x555555756000 0x1000 0x1000 /home/cwl/Desktop/code/gdb/gdbtest/a.out
0x555555756000 0x555555777000 0x21000 0x0 [heap]
0x7ffff70f2000 0x7ffff72a3000 0x1b1000 0x0 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff72a3000 0x7ffff74a2000 0x1ff000 0x1b1000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff74a2000 0x7ffff74a6000 0x4000 0x1b0000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff74a6000 0x7ffff74a8000 0x2000 0x1b4000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff74a8000 0x7ffff74ac000 0x4000 0x0
0x7ffff74ac000 0x7ffff74c3000 0x17000 0x0 /lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff74c3000 0x7ffff76c2000 0x1ff000 0x17000 /lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff76c2000 0x7ffff76c3000 0x1000 0x16000 /lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff76c3000 0x7ffff76c4000 0x1000 0x17000 /lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff76c4000 0x7ffff7856000 0x192000 0x0 /lib/x86_64-linux-gnu/libm-2.27.so
0x7ffff7856000 0x7ffff7a55000 0x1ff000 0x192000 /lib/x86_64-linux-gnu/libm-2.27.so
0x7ffff7a55000 0x7ffff7a56000 0x1000 0x191000 /lib/x86_64-linux-gnu/libm-2.27.so
0x7ffff7a56000 0x7ffff7a57000 0x1000 0x192000 /lib/x86_64-linux-gnu/libm-2.27.so
0x7ffff7a57000 0x7ffff7bc9000 0x172000 0x0 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
0x7ffff7bc9000 0x7ffff7dc9000 0x200000 0x172000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
0x7ffff7dc9000 0x7ffff7dd3000 0xa000 0x172000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
0x7ffff7dd3000 0x7ffff7dd5000 0x2000 0x17c000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
---Type <return> to continue, or q <return> to quit---
0x7ffff7dd5000 0x7ffff7dd8000 0x3000 0x0
0x7ffff7dd8000 0x7ffff7dfd000 0x25000 0x0 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7fce000 0x7ffff7fd4000 0x6000 0x0
0x7ffff7ff7000 0x7ffff7ffa000 0x3000 0x0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x24000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffdc000 0x7ffffffff000 0x23000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
backtrace 查看函数调用栈的情况
backtrace、where、info stack
这三个命令都可以查看函数的调用情况
backtrace full、where full、info stack full
这三个命令查看函数调用情况的同时,打印所有局部变量的值
-
栈帧(stack frame)
#1 是 main 函数用到的栈空间,这一部分可以称之为 main 函数的 stack frame
#0 是 foo 函数用到的栈空间,同样可称之为 foo 函数的 stack frame,0 代表当前执行停在 foo 函数内
可以得到函数调用关系为,main 调用 foo
info frame Num 查看某个函数栈帧的详细信息
(gdb) info frame 0 # <=============== commond ==================
Stack frame at 0x7fffffffcbd0:
rip = 0x555555554680 in foo (bugging.c:13); saved rip = 0x5555555546b8
called by frame at 0x7fffffffcc00
source language c++.
Arglist at 0x7fffffffcbc0, args: n=100
Locals at 0x7fffffffcbc0, Previous frame's sp is 0x7fffffffcbd0
Saved registers:
rbp at 0x7fffffffcbc0, rip at 0x7fffffffcbc8
(gdb) info frame 1 # <=============== commond ==================
Stack frame at 0x7fffffffcc00:
rip = 0x5555555546b8 in main (bugging.c:24); saved rip = 0x7ffff7113a87
caller of frame at 0x7fffffffcbd0
source language c++.
Arglist at 0x7fffffffcbf0, args: argc=1, argv=0x7fffffffccd8
Locals at 0x7fffffffcbf0, Previous frame's sp is 0x7fffffffcc00
Saved registers:
rbp at 0x7fffffffcbf0, rip at 0x7fffffffcbf8