仅通过崩溃地址找出源代码的出错行
仅通过崩溃地址找出源代码的出错行 作者:老罗 http://www.vckbase.com/document/viewdoc/?id=908 提交者:eastvc 发布日期:2003-10-23 9:16:11 原文出处:http://www.luocong.com/articles/show_article.asp?Article_ID=29 作为程序员,我们平时最担心见到的事情是什么?是内存泄漏?是界面不好看?……错啦!我相信我的看法是不会有人反对的——那就是,程序发生了崩溃! “该程序执行了非法操作,即将关闭。请与你的软件供应商联系。”,呵呵,这句 M$ 的“名言”,恐怕就是程序员最担心见到的东西了。有的时候,自己的程序在自己的机器上运行得好好的,但是到了别人的机器上就崩溃了;有时自己在编写和测试的过程中就莫名其妙地遇到了非法操作,但是却无法确定到底是源代码中的哪行引起的……是不是很痛苦呢?不要紧,本文可以帮助你走出这种困境,甚至你从此之后可以自豪地要求用户把崩溃地址告诉你,然后你就可以精确地定位到源代码中出错的那行了。(很神奇吧?呵呵。) 首先我必须强调的是,本方法可以在目前市面上任意一款编译器上面使用。但是我只熟悉 M$ 的 VC 和 MASM ,因此后面的部分只介绍如何在这两个编译器中实现,请读者自行融会贯通,掌握在别的编译器上使用的方法。 Well,废话说完了,让我们开始! :) 首先必须生成程序的 MAP 文件。什么是 MAP 文件?简单地讲, MAP 文件是程序的全局符号、源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方、任何时候使用,不需要有额外的程序进行支持。而且,这是唯一能找出程序崩溃的地方的救星。 好吧,既然 MAP 文件如此神奇,那么我们应该如何生成它呢?在 VC 中,我们可以按下 Alt+F7 ,打开“Project Settings”选项页,选择 C/C++ 选项卡,并在最下面的 Project Options 里面输入:/Zd ,然后要选择 Link 选项卡,在最下面的 Project Options 里面输入: /mapinfo:lines 和 /map:PROJECT_NAME.map 。最后按下 F7 来编译生成 EXE 可执行文件和 MAP 文件。 在 MASM 中,我们要设置编译和连接参数,我通常是这样做的: rc %1.rc 把它保存成 makem.bat ,就可以在命令行输入 makem filename 来编译生成 EXE 可执行文件和 MAP 文件了。 在此我先解释一下加入的参数的含义: /Zd 表示在编译的时候生成行信息 OK,通过上面的步骤,我们已经得到了 MAP 文件,那么我们该如何利用它呢? 让我们从简单的实例入手,请打开你的 VC ,新建这样一个文件: 01 //**************************************************************** 很显然本程序有“除0错误”,在 Debug 方式下编译的话,运行时肯定会产生“非法操作”。好,让我们运行它,果然,“非法操作”对话框出现了,这时我们点击“详细信息”按钮,记录下产生崩溃的地址——在我的机器上是 0x0040104a 。 再看看它的 MAP 文件:(由于文件内容太长,中间没用的部分我进行了省略) CrashDemo Timestamp is 3e430a76 (Fri Feb 07 09:23:02 2003) Preferred load address is 00400000 Start Length Name Class Address Publics by Value Rva+Base Lib:Object 0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo.obj entry point at 0001:000000f0 Line numbers for .\Debug\CrashDemo.obj(d:\msdev\myprojects\crashdemo\crashdemo.cpp) segment .text 13 0001:00000020 14 0001:00000038 15 0001:0000003f 16 0001:00000046 如果仔细浏览 Rva+Base 这栏,你会发现第一个比崩溃地址 0x0040104a 大的函数地址是 0x00401070 ,所以在 0x00401070 这个地址之前的那个入口就是产生崩溃的函数,也就是这行: 0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo.obj 因此,发生崩溃的函数就是 ?Crash@@YAXXZ ,所有以问号开头的函数名称都是 C++ 修饰的名称。在我们的源程序中,也就是 Crash() 这个子函数。 OK,现在我们轻而易举地便知道了发生崩溃的函数名称,你是不是很兴奋呢?呵呵,先别忙,接下来,更厉害的招数要出场了。 请注意 MAP 文件的最后部分——代码行信息(Line numbers information),它是以这样的形式显示的: 13 0001:00000020 第一个数字代表在源代码中的代码行号,第二个数是该代码行在所属的代码段中的偏移量。 如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算: 崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000 为什么要这样做呢?细心的朋友可能会留意到 Rva+Base 这栏了,我们得到的崩溃地址都是由 偏移地址(Rva)+ 基地址(Base) 得来的,所以在计算行号的时候要把基地址减去,一般情况下,基地址的值是 0x00400000 。另外,由于一般的 PE 文件的代码段都是从 0x1000 偏移开始的,所以也必须减去 0x1000 。 好了,明白了这点,我们就可以来进行小学减法计算了: 崩溃行偏移 = 0x0040104a - 0x00400000 - 0x1000 = 0x4a 如果浏览 MAP 文件的代码行信息,会看到不超过计算结果,但却最接近的数是 CrashDemo.cpp 文件中的: 16 0001:00000046 也就是在源代码中的第 16 行,让我们来看看源代码: 16 i /= j; 哈!!!果然就是第 16 行啊! 兴奋吗?我也一样! :) 方法已经介绍完了,从今以后,我们就可以精确地定位到源代码中的崩溃行,而且只要编译器可以生成 MAP 文件(包括 VC、MASM、VB、BCB、Delphi……),本方法都是适用的。我们时常抱怨 M$ 的产品如何如何差,但其实 M$ 还是有意无意间提供了很多有价值的信息给我们的,只是我们往往不懂得怎么利用而已……相信这样一来,你就可以更为从容地面对“非法操作”提示了。你甚至可以要求用户提供崩溃的地址,然后就可以坐在家中舒舒服服地找到出错的那行,并进行修正。 是不是很爽呢? :) |
最新评论 [发表评论] [文章投稿] | 查看所有评论 推荐给好友 打印 |
VS2005不支持了 ( pcasa 发表于 2006-12-25 10:50:00) 错误在 \0 ,系统不能编译通过! 改为:\n ,即可! char* my_strpbrk(char* char* ); void main() } char* my_strpbrk(char* srcStr , char* chrSec) while (*srcStr != NULL) if(str_end) } else ++ srcStr ; }; return str_end ; 恳请各位大侠赐教! ( czyfseal 发表于 2004-2-18 20:53:00) |
仅通过崩溃地址找出源代码的出错行相关推荐
- 通过崩溃地址找错误行数之Delphi版
通过崩溃地址找错误行数之Delphi版 2009-5-11 17:42:35 来源: 转载 作者:网络 访问:360 次 被顶:2 次 字号:[大 中 小] 核心提示:什么是 MAP 文件?简单地讲, ...
- 什么工具可以分析php源代码,PHP_一个可以找出源代码中所有中文的工具,一个可以找出源代码中所有中 - phpStudy...
一个可以找出源代码中所有中文的工具 一个可以找出源代码中所有中文的工具 填写需要查找的路径$sf即可. 功能 1 找出所有中文 2 忽略注释语句中的中文 3 可添加需要忽略的文件和文件夹 4 生成日志 ...
- Python数据分析 找出数组中每行(或每列)中指定的百分位数 numpy.percentile()
[小白从小学Python.C.Java] [Python-计算机等级考试二级] [Python-数据分析] Python数据分析 找出数组中每行(或每列) 中指定的百分位数 numpy.percent ...
- C语言--在终端输入多行信息,找出包含“ould”的行,并打印改行
问题: 在终端输入多行信息,找出包含"ould"的行,并打印改行. 如: Au,love could you and I with fate conspire To grasp t ...
- python dataframe 查看为空值_Python pandas.DataFrame 找出有空值的行
0.摘要 pandas中DataFrame类型中,找出所有有空值的行,可以使用.isnull()方法和.any()方法. 1.找出含有空值的行 方法:DataFrame[DataFrame.isnul ...
- 找出OData service出错根源的小技巧
SAP的Fiori应用是通过OData和后台交互的.在使用Fiori应用时您可能会遇到这样的错误消息: 这个错误消息没有包含有助于partner或者客户定位问题根源的线索. 下面是如何在后台找出问题根 ...
- MAP文件和调试(VC)(从崩溃地址找出错源码位置)
也是:一直听说,从未动手. 所以,用VC生成一下MAP文件,帮助调试. 一.步骤: Project Settings-> C/C++-> Project Options: 这里输入 /Zd ...
- 查找txt中的中文字符_找出nginx请求日志中某个url请求总次数排名前十的ip地址...
答案如下: # 利用linux自带命令:sort.awk.grep.head.uniq组合得出相应的答案 awk '{print $1}' | grep 'www.xxxx.com' access.l ...
- Python中找出dataframe中的重复的行 DataFrame.duplicated()方法
● 选择题 以下关于DataFrame.duplicated()函数说法错误的是: A 该函数用于标记dataframe中内容重复的行 B 该函数返回值是一个序列,True表示重复 C 行内容被判定重 ...
最新文章
- Domino R8.5相关链接
- N个免费DevOps开源工具,没用过,至少应该了解!
- 算法之智能搜索(下)
- mysql 指定目录_mysql 更改默认数据目录
- 明日之后服务器维修会补偿什么,明日之后:服务器修复后官方发来补偿,玩家居然怀疑奖励不真实?...
- julia 数组类型转换_在Julia中确定类型的超类型
- wordpress雪花下雪WP Snow Effect插件
- Spring和Mybatis整合
- 【Janino】Janino框架初识与使用教程
- Nagios插件开发指导
- 车辆路径问题之jsprit(一):认识jsprit
- 遭DeFi反噬,以太坊绝地反击
- Mount is denied because the NTFS volume is already exclusively opened.The volume may be already ...
- java雪崩_了解java架构之微服务架构—雪崩效应
- Redis 报错: WRONGTYPE Operation against a key holding the wrong kind of value
- 6000多万铲屎官,捧得出一个国产主粮的春天吗?
- 一个男人的一生应该有几个女人?
- 什么产品适合做海外众筹
- 安装配置Apache和php
- php update when,iphone will restart when update什么意思
热门文章
- mybatis传递多个参数_Mybatis传递多个参数的4种方式(干货)
- 使用MySQL Workbench远程管理工具进行远程管理Mysql的错误及解决办法
- Python的捕虫笔记
- Java 多态的简单介绍.
- Oracle 实例崩溃恢复原理剖析 -- 检查点队列的作用与意义
- RHEL 5.4 安装Oracle 11gR2, 安装篇2
- centos7 nginx配置php7,centos7下yum安装nginx和php7和php-fpm
- 计算机用于尖端科技,【判断题】用演绎法教问句的方法适用于中高级型学生
- javascript取随机数_查缺补漏一些 Javascript 的小技巧笔记
- 2021年下半年软考报考流程!