cc++定位崩溃代码行的方法

上传人:第*** 文档编号:33925615 上传时间:2018-02-19 格式:DOC 页数:11 大小:202KB
返回 下载 相关 举报
cc++定位崩溃代码行的方法_第1页
第1页 / 共11页
cc++定位崩溃代码行的方法_第2页
第2页 / 共11页
cc++定位崩溃代码行的方法_第3页
第3页 / 共11页
cc++定位崩溃代码行的方法_第4页
第4页 / 共11页
cc++定位崩溃代码行的方法_第5页
第5页 / 共11页
点击查看更多>>
资源描述

《cc++定位崩溃代码行的方法》由会员分享,可在线阅读,更多相关《cc++定位崩溃代码行的方法(11页珍藏版)》请在金锄头文库上搜索。

1、 如何根据异常提示信息找出程序出错代码LINUX 编程 2010-06-23 22:44:10 阅读 136 评论 0 字号:大中小 订阅 看到网上说在 debug 下可以找到预料的崩溃地址行,但是实际上没有什么用呀。(既然在 debug 下,那直接用调试器找不更好吗? 费这么大劲干什么)(转的文章在后面)Release 版本(指编译器优化后的),要找崩溃地址行就比较费劲了。linux 下的方法:1、使之生成 core dump 文件2、gdb 调试该 core 文件3、根据大概的堆栈信息,运行 disassemble (具体用法见 gdb 帮助 )4、根据崩溃地址找到对应的崩溃反汇编码5、分

2、析反汇编代码,找到程序中崩溃代码。(如果用 debug 调试,就更简单了,步骤同上,编译的时候加上编译选项 -ggdb ,选项详情请见 man g+)mac 下的方法:1.、使之可以生成 core 文件,方法同 linux2、分析对应的 crash log 在系统日志目录下。3、根据 2 的堆栈信息,反汇编,得到具体地址行。最后转 2 篇 win 下的文章。(这种方法好像难找 release 的。)(1) (vs2003 以上,vc6 找对应设置就可以)步骤一:编译代码时生成 map 文件和 cod 文件我建立了一个名为 DataAbort 的项目,A )生成 map 文件,打开项目属性对话框

3、,找到 “链接-调试”在“生成映射文件”栏选择“是” ; B)生成 cod 文件,打开项目属性对话框,找到“C/C+- 输出文件”在“汇编输出”栏选择“带机器码的程序集”。在默认情况下 map 文件以项目名称命名,而 cod 文件以 cpp 文件名命名,生成目录也不同,编译后可以在项目目录下搜索*.map 和*.cod步骤二:根据异常信息找到相应的 map 文件,及异常地址所在的函数步骤三:打开异常函数所在的 cod 文件,找到异常对应的代码行。分析问题,解决问题(2)对“仅通过崩溃地址找出源代码的出错行”一文的补充与改进读了老罗的“仅通过崩溃地址找出源代码的出错行 ”(下称罗文)一文后,感觉

4、该文还是可以学到不少东西的。不过文中尚存在有些说法不妥,以及有些操作太繁琐的地方。为此,本人在学习了此文后,在多次实验实践基础上,把该文中的一些内容进行补充与改进,希望对大家调试程序,尤其是 release 版本的程序有帮助。欢迎各位朋友批评指正。一、该方法适用的范围在 windows 程序中造成程序崩溃的原因很多,而文中所述的方法仅适用与:由一条语句当即引起的程序崩溃。如原文中举的除数为零的崩溃例子。而笔者在实际工作中碰到更多的情况是:指针指向一非法地址 ,然后对指针的内容进行了,读或写的操作。例如: void Crash1()char * p =(char*)100;*p=100;这些原因

5、造成的崩溃,无论是 debug 版本,还是 release 版本的程序,使用该方法都可找到造成崩溃的函数或子程序中的语句行,具体方法的下面还会补充说明。另外,实践中另一种常见的造成程序崩溃的原因:函数或子程序中局部变量数组越界付值,造成函数或子程序返回地址遭覆盖,从而造成函数或子程序返回时崩溃。例如:#include void Crash2();int main(int argc,char* argv)Crash2();return 0;void Crash2()char p1;strcpy(p,0123456789);在 vc 中编译运行此程序的 release 版本,会跳出如下的出错提示框

6、。 图一 上面例子运行结果这里显示的崩溃地址为:0x34333231。这种由前面语句造成的崩溃根源,在后续程序中方才显现出来的情况,显然用该文所述的方法就无能为力了。不过在此例中多少还有些蛛丝马迹可寻找到崩溃的原因:函数 Crash2 中的局部数组 p 只有一个字节大小,显然拷贝0123456789这个字符串会把超出长度的字符串拷贝到数组 p 的后面,即 *(p+1)=1,*(p+2)=2,* (p+3)=3,*(p+4)=4。而字符1的ASC 码的值为 0x31,2为 0x32,3为 0x33,4 为 0x34。,由于 intel 的 cpu 中 int 型数据是低字节保存在低地址中,所以保

