首先,在debug之前要对程序进行编译,可以用 gcc 进行编译。
检查是否安装 gcc:
rpm -qa | grep gcc
若没有gcc, 请先安装。
yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim
root@DTSEACLI409540:/ # gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
由于我的代码环境是 c++ 11, 所以用以下命令可以编译:
g++ -g -std=c++11 skip_list.cpp -o skip_list
若不是 c++ 11, 则不需要参数 “-std=c++11”。
检查 GDB 是否安装:
rpm -qa | grep gdb
如果你使用的是 centos 的话, 一般是自带 GDB 的安装包的。可以直接用 yum 安装。
yum -y install <>
gdb <executable c++ file>
(gdb) run //运行程序
(gdb) list <number> //列出该行代码前后十行
(gdb) list <function> //列出该函数前后十行
(gdb) list //不加参数,则打印上次list的后面十行
(gdb) quit //退出
例如:
(gdb) list 2
1 #include <iostream>
2 #include <vector>
3 #include <numeric>
4 #include <random>
5 #include <time.h>
6
7 using namespace std;
8
9 /*The structure of node in skiplist,
10 includes key, pointer and constructor.
(gdb) list main
290 }
291 }
292
293 //main function
294 int main()
295 {
296 SkipList l;
297 for (size_t i = 0; i < 50; i++)
298 {
299 l.insert(i);
(gdb)
300 }
301
302 l.printNode();
303
304 l.insert(20);
305 l.printNode();
306
307 l.find(3);
308
309 l.deleteNode(4);
(gdb) break <line number>
例如:
(gdb) break 299
Breakpoint 1 at 0x40188c: file skip_list.cpp, line 299.
(gdb) break <function name>
例如:
(gdb) break SkipList::printNode()
Breakpoint 2 at 0x401635: file skip_list.cpp, line 264.
(gdb) info breakpoints
例如:
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040188c in main() at skip_list.cpp:299
2 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
(gdb) disable <breakpoint num>
例如:
(gdb) disable 1
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep n 0x000000000040188c in main() at skip_list.cpp:299
2 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
(gdb) enable <breakpoint num>
例如:
(gdb) enable 1
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040188c in main() at skip_list.cpp:299
2 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
(gdb) delete <breakpoint num>
例如:
(gdb) delete 1
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
(gdb) delete
例如:
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) info breakpoints
Num Type Disp Enb Address What
3 breakpoint keep y 0x000000000040188c in main() at skip_list.cpp:299
4 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
(gdb) run
Starting program: /home/c_plus/skip_list
Breakpoint 3, main () at skip_list.cpp:299
299 l.insert(i);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64 libgcc-4.8.5-36.el7_6.2.x86_64 libstdc++-4.8.5-36.el7_6.2.x86_64
(gdb) debuginfo-install glibc-2.17-222.el7.x86_64 libgcc-4.8.5-36.el7_6.2.x86_64 libstdc++-4.8.5-36.el7_6.2.x86_64
有报错。退出GDB,安装 debuginfos。
debuginfo-install glibc-2.17-222.el7.x86_64 libgcc-4.8.5-36.el7_6.2.x86_64 libstdc++-4.8.5-36.el7_6.2.x86_64
安装需要几分钟。
调试命令:
run(简写c ): 其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。
continue (简写c):继续执行,到下一个断点处(或运行结束)
next:(简写n),单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。
step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
until+行号: 运行至某行,不仅仅用来跳出循环
finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
quit:简记为 q ,退出gdb
where/bt :当前运行的堆栈列表;
bt backtrace 显示当前调用堆栈
up/down 改变堆栈显示的深度
set args 参数:指定运行时的参数
show args:查看设置好的参数
info program: 来查看程序的是否在运行,进程号,被暂停的原因。
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000401635 in SkipList::printNode() at skip_list.cpp:264
2 breakpoint keep y 0x000000000040188c in main() at skip_list.cpp:299
(gdb) run
Starting program: /home/c_plus/skip_list
Breakpoint 2, main () at skip_list.cpp:299
299 l.insert(i);
(gdb) n
key: 0, randomLevel: 4
297 for (size_t i = 0; i < 50; i++)
(gdb) n
Breakpoint 2, main () at skip_list.cpp:299
299 l.insert(i);
(gdb) n
key: 1, randomLevel: 2
297 for (size_t i = 0; i < 50; i++)
(gdb) continue
Continuing.
key: 5, randomLevel: 1
Breakpoint 2, main () at skip_list.cpp:299
299 l.insert(i);
(gdb) continue
Continuing.
key: 6, randomLevel: 1
Breakpoint 2, main () at skip_list.cpp:299
299 l.insert(i);
(gdb) step
SkipList::insert (this=0x7fffffffe2f0, x=11) at skip_list.cpp:162
162 int x_level = randomLevel();
(gdb) step
SkipList::randomLevel (this=0x7fffffffe2f0) at skip_list.cpp:108
108 int random_level = 1;
(gdb) step
109 int seed = time(NULL);
(gdb) step
110 static default_random_engine e(seed);
(gdb) step
111 static uniform_int_distribution<int> u(0, 1);
当然,GDB可以用于更底层的一些信息的查看,例如查看当前调用堆栈 backtrace(bt), 查看线程信息 info threads (i t), 甚至寄存器信息 info registers (i r)。
这一块具体的使用我还了解的不是很清楚,希望之后有更加深入的理解了之后再来补充。
Breakpoint 1, SkipList::printNode (this=0x7fffffffe2f0) at skip_list.cpp:264
264 for (size_t i = 0; i < maxLevel; i++)
(gdb) backtrace
#0 SkipList::printNode (this=0x7fffffffe2f0) at skip_list.cpp:264
#1 0x00000000004018b8 in main () at skip_list.cpp:302
(gdb) info threads
Id Target Id Frame
* 1 process 12190 "skip_list" SkipList::printNode (this=0x7fffffffe2f0) at skip_list.cpp:264
(gdb) info registers
rax 0x7fffffffe2f0 140737488347888
rbx 0x0 0
rcx 0x0 0
rdx 0x607210 6320656
rsi 0x0 0
rdi 0x7fffffffe2f0 140737488347888
rbp 0x7fffffffe2e0 0x7fffffffe2e0
rsp 0x7fffffffe2a0 0x7fffffffe2a0
r8 0x0 0
r9 0x8 8
r10 0x3 3
r11 0x246 582
r12 0x400c30 4197424
r13 0x7fffffffe410 140737488348176
r14 0x0 0
r15 0x0 0
rip 0x401635 0x401635 <SkipList::printNode()+13>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
GDB 有一个简单的图形界面可供大家调试使用。
使用如下命令即可打开图形界面:
gdb --tui a.out
界面如图所示:
可以看到有上下两个窗口,一个窗口用来显示我们用来调试的程序,另外一个用于输入GDB命令。
Ctrl + X + A
在已经进入 GDB 环境后,还可以通过如下命令进入 TUI :
(gdb) wi
打印变量 print <>:
(gdb) p l
$2 = {head = 0x606010, minInt = -2147483648, maxInt = 2147483647, maxLevel = 6, tail = 0x606080}
监控变量 watch <>, info watch:
(gdb) watch l
Hardware watchpoint 2: l
(gdb) info watch
Num Type Disp Enb Address What
2 hw watchpoint keep y l
查看变量类型 whatis <>:
(gdb) whatis l
type = SkipList