初步
怎么运行gdb?
写一个有bug的程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// crash.cpp
#include <iostream>
using namespace std;
int divint(int, int);
int main()
{
x = 3; y = 0;
cout << divint(x, y);
return 0;
}
int divint(int a, int b)
{
return a / b;
}
使用g++
编译程序,运行出错
1
2
3
4
5
g++ crash.cpp -o crash
./crash
# Floating point exception (core dumped)
增加-g
选项,编译debug版本
1
g++ -g crash.cpp -o crash_gdb
启动gdb
1
gdb crash_gdb
显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GNU gdb (Ubuntu 8.2-0ubuntu1~16.04.1) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from crash...done.
(gdb)
最后两行显示
1
2
Reading symbols from crash...done.
(gdb)
表示载入debug版本的可执行程序成功,并进入gdb交互状态。
输入r
在debug环境中运行程序:
1
2
3
4
5
6
(gdb) r
Starting program: crash
Program received signal SIGFPE, Arithmetic exception.
0x00000000004006e1 in divint (a=3, b=0) at demo.cpp:18
18 return a / b;
输入l
(代表list
),打印异常处附近的代码。
1
2
3
4
5
6
7
8
(gdb) l
13 return 0;
14 }
15
16 int divint(int a, int b)
17 {
18 return a / b;
19 }
输入bt
或where
,打印函数的调用栈
1
2
3
(gdb) bt
#0 0x00000000004006e1 in divint (a=3, b=0) at demo.cpp:18
#1 0x00000000004006c0 in main () at demo.cpp:11
进阶
打断点
写一个demo程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// for_breakpoint.cpp
#include <iostream>
using namespace std;
void my_func1(int i) {
std::cout << "Now in func1, i = " << i << "\n";
}
void my_func2(int i) {
std::cout << "Now in func2, i = " << i << "\n";
}
int main() {
for (int i = 0; i < 3; ++i) {
my_func1(i);
my_func2(i);
}
return 0;
}
加上-g
参数编译,并运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
g++ -g for_breakpoint.cpp -o bt_demo
gdb ./demo2
GNU gdb (Ubuntu 8.2-0ubuntu1~16.04.1) 8.2
...
Reading symbols from bt_demo...done.
(gdb) r
Starting program: /home/zyf301/NewDisk/zg/learn_gym/learn_gdb/bt_demo
Now in func1, i = 0
Now in func2, i = 0
Now in func1, i = 1
Now in func2, i = 1
Now in func1, i = 2
Now in func2, i = 2
正常执行。
在第14行增加断点(my_func1调用的位置)
1
2
(gdb) b 14
Breakpoint 1 at 0x40076b: file for_breakpoint.cpp, line 14.
再执行一下看看,程序在断点处停下来了
1
2
3
4
5
(gdb) r
Starting program: bt_demo
Breakpoint 1, main () at for_breakpoint.cpp:14
14 my_func1(i);
打印一下i
的值
1
2
(gdb) p i
$1 = 0
接下来步进。步进有两种模式,一种是不进入内层函数,对应n
(next)执行;一种是进入内层函数,对应s
(step)执行。分别试试
1
2
3
4
5
6
7
8
9
10
(gdb) n
Now in func1, i = 0
15 my_func2(i);
(gdb) n
Now in func2, i = 0
13 for (int i = 0; i < 3; ++i) {
(gdb) n
Breakpoint 1, main () at for_breakpoint.cpp:14
14 my_func1(i);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) s
my_func1 (i=1) at for_breakpoint.cpp:5
5 std::cout << "Now in func1, i = " << i << "\n";
(gdb) s
Now in func1, i = 1
6 }
(gdb) s
main () at for_breakpoint.cpp:15
15 my_func2(i);
(gdb) s
my_func2 (i=1) at for_breakpoint.cpp:9
9 std::cout << "Now in func2, i = " << i << "\n";
(gdb) s
Now in func2, i = 1
10 }
(gdb) s
main () at for_breakpoint.cpp:13
13 for (int i = 0; i < 3; ++i) {
(gdb) s
Breakpoint 1, main () at for_breakpoint.cpp:14
14 my_func1(i);
(gdb)
可以发现,使用s,相比于使用n,在步进的时候进入了my_func1和my_func2的内部。
或者直接执行,直到下一个断点/异常/执行结束:c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) c
Continuing.
Now in func1, i = 0
Now in func2, i = 0
Breakpoint 1, main () at for_breakpoint.cpp:14
14 my_func1(i);
(gdb) c
Continuing.
Now in func1, i = 1
Now in func2, i = 1
Breakpoint 1, main () at for_breakpoint.cpp:14
14 my_func1(i);
(gdb) c
Continuing.
Now in func1, i = 2
Now in func2, i = 2
[Inferior 1 (process 11840) exited normally]
显示当前所有断点:info break
1
2
3
4
5
6
(gdb) b 15
Breakpoint 2 at 0x400775: file for_breakpoint.cpp, line 15.
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040076b in main() at for_breakpoint.cpp:14
2 breakpoint keep y 0x0000000000400775 in main() at for_breakpoint.cpp:15
清除断点:d Num
1
2
3
4
(gdb) d 1
(gdb) info break
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000400775 in main() at for_breakpoint.cpp:15
清除所有断点:d
1
2
3
4
5
(gdb) d
Delete all breakpoints? (y or n) y
(gdb) info break
No breakpoints or watchpoints.
(gdb)
在指定文件的某一行打断点:b filepath:line
1
2
(gdb) b for_breakpoint.cpp:14
Breakpoint 3 at 0x40076b: file for_breakpoint.cpp, line 14.
打印
打印函数中变量i
的当前值
1
2
(gdb) p i
$1 = 0
打印某一个函数的执行结果
1
2
3
(gdb) p my_func1(5)
Now in func1, i = 5
$2 = void
退出gdb
使用q
或quit
退出当前gdb
1
2
3
4
5
6
(gdb) q
A debugging session is active.
Inferior 1 [process 11934] will be killed.
Quit anyway? (y or n) y
进阶使用
根据pid attach程序
1
(gdb) attach <pid>
参考
https://zhuanlan.zhihu.com/p/504186531
https://www.tutorialspoint.com/gnu_debugger/gdb_commands.htm