7、存字符串1234的内存,显示为一个 4 字节的 int 型数时就是0x34333231。显然拷贝 0123456789这个字符串时,1234这几个字符把函数 Crash2 的返回地址给覆盖,从而造成程序崩溃。对于类似的这种造成程序崩溃的错误朋友们还有其他方法排错的话,欢迎一起交流讨论。二、设置编译产生 map 文件的方法该文中产生 map 文件的方法是手工添加编译参数来产生 map 文件。其实在 vc6 的 IDE 中有产生map 文件的配置选项的。操作如下:先点击菜单Project-Settings 。,弹出的属性页中选中Link页,确保在category中选中General,最后选中Gen

8、erate mapfile的可选项。若要在在 map 文件中显示Line numbers 的信息的话 ,还需在 project options 中加入/mapinfo:lines 。Line numbers 信息对于罗文所用的方法来定位出错源代码行很重要 ,但笔者后面会介绍更加好的方法来定位出错代码行,那种方法不需要 Line numbers 信息。 图二 设置产生 MAP 文件三、定位崩溃语句位置的方法罗文所述的定位方法中,找到产生崩溃的函数位置的方法是正确的,即在 map 文件列出的每个函数的起始地址中,最近的且不大于崩溃地址的地址即为包含崩溃语句的函数的地址 。但之后的再进一步的定位出错

9、语句行的方法不是最妥当,因为那种方法前提是,假设基地址的值是 0x00400000 ,以及一般的 PE 文件的代码段都是从 0x1000 偏移开始的。虽然这种情况很普遍,但在 vc 中还是可以基地址设置为其他数,比如设置为 0x00500000,这时仍旧套用崩溃行偏移 = 崩溃地址 - 0x00400000 - 0x1000 的公式显然无法找到崩溃行偏移。 其实上述公式若改为崩溃行偏移 = 崩溃地址 - 崩溃函数绝对地址 + 函数相对偏移即可通用了。仍以罗文中的例子为例:罗文 中提到的在其崩溃程序的对应 map 文件中,崩溃函数的编译结果为0001:00000020 ?CrashYAXXZ 0

10、0401020 f CrashDemo。obj 对与上述结果,在使用我的公式时 , 崩溃函数绝对地址指 00401020, 函数相对偏移指 00000020, 当崩溃地址= 0x0040104a 时, 则 崩溃行偏移 = 崩溃地址 - 崩溃函数起始地址+ 函数相对偏移 = 0x0040104a - 0x00401020 + 0x00000020= 0x4a,结果与 罗文计算结果相同 。但这个公式更通用。四、更好的定位崩溃语句位置的方法。其实除了依靠 map 文件中的 Line numbers 信息最终定位出错语句行外,在 vc6 中我们还可以通过编译程序产生的对应的汇编语句,二进制码,以及对应

11、 c/c+语句为一体的cod 文件来定位出错语句行。先介绍一下产生这种包含了三种信息的cod文件的设置方法:先点击菜单Project-Settings。,弹出的属性页中选中C/C+页 ,然后在 Category中选则Listing Files,再在Listing file type的组合框中选择Assembly,Machine code, and source。接下去再通过一个具体的例子来说明这种方法的具体操作。 图三 设置产生cod文件 准备步骤 1)产生崩溃的程序如下:01 /*02 /文件名称:crash。cpp03 /作用: 演示通过崩溃地址找出源代码的出错行新方法04 /作者: 伟功

12、通信 roc05 /日期: 2005-5-1606/*07 void Crash1();08 int main(int argc,char* argv)09 10 Crash1();11 return 0;12 1314 void Crash1()15 16 char * p =(char*)100;17 *p=100;18 准备步骤 2)按本文所述设置产生 map 文件( 不需要产生 Line numbers 信息)。准备步骤 3)按本文所述设置产生 cod 文件。准备步骤 4)编译。这里以 debug 版本为例(若是 release 版本需要将编译选项改为不进行任何优化的选项,否则上述代码

13、会因为优化时看作废代码而不被编译,从而看不到崩溃的结果),编译后产生一个exe文件 ,一个map文件,一个cod 文件。 运行此程序,产生如下如下崩溃提示: 图四 上面例子运行结果 排错步骤 1)定位崩溃函数。可以查询 map 文件获得。我的机器编译产生的 map 文件的部分如下:CrashTimestamp is 42881a01 (Mon May 16 11:56:49 2005)Preferred load address is 00400000Start Length Name Class0001:00000000 0000ddf1H .text CODE0001:0000ddf1 0

14、001000fH .textbss CODE0002:00000000 00001346H .rdata DATA0002:00001346 00000000H .edata DATA0003:00000000 00000104H .CRT$XCA DATA0003:00000104 00000104H .CRT$XCZ DATA0003:00000208 00000104H .CRT$XIA DATA0003:0000030c 00000109H .CRT$XIC DATA0003:00000418 00000104H .CRT$XIZ DATA0003:0000051c 00000104H

15、 .CRT$XPA DATA0003:00000620 00000104H .CRT$XPX DATA0003:00000724 00000104H .CRT$XPZ DATA0003:00000828 00000104H .CRT$XTA DATA0003:0000092c 00000104H .CRT$XTZ DATA0003:00000a30 00000b93H .data DATA0003:000015c4 00001974H .bss DATA0004:00000000 00000014H .idata$2 DATA0004:00000014 00000014H .idata$3 DATA0004:00000028 00000110H .idata$4 DATA0004:00000138 00000110H .idata$5 DATA0004:00000248 000004afH .idata$6 DATAAddress Publics by Value Rva+Base Lib:Object0001:00000020 _main 00401020 f

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号