[转]两个经典的windbg调试案例,值得学习。

 

1. 调试Bug的神兵利器:通过WinDbg条件断点收集Log

原文地址:http://blogs.msdn.com/yizhang/archive/2009/03/30/bug-windbg-log.aspx

调试Bug的神兵利器:通过WinDbg条件断点收集Log

前段时间花了几天一直在用WinDbg调试一个比较棘手的Bug。这个Bug是C# Team那边发现的,他们的Testcase跑大概10分钟左右会出一个在CLR内部的ASSERT。比较难调试的主要原因在于ASSERT表明一个全局的数据结构出现了问题,本来不应该用完的数组却已经用完了(因为按照设计,这个数组是边使用边清理的,是不会用完的)。初步想到的有下面几种方案来调试:

1. 设置数据断点

2. 一步一步调试

3. 添加Log代码

设置数据断点的主要问题是不太好确定到底是因为什么原因导致的数据结构问题,而且因为是数组被用完,很难将是到底是哪一个数组元素的加入导致了数组被全部占用,因此无法通过设置数据断点的方法来调试。一步一步的调试显然也没法解决问题,因为这个Testcase本身要跑十分钟,可以想象单步调试运行十分钟的程序会花费多长时间。因此两个方案都被我否决。添加Log代码其实是可以的,只是需要修改代码,每次修改之后需要重新编译代码,然后需要在目标机器上安装,而且C#使用的CLR的Branch并非我们正在开发的Branch,需要重新下载源代码,相对比较麻烦。最后为了解决这个问题,我采取的方法是使用WinDbg的条件断点+Log的方式。大致的方法如下:

第一步:在一个或者多个可疑处设置断点

bu address “command”

bu是WinDbg中的设置Unresolved Breakpoints命令,用起来比较方便,我比较喜欢用。address就是你所要断的代码地址,可以是函数开始,也可以是某一行。Command非常重要,它表示了WinDbg在每次断到address的时候都要执行的命令,不同命令用分号隔开,如:

.echo [Function A]; dv this; kb; g

这几条命令意思是:打印[Function A],打印this指针的值,打印当前调用栈,然后继续执行。大家可以根据实际情况添加一些其他命令打印一些自己所需要的信息。通过上面这套命令打印的内容大致如下:

[FunctionA]

this = 0xABCDEFG

module!FuncA

module!FuncB

module!FuncC

可以看出,这条断点如果反复被断,那么在WinDbg的命令窗口中便会把每次断点被Hit的相关信息通过刚才定义的命令打印出来。如果定义了很多这样的断点,那么在命令窗口中就会把整个程序执行的情况打印出来,起到Log的作用,而且可以显示调用栈等信息,比一般的Log要强大许多。

第二步:设置Log

缺省情况下,WinDbg的Buffer大小是有限的,如果程序运行时间比较长,那么Buffer可能会不够,我们通过条件断点打出的信息会被截断。幸好,WinDbg提供了将命令窗口的内容输出到Log中的功能。选择Edit->Open/Close Log File菜单项,WinDbg会显示如下对话框:

clip_image002

在这个对话框里面输入你想要保存的Log文件名即可。如果是添加新的内容而不是覆盖原有的,则勾上Append。

第三步:分析Log

当获得了Log信息之后,下一步就需要分析Log的内容了,这是一件需要耐心、对数据的敏感、以及一点点运气的事情。分析的时候可能发现Log的信息不足,这时就需要添加新的断点或者修改打印的信息,重新收集Log,再加以分析,直到Log信息足够为止。这时WinDbg设置条件断点的优势就出来了,因为不需要修改代码,编译代码,部署代码这样的一个过程,而是只需要键入不同的命令而已。经过几次调整断点位置和打印的信息并重新收集Log,我最终通过分析发现这个Bug是只有可能在特定情况下RCW没有被GC,并且创建线程退出的时候才会出现,具体的内容因为涉及到.NET 4.0中还没有发布的新功能,这里就不多说了。可以看到,如果采用常规的方法,对于这种在特定的条件下才会重现的问题是很难发现的。

