一、GDB应用
在前面讲过了很多GDB的命令和相关的调试小程序,但是好多人发现在学习完成这些命令后,不知道如何应用到实际的工程中去,这里就使用一个实际的工程进行一下调试。为了合乎规范,使用的并不是完整和全面的公司的代码,而在上面进行了缩减了的代码,但整体的架构几乎一致,完全可以和实际工程比拟。
二、基本情况介绍
1、服务器软硬件
服务器使用的是2*64=128核心的DELL服务器,内存128G,SSH远端登陆。CentOS7的操作系统。
2、编译工具
使用cmake3.3 ,gcc-g++ 4.8.5
3、调试工具
使用gdb-7.6调试。
4、代码结构
三、启动调试前的准备
这个程序是一个网络服务端的高并发的简化,为了简单并没有把epoll弄进来,而是通过两个线程模拟发送和接收,并送到逻辑处理队列进行整包控制来进行。
先看一下崩溃转储的设置:
[root@server1 build]# ulimit -c
10240
如果为0的话,请使用:
ulimit -c N 设置大小,N单位为k。
上面的设置只适合当前终端,退出后变为0
永久修改:
/etc/profile:全局
.bash_profile:当前用户
ulimit -c N
source .bash_profile
设置这个参数的目的是为了在调试时如果进程崩溃,可以产生转储文件Core。
写一个简单的CMakeLists.txt,然后放到当前的根目录下,创建一个文件夹build,然后进入到这个文件夹:
cd build
cmake ..
make
就会在此目录下生成可执行文件,以后所有的操作都是以这个文件夹为基本目录操作的,请知悉。
四、启动进程
然后启动进程:
[root@server1 build]# ls
CMakeCache.txt CMakeFiles cmake_install.cmake core.70236 gdbTest Makefile
[root@server1 build]# nohup ./gdbTest >1.log 2>&1 &
[1]4144
这个4144是启动的进程ID,和ps -ef|grep gdbTest得到的ID一样。如果不是使用上面的方法启动进程,可以使用这个命令来得到当前的进程ID,效果一样。然后使用tail命令来查看程序的正常输出。
[root@server1 build]# ls
1.log CMakeCache.txt CMakeFiles cmake_install.cmake core.70236 gdbTest Makefile
[root@server1 build]# tail -f -n 20 1.log
dataparse tmp netData:100
dataparse tmp netData:100
dataparse tmp netData:100
dataparse tmp netData:100
dataparse tmp comData:60
dataparse tmp comData:60
这里将使用动态加载已运行的进程的方式来调试:
[root@server1 build]# ls
1.log CMakeCache.txt CMakeFiles cmake_install.cmake core.70236 gdbTest Makefile
[root@server1 build]# gdb attach 4144 (注意:调试完成要detach)
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
attach: No such file or directory.
Attaching to process 4144
Reading symbols from /root/projects/gdbTest/build/gdbTest...done.
Reading symbols from /lib64/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libstdc++.so.6
Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libgcc_s.so.1
Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done.
[New LWP 4146]
[New LWP 4145]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007f18884b0017 in pthread_join () from /lib64/libpthread.so.0
Missing separate debuginfos, use: debuginfo-install glibc-2.17-317.el7.x86_64 libgcc-4.8.5-44.el7.x86_64 libstdc++-4.8.5-44.el7.x86_64
(gdb) stop
(gdb)
此处需要root权限,如果没有则会报权限受限,sudo或者其它可以取得root方式均可。启动后使用stop命令停止当前进程 。
执行一下list命令,查看当前可以看到的代码,发现并没导入的代码
(gdb) l
1 #include <cstdio>
2 #include "ModuleNet.h"
3
4 int main()
5 {
6 ModuleNet mn;
7 std::string ip = "192.168.0.2";
8 mn.Init(0, ip);
9 mn.Start(0);
10 getchar();
(gdb)
如果想查看当前路径,需要加上shell表示是执行的shell命令:
(gdb) shell ls
1.log CMakeCache.txt CMakeFiles cmake_install.cmake core.70236 gdbTest Makefile
(gdb)
如果想调试哪个路径下的文件,可以使用下面的命令:
(gdb) dir ../inet/
Source directories searched: /root/projects/gdbTest/build/../inet:$cdir:$cwd
(gdb)
导入想要调试的文件路径。
(gdb) l Server.cpp:18
13 Server::~Server()
14 {
15 this->id.join();
16 this->idwork.join();
17 }
18 int Server::InitServer(int count, std::string & ip)
19 {
20 if (nullptr == this->pData_)
21 {
22 this->pData_ = std::make_shared<data::IData>();
(gdb)
如果没有前面的 dir命令,则无法进行查看。
(gdb) show dir
Source directories searched: /root/projects/gdbTest/build/../inet:$cdir:$cwd
(gdb)
使用:号可以连接导入多个路径
(gdb) dir ../inet/:../data/netdata/:../data/comdata/
Source directories searched:
/root/projects/gdbTest/build/../inet:/root/projects/gdbTest/build/../data/netdata:/root/projects/gdbTest/build/../data/comdata:$cdir:$cwd
(gdb)
这样就可以在关心的文件中进行各种操作如下断点。假使不希望再使用当前的导入路径的文件可以直接使用dir命令,则当前所有的导入都会清除,只留下默认部分。
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
准备好上述的基本的环境后,可以下断点了。断点设置方法在前面的GDB应用中介绍过,下面使用其中的方法来进行断点操作。
如果想在函数中下断点,但又不太清楚的记得函数名称可以用名空间名称-类名等依次向下点击两次TAB键,则会自动出现相关的符号:
(gdb) b inet::Server
Server
Server::InitServer(int, std::string&)
Server::RunWork()
Server::RunWork()::{lambda()#1}&& std::forward<inet::Server::RunWork()::{lambda()#1}>(std::remove_reference<inet::Server::RunWork()::{lambda()#1}>::type&)
Server::RunWork()::{lambda()#1}::operator()() const
Server::Server()
Server::Start()
Server::Start()::{lambda()#1}&& std::forward<inet::Server::Start()::{lambda()#1}>(std::remove_reference<inet::Server::Start()::{lambda()#1}>::type&)
Server::Start()::{lambda()#1}::operator()() const
Server::Stop()
Server::~Server()
如果进一步指定一个函数的开头字母:
(gdb) b inet::Server::S
Server()
Start()
Start()::{lambda()#1}&& std::forward<inet::Server::Start()::{lambda()#1}>(std::remove_reference<inet::Server::Start()::{lambda()#1}>::type&)
Start()::{lambda()#1}::operator()() const
Stop()
当然,还是习惯于用行号来下断点:
(gdb) l Server.cpp:33
28 }
29 int Server::Start()
30 {
31 int num = 0;
32 this->id = std::thread([&]() {
33 //
34 while (!quit_)
35 {
36 int len = strlen(barr[num % 10]);
37 memmove(dbuf_, barr[num%10], len);
(gdb) b Server.cpp:36
Breakpoint 1 at 0x417e3e: file /root/projects/gdbTest/inet/Server.cpp, line 36.
(gdb)
可以对断点进行查看和删除:
(gdb) info b
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000417e3e in inet::Server::__lambda0::operator()() const at /root/projects/gdbTest/inet/Server.cpp:36
(gdb) delete 2
(gdb) info b
No breakpoints or watchpoints.
(gdb) b Server.cpp:36
Breakpoint 3 at 0x417e3e: file /root/projects/gdbTest/inet/Server.cpp, line 36.
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb)
还可以对断点进行禁用、启用和忽略:
(gdb) b inet::Server::Start
Breakpoint 4 at 0x417f64: file /root/projects/gdbTest/inet/Server.cpp, line 31.
(gdb) clear
No source file specified.
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep y 0x0000000000417f64 in inet::Server::Start() at /root/projects/gdbTest/inet/Server.cpp:31
(gdb) disable 4
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep n 0x0000000000417f64 in inet::Server::Start() at /root/projects/gdbTest/inet/Server.cpp:31
(gdb) enable
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep y 0x0000000000417f64 in inet::Server::Start() at /root/projects/gdbTest/inet/Server.cpp:31
(gdb) in
inferior info init-if-undefined interpreter-exec interrupt
(gdb) ignore 4
Second argument (specified ignore-count) is missing.
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep y 0x0000000000417f64 in inet::Server::Start() at /root/projects/gdbTest/inet/Server.cpp:31
(gdb)
同样,使用clear也可以删除断点,clear Server.cpp:31 就会把上面的断点4给删除。需要注意的是,clear这个命令是基于行命令删除的(也就是说基于行号)。
查看一下当前的线程:
(gdb) info thread
Id Target Id Frame
3 Thread 0x7f18880d8700 (LWP 4145) "gdbTest" 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
2 Thread 0x7f18878d7700 (LWP 4146) "gdbTest" 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
* 1 Thread 0x7f18890fa740 (LWP 4144) "gdbTest" 0x00007f18884b0017 in pthread_join () from /lib64/libpthread.so.0
查看当前所有线程的堆栈信息:
(gdb) thread apply all bt
Thread 3 (Thread 0x7f18880d8700 (LWP 4145)):
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
#2 0x0000000000417f3b in inet::Server::__lambda0::operator() (__closure=0xc913c0) at /root/projects/gdbTest/inet/Server.cpp:42
#3 0x0000000000419e96 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1732
#4 0x0000000000419d45 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::operator()(void) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1720
#5 0x0000000000419c76 in std::thread::_Impl<std::_Bind_simple<inet::Server::Start()::__lambda0()> >::_M_run(void) (this=0xc913a8) at /usr/include/c++/4.8.2/thread:115
#6 0x00007f1888c90330 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f18884aeea5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f18881d796d in clone () from /lib64/libc.so.6
Thread 2 (Thread 0x7f18878d7700 (LWP 4146)):
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
#2 0x0000000000418122 in inet::Server::__lambda1::operator() (__closure=0xc91660) at /root/projects/gdbTest/inet/Server.cpp:77
#3 0x0000000000419e38 in std::_Bind_simple<inet::Server::RunWork()::__lambda1()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc91660) at /usr/include/c++/4.8.2/functional:1732
#4 0x0000000000419d27 in std::_Bind_simple<inet::Server::RunWork()::__lambda1()>::operator()(void) (this=0xc91660) at /usr/include/c++/4.8.2/functional:1720
#5 0x0000000000419c58 in std::thread::_Impl<std::_Bind_simple<inet::Server::RunWork()::__lambda1()> >::_M_run(void) (this=0xc91648) at /usr/include/c++/4.8.2/thread:115
#6 0x00007f1888c90330 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f18884aeea5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f18881d796d in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x7f18890fa740 (LWP 4144)):
#0 0x00007f18884b0017 in pthread_join () from /lib64/libpthread.so.0
#1 0x00007f1888c900f7 in std::thread::join() () from /lib64/libstdc++.so.6
#2 0x0000000000417d36 in inet::Server::~Server (this=0xc8f058, __in_chrg=<optimized out>) at /root/projects/gdbTest/inet/Server.cpp:15
#3 0x000000000041c9a4 in __gnu_cxx::new_allocator<inet::Server>::destroy<inet::Server> (this=0xc8f050, __p=0xc8f058) at /usr/include/c++/4.8.2/ext/new_allocator.h:124
#4 0x000000000041c961 in std::allocator_traits<std::allocator<inet::Server> >::_S_destroy<inet::Server> (__a=..., __p=0xc8f058) at /usr/include/c++/4.8.2/bits/alloc_traits.h:281
#5 0x000000000041c917 in std::allocator_traits<std::allocator<inet::Server> >::destroy<inet::Server> (__a=..., __p=0xc8f058) at /usr/include/c++/4.8.2/bits/alloc_traits.h:405
#6 0x000000000041c85f in std::_Sp_counted_ptr_inplace<inet::Server, std::allocator<inet::Server>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0xc8f040)
at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:407
#7 0x0000000000415aea in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0xc8f040) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:144
#8 0x0000000000415639 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x7ffc47678008, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:546
#9 0x000000000041bf24 in std::__shared_ptr<inet::Server, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0xaf7e47678000, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:781
#10 0x000000000041bf62 in std::shared_ptr<inet::Server>::~shared_ptr (this=0x7ffc47678000, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr.h:93
#11 0x000000000041be28 in ModuleNet::~ModuleNet (this=0x7ffc47678000, __in_chrg=<optimized out>) at /root/projects/gdbTest/ModuleNet.cpp:8
#12 0x000000000041bd11 in main () at /root/projects/gdbTest/main.cpp:12
进一步查看一下当前线程调试调度锁的情况,并通过设置参数进行锁定和放开:
(gdb) show scheduler-locking
Mode for locking scheduler during execution is "step".
(gdb) set scheduler-locking on
(gdb) show scheduler-locking
Mode for locking scheduler during execution is "on".
(gdb) set scheduler-locking off
(gdb) show scheduler-locking
Mode for locking scheduler during execution is "off".
通过这个命令,可以强制指定只调试某个线程,当初第一次用这个命令时,还忽视了,结果发现另外一个线程死活也进不了断点。初学者不要忘记不用了改回到初始状态。
查看一下当前线程的帧和相关堆栈:
(gdb) info frame
Stack level 0, frame at 0x7ffc47677ea0:
rip = 0x7f18884b0017 in pthread_join; saved rip 0x7f1888c900f7
called by frame at 0x7ffc47677eb0
Arglist at 0x7ffc47677e38, args:
Locals at 0x7ffc47677e38, Previous frame's sp is 0x7ffc47677ea0
Saved registers:
rbx at 0x7ffc47677e68, rbp at 0x7ffc47677e70, r12 at 0x7ffc47677e78, r13 at 0x7ffc47677e80, r14 at 0x7ffc47677e88, r15 at 0x7ffc47677e90, rip at 0x7ffc47677e98
(gdb) bt
#0 0x00007f18884b0017 in pthread_join () from /lib64/libpthread.so.0
#1 0x00007f1888c900f7 in std::thread::join() () from /lib64/libstdc++.so.6
#2 0x0000000000417d36 in inet::Server::~Server (this=0xc8f058, __in_chrg=<optimized out>) at /root/projects/gdbTest/inet/Server.cpp:15
#3 0x000000000041c9a4 in __gnu_cxx::new_allocator<inet::Server>::destroy<inet::Server> (this=0xc8f050, __p=0xc8f058) at /usr/include/c++/4.8.2/ext/new_allocator.h:124
#4 0x000000000041c961 in std::allocator_traits<std::allocator<inet::Server> >::_S_destroy<inet::Server> (__a=..., __p=0xc8f058) at /usr/include/c++/4.8.2/bits/alloc_traits.h:281
#5 0x000000000041c917 in std::allocator_traits<std::allocator<inet::Server> >::destroy<inet::Server> (__a=..., __p=0xc8f058) at /usr/include/c++/4.8.2/bits/alloc_traits.h:405
#6 0x000000000041c85f in std::_Sp_counted_ptr_inplace<inet::Server, std::allocator<inet::Server>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0xc8f040)
at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:407
#7 0x0000000000415aea in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0xc8f040) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:144
#8 0x0000000000415639 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x7ffc47678008, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:546
#9 0x000000000041bf24 in std::__shared_ptr<inet::Server, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0xaf7e47678000, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:781
#10 0x000000000041bf62 in std::shared_ptr<inet::Server>::~shared_ptr (this=0x7ffc47678000, __in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/shared_ptr.h:93
#11 0x000000000041be28 in ModuleNet::~ModuleNet (this=0x7ffc47678000, __in_chrg=<optimized out>) at /root/projects/gdbTest/ModuleNet.cpp:8
#12 0x000000000041bd11 in main () at /root/projects/gdbTest/main.cpp:12
(gdb)
如果想进入某个线程并查看相关堆栈和具体的信息:
(gdb) thread 3
[Switching to thread 3 (Thread 0x7f18880d8700 (LWP 4145))]
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
(gdb) bt
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
#2 0x0000000000417f3b in inet::Server::__lambda0::operator() (__closure=0xc913c0) at /root/projects/gdbTest/inet/Server.cpp:42
#3 0x0000000000419e96 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1732
#4 0x0000000000419d45 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::operator()(void) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1720
#5 0x0000000000419c76 in std::thread::_Impl<std::_Bind_simple<inet::Server::Start()::__lambda0()> >::_M_run(void) (this=0xc913a8) at /usr/include/c++/4.8.2/thread:115
#6 0x00007f1888c90330 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f18884aeea5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f18881d796d in clone () from /lib64/libc.so.6
(gdb) bt
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
#2 0x0000000000417f3b in inet::Server::__lambda0::operator() (__closure=0xc913c0) at /root/projects/gdbTest/inet/Server.cpp:42
#3 0x0000000000419e96 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1732
#4 0x0000000000419d45 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::operator()(void) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1720
#5 0x0000000000419c76 in std::thread::_Impl<std::_Bind_simple<inet::Server::Start()::__lambda0()> >::_M_run(void) (this=0xc913a8) at /usr/include/c++/4.8.2/thread:115
#6 0x00007f1888c90330 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f18884aeea5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f18881d796d in clone () from /lib64/libc.so.6
(gdb) info frame
Stack level 0, frame at 0x7f18880d7c70:
rip = 0x7f188819e85d in nanosleep; saved rip 0x7f188819e6f4
called by frame at 0x7f18880d7e50
Arglist at 0x7f18880d7c58, args:
Locals at 0x7f18880d7c58, Previous frame's sp is 0x7f18880d7c70
Saved registers:
rip at 0x7f18880d7c68
(gdb) bt
#0 0x00007f188819e85d in nanosleep () from /lib64/libc.so.6
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
#2 0x0000000000417f3b in inet::Server::__lambda0::operator() (__closure=0xc913c0) at /root/projects/gdbTest/inet/Server.cpp:42
#3 0x0000000000419e96 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1732
#4 0x0000000000419d45 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::operator()(void) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1720
#5 0x0000000000419c76 in std::thread::_Impl<std::_Bind_simple<inet::Server::Start()::__lambda0()> >::_M_run(void) (this=0xc913a8) at /usr/include/c++/4.8.2/thread:115
#6 0x00007f1888c90330 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f18884aeea5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f18881d796d in clone () from /lib64/libc.so.6
栈帧可以自由的在范围内上下选择:
(gdb) up 1
#1 0x00007f188819e6f4 in sleep () from /lib64/libc.so.6
(gdb) up 2
#3 0x0000000000419e96 in std::_Bind_simple<inet::Server::Start()::__lambda0()>::_M_invoke<>(std::_Index_tuple<>) (this=0xc913c0) at /usr/include/c++/4.8.2/functional:1732
1732 std::forward<_Args>(std::get<_Indices+1>(_M_bound))...);
(gdb) down 1
#2 0x0000000000417f3b in inet::Server::__lambda0::operator() (__closure=0xc913c0) at /root/projects/gdbTest/inet/Server.cpp:42
42 sleep(1);
(gdb)
怎么样?这些基础命令的使用在实际的工程中发现它的更具体的用法了吧。
最后,输入detach命令,让程序恢复正常运行。
如果想退出调试,quit即可。
五、总结
GDB的使用非常灵活和强大,需要把相关文档中的知识和实际的应用不断的结合,才能形成自己的一套调试技巧和调试思想。工具谁都会用,但是怎么才能用好,更能为我所用,这才是根本。