方法:
注意事项:在最后面^_^。
完整项目源码请点击这里!
一.使用.map以及.cod定位bug(暴力崩溃)
首先介绍在软件异常崩溃后如何使用.map以及.cod定位bug。
需要进行的工程项目属性配置:
设置好项目属性后,按下F7进行编译,可以看到工程目录下生成对应的.map文件:
那.cod文件在哪里呢?
找不到搜索一下就知道了:
可以看到每个.cpp文件会对应的生成一个.cod。
下面来演示一下如何使用.map以及.cod精确定位到程序崩溃的位置:
首先,运行.exe,让它暴力的崩掉:
这是一件很恐怖的事情!
接下来,我们点击一下“查看问题详细信息”这个扩展按钮;
凉凉!差点。还好这次我们还有神器.map和.cod。
下面就是见证奇迹的地方:
a1. 打开.map文件(vs就可以打开了,当然用记事本也是没有问题滴),我们可以看到开头的是这几行:
ExceptionHandleTest:工程名
Timestamp is 5c7de239 (Tue Mar 05 10:43:05 2019):工程是什么时间编译的
Preferred load address is 0000000140000000:(三角形重点)基地址
接下来是data段了,这里不用管。
再继续往下看,可以看到画红色底线这行了,重点又来了:
Rva:偏移地址
Base:基地址
红色线下面开始就是函数信息,而我们需要的信息隐藏在其中。
在Windows弹出的崩溃信息窗口可以看到
偏移地址:0000000000001ce5
而基地址(在.map开头):0000000140000000
那么软件崩溃的Rva+Base就是0000000140001ce5这里了,当然.map里并没有对每一个地址都做详尽的记录,我们要做的是找到比这个地址小一点的地方就能大概找到崩溃的位置了。
在本例中,Ctrl+F,输入0140001c进行查找
刚好找到一个比0000000140001ce5稍微要小的地址,我们来看一下这一行告诉了我们什么信息
可以看到,这这里是ExceptionHandleTestDlg的fun函数里,对应地址是0000000140001c90。到了这里可以大概定位到了崩溃函数的位置了。但是我们还可以更进一步定位到是在哪一行代码崩溃的。
终于轮到我们的.cod出场了。
找到ExceptionHandleTestDlg.cod,双击打开,查找到以?fun@CExceptionHandleTestDlg开头的一行
包含这一串字符的会有不少行,但是以其开头的只有这一行,对,就是蓝色这一行。
然后我们来看一看我们找到的这一行下面的是什么
; 179 : int b[10]; --> 行数 : 源码
0001d c7 44 24 60 00 --> 偏移地址 机器码
接下来我们就要做一个简单的计算,以确定是在哪一行崩了的。
从windows弹出的软件崩溃提示信息窗口中我们得知的:
异常偏移地址Rva:0000000000001ce5
那么异常地址 expeAddr = expeRva + Base = 0000000140001ce5
而我们找到的函数地址 findAddr = 0000000140001c90
那么导致崩溃对应的代码所在行的偏移地址 = expeAddr - findAddr = 0x0055
那么我们找到fun函数下偏移0055的地方:
从这行往上一点点,我们看到了: ; 193 : *c = 5;
好开心,终于找到你了。
然后打开CExceptionHandleTestDlg.cpp,找到第193行,可以看到:
我的天,竟然定义了指针,没开辟内存就直接赋值了。
至此,利用.map和.cod两大神器找崩结束,修bug就交给你了。
二.使用.dmp定位bug(优雅崩溃)
首先需要进行的工程项目属性配置:
1.xxx属性 -> 配置属性 -> C/C++ -> 常规 -> 调试信息格式,选择 程序数据库 (/Zi)
(浅尝不选这个也行,尚未深究)
接下来就是如何生成.bmp文件了,详情观看一下例程。
在CExceptionHandleTestApp.h类中#include "HiExceptionHandle.h",并定义一个HiExceptionHandle类对象excep:
然后在启动软件时,运行的比较早的函数中添加函数调用:excep.RunCrashHandler();
然后,F7编译。
接着再次让软件进入崩溃:
可以看到这次显示竟然不是Windows自动弹出的“xxx停止工作”那个让人绝望的窗口了,而是弹出我们自己设定的窗口,点击确定就可以优雅的关掉软件了,并且可以看到关掉软件后生成了.dmp文件:
下面就让我们来试一下如何.dmp来快速定位使软件崩溃的位置吧。
双击打开HiMiniDump.dmp(VS2010即可打开),进入以下界面:
在该界面中,我们可以看到并不明显的右上角“操作”这个框框:
那么在此呢,我们需要保证几个东西的一致性,即.exe .pdb .dmp是同一个版本的,当然还有相对应的源码也要保持一致。
然后接下来呢,有两种情况:
那么设置一下符号路径:
(其实我在本机上也不用这么设置,但是拷贝到另一台电脑测试时就要)
点击“确定”,然后点击“使用 仅限本机 进行调试”,进入以下界面:
点击“中断”,这里需要稍等一会儿,莫心急哈。
然后,我们把“调用堆栈”的滑条滑到最上面,你就能惊奇的发现点蛛丝马迹:
对!就是这个:
> ExceptionHandleTest.exe!CExceptionHandleTestDlg::fun(int * a) 行 193 + 0x5 字节 C++
然后兴奋的双击它,额!怎么弹出下面这个框的?
嗦嘎,原来是需要对应的源文件,那就找到这个.cpp,拷过来瞧一瞧会发生点什么吧。
把对应的.cpp放进去后,打开,竟然,竟然神奇的定位到了念念不忘的可爱的bug的位置了:
至此,完成了使软件崩溃的bug的查找,完善bug就交给你了。
注意事项:
以上两种方法的使用都有前提,那就是要保证用到的文件要保持版本一致性,所以要做好相应的备份哦!
另外,在测试中发现数组越界导致的崩溃竟无法定位到,好伤心,各位大神大咖有什么建议意见还望不吝指点小弟迷津。感激阅读!
完整工程源码请点击这里!