Home gdb学习
Post
Cancel

gdb学习

初步

怎么运行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      }

输入btwhere,打印函数的调用栈

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

使用qquit退出当前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

This post is licensed under CC BY 4.0 by the author.

【WIP】推理图优化方法小结

-