总之,使用WinDbg来设置条件断点,打印相关信息,并且输出到Log文件是一种非常强大的调试方法,可以调试一些非常复杂的Bug,而且具有不需要修改代码的灵活性,可以自由定义自己想需要打印的信息和断点设置的位置,主要的缺点是方法稍显复杂,不过如果适应了之后还是很方便的。我强烈推荐大家在遇到比较复杂的Bug的时候,可以尝试使用一下这种方法,可能具有意想不到的效果哦。

 

 

如果一个程序跑10000次只失败一次,你会怎么调试?

原址:http://blogs.msdn.com/yizhang/archive/2009/08/28/9887951.aspx

CLR小组中存在着大量的回归测试,这些回归测试会定期执行来发现CLR中的Bug,Developer在Checkin之前,也需要执行这些测试的一部分(大概是10小时左右,如果全部跑的话估计要好几天)。这些测试对于保证CLR的质量是至关重要的。有时候,这些测试会偶尔失败,比如跑100次失败大概一到两次,有些极端的例子甚至是10000次才失败一次。像这种问题通常是很难调试的。在前面调试Bug的神兵利器:通过WinDbg条件断点收集Log这篇文章中,我讲到了如何通过条件断点收集各种信息来判断Bug究竟出在哪里。但是,这个方法还是不太管用,因为它不能够反复执行某个程序。下面我要讲一种技巧可以用来调试类似这样的问题,这种技巧主要适用于下面几种情况:

  1. 在程序出错的时候,某些信息、状态已经丢失,无法通过当前出错时候的状态推断出之前的状态。说的稍微具体一点就是,比如某个变量变成了NULL导致Access Violation,但是很难直接推断出为什么这个变量变成了NULL
  2. 程序运行时间较长,很难直接单步调试
  3. 程序较难修改加入打印代码(比如加入新代码并编译非常花时间,或者该程序没有源代码
  4. 该程序运行次数较多的时候才能发现问题,也就是说问题不是每次都出现

#2和#4决定了一步步调试基本上是不可能的。#1和#3则意味着我们必须得使用条件断点来收集信息来判断代码的错误,因为直接调试出错的位置是不可行的。下面了我来讲一下如何用CDB(其实就是WinDbg的无UI版本,WinDbg=CDB+UI)来做到:

  1. 反复执行程序
  2. 当程序出错的时候自动暂停
  3. 通过条件断点收集信息,只保留出错时候的那一次Log

我们先假设我们需要调试的程序叫做Hello.exe,每次出问题的现象是,调用某个函数Hello!Func()的时候,其参数arg为NULL。Arg这个变量是由某个全局变量g_arg传入而来。我们可以通过硬件的数据断点来查看每次将g_arg赋值为NULL的情况(当然了,赋值为NULL并不代表是错误,只有传入Hello!Func的时候为NULL才是错误)。程序一般要跑10000次才可能发现问题。使用下面的命令行可以做到反复收集Func1(Func2、Func3因为类似,这里就不列出了)执行时候的g_arg的值并放入Log文件中,并且如果发现调用Hello!Func的时候arg参数为NULL,则停止程序:

for /L %i in (1, 1, 10000) DO CDB.exe -c "bu Hello!Func \".echo Inside Hello!Func; dv; .if (poi(arg)!=0) { g } \"; ba w4 Hello!g_arg \“.if (poi(Hello!g_arg)==0) { .echo g_arg changes to NULL; kb; }\”; g" -G -logo debug.log Hello.exe

我们来简单分析一下:

  1. 一开头的For语句用于执行CDB命令10000次,也就是调试Hello.exe一万次
  2. -c命令指定让CDB在程序开始的时候执行下面的命令
    1. bu Hello!Func “.echo Inside Hello!Func; dv; .if (poi(arg)!=0) { g }意思是每次Hello!Func被执行的时候,打印Inside Hello!Func,之后打印所有局部变量和参数(包括arg),如果发现arg!=NULL,则继续。注意上面命令中的\”是转义符,代表真正的引号,避免冲突。
    2. ba w4 Hello!g_arg “.if (poi(Hello!g_arg)==0) { .echo g_arg changes to NULL; kb; }”意思是每次如果g_arg被修改成NULL,打印出Callstack
    3. g命令表示让程序开始执行
  3. -G:表示让CDB忽略程序结束的时候的Breakpoint,避免CDB在运行结束的时候停下,保证CDB可以持续执行不需要人工干预
  4. -logo debug.log:表示让CDB把每次输出的结果放入Debug.log中,并且每次都新建立文件,也就是说,会把上一次覆盖。这正好是我们需要的,因为我们设置了一旦程序错误则停止,那么这一次的Debug.log才是需要保留的

除了用-c指定初始的命令之外,也可以使用-cf来指定一个文件包含任意条CDB命令,如果CDB命令较多,可以采用这种方法。

本文说道的方法是比较有效的,我自己曾经使用过这种方法解决过不少比较棘手的问题。如果碰到了此种需要运行10000次才能重现问题的Bug,不妨试一下本文的方法。

转载于:https://www.cnblogs.com/hhuai/archive/2010/03/01/1675383.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式之观察者

观察者模式介绍观察者又名事件订阅者、监听者。观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察者”该对象的其他对象。通知目标:拥有一些值得关注的状态的对象。发布者:它要自身的状态改…

二面京东被问到Java 反射,我直呼好家伙,这我不是必过吗?

二面京东被问到Java 反射,我直呼好家伙,这我不是必过吗?用多久我会升职加薪、当上技术总监、迎娶漂亮学姐、走上人生巅峰!想想还有点小激动。 好了开始分享面试经历 说说你反射的理解 到底什么是反射呢??…

通用路由封装(GRE)×××配置

本人没有很好的文采,只能直接配置,有不懂的地方,后面可以联系我,在配置当中,我会尽量在配置命令后面加标注。1、在R1上配置相关的命令R1(config)#int fa0/0 ---进入以太网fa0/0接口--R1&#…

gridview DataFormatString

转有个时间要在gridview中显示,但是保持着数据库中的是标准时间,很长,而且只需要显示日期,就想要格式化字符串,可是设置了DataFormatString就是不起作用,后来一查,原来要设置"行为"中HtmlEncode false DataFormatString"{0:格式字符串}" 在DataFormatStri…

太神奇了!使用C#实现自动核验健康码:(1)二维码识别

前言因为疫情的原因,无论是进入商场还是医院、车站,都需要出示健康码。现在基本都是采取人工方式核验健康码,看到绿码就通过,否则就禁止进入。但是,单靠人工核验健康码容易造成人员拥堵,增加病毒交叉感染的…

三角形中惊现叛徒!自己胖的像个球,却能成就世界上最快的赛车引擎......

全世界只有3.14 % 的人关注了青少年数学之旅一日,理科生上山寻访禅师。理科生问禅师:“大师,世人为何总嫌我棱角太突出,不合群!”禅师思索一阵,掏出数根圆柱铺在地上,在上面搁了一块木板&#x…

我丢,去面试初级Java开发岗位,被问到泛型?

1、泛型的基础概念 1.1 为什么需要泛型 List list new ArrayList();//默认类型是Objectlist.add("A123");list.add("B234");list.add("C345");System.out.println(list);for(int i0;i<list.size();i){//若要将list中的元素赋给String变量&a…

echart 地图 某个地区_中国饮食地图来袭!你爱的口味暗藏健康隐患吗?

食&#xff0c;既是人生存之根本&#xff0c;也是人们热爱生活的体现。中国地域广阔、物产富饶&#xff0c;中国人对“吃”看重也愿钻研&#xff0c;种种因素造就了中国美食 “百花齐放”的局面&#xff0c;在“吃货”眼里&#xff0c;中国地图俨然就是一张美食地图。不同地区的…

面试官:实现一个带值变更通知能力的Dictionary

如题&#xff0c; 你知道字典KEY对应的Value什么时候被覆盖了吗&#xff1f;最近大家都在追.Net6 update&#xff0c;咱还是保持节奏&#xff0c;通用语言聊技术。没背景说个铲铲上文中 数据获取组件维护了业务方所有(在用)的连接对象&#xff0c;DBA能在后台无侵入的切换备份库…

颠覆认知!完美赌徒,到底是如何用数学打造经济神话?!

▲ 点击查看说起世界上最会赚钱的数学家&#xff0c;非詹姆斯西蒙斯莫属。1938年&#xff0c;西蒙斯出生于美国的马萨诸塞州&#xff0c;是一个鞋厂的儿子。在其他的孩子&#xff0c;还在听童话故事的时候&#xff0c;西蒙斯就已经开始展露出惊人的数学天赋了。3岁的时候&…

abs函数的使用方法 oracle_SQL Server 常用函数使用方法

1、SubString()&#xff1a;用于截取指定字符串的方法。该方法有三个参数&#xff1a;参数1&#xff1a;用于指定要操作的字符串。参数2&#xff1a;用于指定要截取的字符串的起始位置&#xff0c;起始值为 1 。参数3&#xff1a;用于指定要截取的长度。select substring(abcde…

高考落榜怎么办,奉劝学弟学妹们一些事情,请一定要擦亮眼睛

在目前这个社会情况Java技术是当前社会的一个热门专业&#xff0c;无论是pc端还是移动端对java的需求都是最多的&#xff0c;大学生学java正好顺应时代的发展&#xff0c;不仅有钱途还有前途&#xff0c;Java也适合零基础的人学习。 最近看见一句话 高考不努力&#xff0c;学习…

神仙打架!一人公开单挑全欧洲数学家,却惨遭4位数学家大反转,66年的难题被一晚破解......

全世界只有3.14 % 的人关注了青少年数学之旅两点之间直线最短&#xff0c;这家喻户晓的数学名言&#xff0c;就算是学渣也能倒背如流。但学渣们不知道的是&#xff0c;这条直线并不是最快的。为了让学渣们真正理解这句话&#xff0c;今天&#xff0c;超模君决定科普一波起源关于…

基于事件驱动架构构建微服务第4部分:repositories

原文链接&#xff1a;https://logcorner.com/building-microservices-through-event-driven-architecture-part4-repositories/在本文中&#xff0c;我将实现Repositories的命令端。存储库属于Clean架构的接口适配器在这一步中&#xff0c;我将开始实现基础设施的命令端&#x…

小松

之前做过一次小小的介绍(没看过的请参看此文&#xff1a;闲话小松)&#xff0c;相信不少老朋友应该都知道我是谁了。还不认识我的朋友可以称呼我小松(这名号有年头了&#xff0c;听习惯了^_^)&#xff0c;当然你喜欢怎么喊都成&#xff1a;)偶是个是理想主义的倡导者&#xff0…

vlan后 出现 outlook 正在试图从服务器检索数据

vlan后 出现 outlook 正在试图从服务器检索数据 cisco vlan outlook 正图试从Microsoft Exchange Server 检索数据。cisco 3750 vlan outlook is retrieving data from Microsoft Exchange Server mail.abc.com 最近对公司的网络按需要划分了基出802.1q的VLAN&#xff0c;…

二面京东,面试官直接问我JVM,我心里一阵暗爽~

二面京东&#xff0c;面试官直接问我JVM&#xff0c;我心里一阵暗爽~简直了&#xff0c;hhhh明人不说暗话&#xff0c;直接进入主题&#xff01;&#xff01;&#xff01;一、什么是JVM二、JAVA代码编译和执行过程类加载机制类执行机制三、JVM内存管理和垃圾回收垃圾回收按照基…

最后的代课老师———漆红玉[转]

1月31日凌晨6点我们从渭源县城出发&#xff0c;天还未亮。1月的甘肃干冷干冷的&#xff0c;我们是在半路上接的漆老师&#xff0c;刚开始我以为是寇筱茜老师的一个熟人&#xff0c;路上寇老师才和我说漆老师也是代课老师。寇筱茜老师有一句名言&#xff1a;每一个代课老师都有一…

ae渲染出现错误是什么问题_[Switch]解决OPENWRT路由,使用UU加速器等出现相同IP,DNS解析错误问题...

本文在之上添加DNS解析错误的解决方案解决 NS openwrt路由器 开腾讯 UU之类的加速器无法上网的问题​tieba.baidu.com将子网掩码转换为二进制&#xff0c;即为11111111.11111111.0.0&#xff0c;1有16位&#xff0c;令x16&#xff1b;IP地址若为aaa.bbb.ccc.ddd&#xff0c;设置…

程序员从入门到升级,或许可以看一看这几个公众号

全世界只有3.14 % 的人关注了青少年数学之旅快节奏的现代社会中&#xff0c;每个人都疲于奔命&#xff0c;“丧、累、太难了”已成为成年人的生活主题。难得的闲暇时间&#xff0c;公众号是不可或缺的消遣方式。但我们被海量数据淹没&#xff0c;越来越多的公众号只是消耗情绪&…