GDB的non-stop模式
线程调试必杀技 - GDB的non-stop模式
开源的GDB被广泛使用在Linux、OSX、Unix和各种嵌入式系统(例如手机),这次它又带给我们一个惊喜。
多线程调试之痛
调试器(如VS2008和老版GDB)往往只支持all-stop模式,调试多线程程序时,如果某个线程断在一个断点上,你的调试器会让整个程序freeze,直到你continue这个线程,程序中的其他线程才会继续运行。这个限制使得被调试的程序不能够像真实环境中那样运行--当某个线程断在一个断点上,让其他线程并行运行。
GDBv7.0引入的non-stop模式使得这个问题迎刃而解。在这个模式下,
- 当某个或多个线程断在一个断点上,其他线程仍会并行运行
- 你可以选择某个被断的线程,并让它继续运行
让我们想象一下,有了这个功能后
- 当其他线程断在断点上时,程序里的定时器线程可以正常的运行了,从而避免不必要得超时
- 当其他线程断在断点上时,程序里的watchdog线程可以正常的运行了,从而避免嵌入式硬件以为系统崩溃而重启
- 可以控制多个线程运行的顺序,从而重现deadlock场景了。由于GDB可以用python脚本驱动调试,理论上可以对程序在不同的线程运行顺序下进行自动化测试。
因此,non-stop模式理所当然成为多线程调试“必杀技”。这2009年下半年之后发布的Linux版本里都带有GDBv7.0之后的版本。很好奇,不知道VS2010里是不是也支持类似的调试模式了。
演示GDB的non-stop模式
让破砂锅用一个C++小程序在Ubuntu Linux 09.10下demo这个必杀技。虽然我的demo使用命令行版gdb,如果你喜欢图形化的调试器,Eclipse2009年5月之后的版本可以轻松的调 用这个功能,详情参见Eclipse参见http://live.eclipse.org/node/723
1. 编译以下程序nonstop
1 // gdb non-stop mode demo
2 // build instruction: g++ -g -o nonstop nonstop.cpp -lboost_thread
3
4 #include <iostream>
5 #include <boost/thread/thread.hpp>
6
7 struct op
8 {
9 op(int id): m_id(id) {}
10
11 void operator()()
12 {
13 std::cout << m_id << " begin" << std::endl;
14 std::cout << m_id << " end" << std::endl;
15 }
16
17 int m_id;
18 };
19
20 int main(int argc, char ** argv)
21 {
22 boost::thread t1(op(1)), t2(op(2)), t3(op(3));
23 t1.join(); t2.join(); t3.join();
24 return 0;
25 }
26
2. 把一下3行添加到~/.gdbinit来打开non-stop模式
set target-async 1
set pagination off
set non-stop on
3. 启动gdb,设断点,运行.可以看到主线程1是running,3个子线程都断在断点上,而不是只有一个子线程断在断点上.
~/devroot/nonstop$ gdb ./nonstop
GNU gdb (GDB) 7.0-ubuntu
Reading symbols from /home/frankwu/devroot/nonstop/nonstop...done.
(gdb) break 14
Breakpoint 1 at 0x402058: file nonstop.cpp, line 14.
(gdb) break 24
Breakpoint 3 at 0x401805: file nonstop.cpp, line 24.
(gdb) run
Starting program: /home/frankwu/devroot/nonstop/nonstop
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff6c89910 (LWP 2762)]
[New Thread 0x7ffff6488910 (LWP 2763)]
1 begin
Breakpoint 1, op::operator() (this=0x605118) at nonstop.cpp:14
14 std::cout << m_id << " end" << std::endl;
2 begin
Breakpoint 1, op::operator() (this=0x605388) at nonstop.cpp:14
14 std::cout << m_id << " end" << std::endl;
[New Thread 0x7ffff5c87910 (LWP 2764)]
3 begin
Breakpoint 1, op::operator() (this=0x605618) at nonstop.cpp:14
14 std::cout << m_id << " end" << std::endl;
(gdb) info threads
4 Thread 0x7ffff5c87910 (LWP 2764) op::operator() (this=0x605618) at nonstop.cpp:14
3 Thread 0x7ffff6488910 (LWP 2763) op::operator() (this=0x605388) at nonstop.cpp:14
2 Thread 0x7ffff6c89910 (LWP 2762) op::operator() (this=0x605118) at nonstop.cpp:14
* 1 Thread 0x7ffff7fe3710 (LWP 2759) (running)
4. 让线程3继续运行,注意我顾意把主线程1也continue,这是我发现的workaround,否则gdb不能切回thread 1.
(gdb) thread apply 3 1 continue Thread 3 (Thread 0x7ffff6488910 (LWP 2763)):
Continuing. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
2 end
[Thread 0x7ffff6488910 (LWP 2763) exited] warning: Unknown thread 3. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
(gdb) info threads
4 Thread 0x7ffff5c87910 (LWP 2764) op::operator() (this=0x605618) at nonstop.cpp:14
2 Thread 0x7ffff6c89910 (LWP 2762) op::operator() (this=0x605118) at nonstop.cpp:14
* 1 Thread 0x7ffff7fe3710 (LWP 2759) (running)
5. 让另外两个线程继续运行而结束,主线程断在第24行,最后结束.
(gdb) thread apply 4 2 1 continue Thread 4 (Thread 0x7ffff5c87910 (LWP 2764)):
Continuing. Thread 2 (Thread 0x7ffff6c89910 (LWP 2762)):
Continuing. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
3 end
1 end
[Thread 0x7ffff5c87910 (LWP 2764) exited]
[Thread 0x7ffff6c89910 (LWP 2762) exited] Breakpoint 3, main (argc=1, argv=0x7fffffffe348) at nonstop.cpp:24
24 return 0; (gdb) continue
Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing. Program exited normally.
参考资料
Reverse Debugging, Multi-Process and Non-Stop Debugging Come to the CDT
GDB的non-stop模式的更多相关文章
- GDB技巧:使用终端界面模式
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 简 ...
- GDB调试命令小结
1.启动调试 前置条件:编译生成执行码时带上 -g,如果使用Makefile,通过给CFLAGS指定-g选项,否则调试时没有符号信息.gdb program //最常用的用gdb启动程序,开始调试的方 ...
- [skill][gdb] gdb 多线程调试
中文快速入门: http://coolshell.cn/articles/3643.html (关于多线程的部署说的并不太对) 进阶: 多进程相关概念: inferiors 是什么? http://m ...
- GDB 调试 一些命令
1. gdb查看指定地址的内存地址的值:examine 简写 x-----使用gdb> help x 来查看使用方式 x/ (n,f,u为可选参数)n: 需要显示的内存单元个数,也就是从 ...
- gdb 调试程序
要调试生成的可执行程序,必须在生成的时候加入-g选项,生成可以调试的代码 例如:gcc -o test a.c b.c -g 这样gcc就会在链接的时候加入一些用于调试的符号 在生成可以调试的可执行程 ...
- GCC编译器和GDB调试器常用选项
http://blog.csdn.net/u014328976/article/details/46745349 GCC编译器 gcc hello.c -o hello ...
- Gdb远程调试Linux内核遇到的Bug
知识共享许可协议本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/gdb-bug 本博客同步在http://www.cn ...
- 【疑难杂症】gdb调试多线程程序报错:interrupted system call
一. cmake生成可调试版本的程序,该内容参考自https://www.linuxidc.com/Linux/2014-03/98622.htm 具体内容如下: 1, 使用CMAKE编译确实很方便. ...
- Linux多进程和多线程的一次gdb调试实例
转载https://typecodes.com/cseries/multilprocessthreadgdb.html 1 原文整理 默认设置下,在调试多进程程序时gdb只会调试主进程.gdb7以上的 ...
- Linux下gdb调试(tui)
1 处于TUI模式的GDB 为了以TUI模式运行GDB,可以在调用GDB时在命令行上指定-tui选项,或者处于非TUI模式时在GDB中使用Ctrl+X+A组合键.如果当前处于TUI模式,后一种命令方式 ...
随机推荐
- linux线程(一)基本应用
有感而发(可以直接忽略~):每次要用到线程,都要在网上重新学下基础,例子倒是不少:一种是排版好,讲的不全又不是自己想要的:一种是排版不好,直接略过了.两者兼有的又要苦苦寻找,所以还是自己总结了,觉得每 ...
- 标签form表单里的属性简单介绍了一下
<form id="form1" name="form1" method="post" action=""> ...
- 国内外免费PHP开源建站程序一览(最全)
论坛社区:Discuz.PHPWind.ThinkSAAS.phpBB CMS内容管理:DedeCMS.PHPCMS.帝国CMS.齐博CMS.Drupal 企业建站:CmsEasy.KingCMS.P ...
- JavaScript clearInterval定时器失效原因
检查下是不是setInterval重复执行(两次以上<!-- 文件上传板块 --> <div id="adUploadWindow" class="ea ...
- 【LA 5713 】 Qin Shi Huang's National Road System (MST)
[题意] 秦始皇要在n个城市之间修路,而徐福声可以用法术位秦始皇免费修1条路,每个城市还有人口数,现要求徐福声所修之路的两城市的人口数之和A尽量大,而使n个城市互通需要修的路长B尽量短,从而使得A/B ...
- HTML图片热点、网页划区、拼接、表单
一.图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可以完成跳转的效果. 示例: 二.网页划区: 在一个网页里,规划出一个区域用来展示另一个网页的内容. 示例: 三.网页的拼接: ...
- GCC优化选项-fomit-frame-pointer对于esp和ebp优化的作用
我的博客:www.while0.com -fomit-frame-pointer选项是发布产品时经常会用到的优化选项,它可以优化汇编函数中用edp协助获取堆栈中函数参数的部分,不使用edp,而是通过计 ...
- 17.1.1 How to Set Up Replication 设置复制:
17.1.1 How to Set Up Replication 设置复制: 17.1.1.1 Setting the Replication Master Configuration 17.1.1. ...
- 子查询解嵌套in改写为exists
SELECT * FROM (SELECT pubformdat0_.id id332_, pubformdat0_.domain_id domain2_332_, pubformdat0_.proc ...
- 原生态Ajax实例
<script type="text/javascript"> var xmlhttprequest; function GetXmlHttpRequest() { i ...