map 文件的使用(续)

KEIL Map文件解析以及如何从Map文件还原内存分布 Keil的Map文件解析,内存分布图的还原以及内存越界分析 阅读详情
----- 前言 -----

    在程序发布后,最怕的事情是什么?不是效率低,不是界面不好,而是 crash。当用户把一张程序 crash 后的 Windows 截图发给你时,此时最大的愿望肯定是希望通过这张截图,获取更多的关于 crash 的信息。下面就探讨如何通过 crash 地址找出源代码的相关信息。

    探讨之前进行一些简单的界定:
适用:Windows 下 Visual C++ 编程。
条件:Project 设置正确,生成 map 文件,修正 Dll 加载地址的冲突。
功能:主要是查找内存访问违规导致的 crash,不能查找一个无效的指令地址,如访问 delete 后的指针。


----- 生成 map 文件 -----

    好的开始,是成功的一半!请按部就班进行以下操作:

1, 下载最新的 dbghelp.dll 符号引擎

    把该 Dll 放到要使用该 Dll 的程序相同的目录下。

2, 把 pdb 文件和 build 的二进制文件放在相同目录下。

    该步骤对生成 map 文件是不需要的,主要是方便用微软的调试工具 + dump 文件来查找 crash 信息。具体请查阅参考资料 [1]。

3, 用调试符来连编所有的构件

    调试符是调试器显示程序的源代码信息、变量名称以及数据类型信息的数据。

    在 VC++ 2003 中设置 (*** 代表 Project 名字):
    Project -> *** Properties -> *** Property Pages =>

a) -> c/c++ -> General -> Debug Information Format -> Program Database (/Zi)

    这将开启发布构件的调试符。把调试符加入二进制代码中时,二进制代码的大小会有少量增加。
    实测表明 .exe 文件大小无变化,但生成的 .pdb 和 .map 文件会增大不少。这会把程序代码相关的信息写入 .map 文件,否则 .map 文件中只写入 lib 文件的代码信息。

b) -> Linker -> Debugging -> Generate Debug Info (/DEBUG); Generate Map File (/MAP); Map Exports; Map Lines

   /MAP:生成 map 文件
   /MAPINFO:EXPORTS:将导出信息包含到 map 文件中 (增大 .pdb 文件)
   /MAPINFO:LINES:将代码行信息包含到 map 文件中

   -> Linker -> Command Line -> Additional Options 输入:/OPT:REF

   /OPT:REF 开关使链接器只调入程序直接调用的函数;否则,发布的应用程序会包括从未调用过的函数,使应用程序要大得多。

4, 修改部分代码的编译条件

    把有问题文件以 3 级警告编译,其他的用 4 级警告编译:
#pragma warning (push, 3)
#include "IDoNotCompileAtWarning4.h"
#pragma warning (pop)

    在特定代码区域关闭个别警告:
// Turning off 4201
#pragma warning (disable : 4201)
//... codes ...
// Turn warning back on.
#pragma warning (default:4201)

5, Dll 的加载地址

    根据向导创建项目的默认值,VC++ Dlls 加载在 0x10000000,可以改变 Dll 的基本地址(即 rebase)。

当在调试器的 Output 输出:
LDR: Dll xxx base 10000000 relocated due to collision with yyy
这说明:xxx 和 yyy 两个 Dll 有冲突。

此时需要重定义基址:
c) -> Linker -> Advanced -> Base Address; Fixed Base Address

    推荐按照字母顺序重定义 Dll 的基址:
Dll 首字母: Base Addr
A_C: 0X60000000
G_I: 0X62000000
J_L: 0X63000000
M_O: 0X64000000
P_R: 0X65000000
S_U: 0X66000000
V_X: 0X67000000
Y_Z: 0X68000000

    操作系统 Dll 在 0x70000000 - 0x78000000 这段地址上进行加载。


----- map文件的内容 -----

    通常,map 文件是一个几 MB 或更大的文本文件,包括以下几部分:
注:本文附带的是一个节选的 demo,为简单说明用。

a) 首部信息,包括:模块名称、显示 link.exe 链接模块的时间标记、首选的加载地址(可简记为 PLA )。
 demo
 Timestamp is 4326e927 (Tue Sep 13 22:58:47 2005)
 Preferred load address is 00400000

b) 扇区信息,说明链接器从各个 obj 文件和 lib 文件引入哪些扇区。
 Start         Length     Name                   Class
 0001:00000000 001840feH .text                   CODE
 0002:00000000 00000ba4H .idata$5                DATA

c) 公用函数信息包括函数名称,Rva+Base 表示函数的启动地址,与 Address 存在如下换算关系:
  Rva+Base = (Preferred load address) + Address + 0x1000

  Address         Publics by Value              Rva+Base     Lib:Object
 0000:00000000       ___ImageBase               00400000     <linker-defined>
 0001:00000000       ?Allocate@CCRTAllocator@ATL@@SAPAXI@Z 00401000 f i AboutDlg.obj

    静态声明的函数信息:
 entry point at        0001:00135a59
 Static symbols
 0001:0000a933       $L111251                   0040b933 f i DownloadDlg.obj

d) 代码行信息
  Line numbers for ./Release/frozen.obj(f:/btdown/frozen.c) segment .text
   304 0001:000647e0   303 0001:000647e0   305 0001:000647e6   306 0001:000647f0
    其中 304 0001:000647e0,304 表示代码行号;0001:000647e0 表示从代码行所在的代码段开始部分到该代码行所在位置的偏移量。

e) 模块的导出函数
 Exports
 ordinal name
 1 ?MapDllFunction@@YAHXZ (int __cdecl MapDllFunction(void))


----- map 文件的使用 -----

    当有了合格的 map 文件,就可以进行使用了。

a) 寻找包含崩溃地址的文件

    if 首选的加载地址 <= 崩溃地址 <= 公用函数扇区的最后一个地址
    then 查看的是正确的 map 文件

b) 浏览公用函数的 Rva+Base 栏,直到找到第一个比崩溃地址大的函数的地址。map 文件中先前的那个入口就是产生 crash 的函数。
    所有以问号 '?' 打头的函数名称都是 C++ 修饰的名称,如要转换该名称,需要将它作为一个命令行参数传送到 Platform SDK 程序 UNDNAME.EXE 中。

c) 计算偏移量

    偏移量 = (crash address) - (preferred load address) - 0x1000
    因为 crash 地址是从代码扇区开始的偏移量,但代码扇区并不是二进制代码的开头部分;二进制代码的开头部分是 PE (Portable Executable) 标题,该标题的长度为 0x1000 字节;所以计算地址要减去 0x1000。

d) 查找代码行号

    查找 map 文件的代码行信息,直到找到不大于但却最接近这个偏移量的数为止。


----- 使用实例 -----

a) 报错信息:"0x0044a093" 指令引用的 "0x4e49b391" 内存。该内存不能为 "Read"。

b) 查找 map 文件:
 0001:00048b20       ?OnEraseBkgnd@CDemoView@@QAEHPAVCDC@@@Z 00449b20 f   DemoView.obj
 0001:00049300       ?OnLButtonDown@CDemoView@@QAEXIVCPoint@@@Z 0044a300 f   DemoView.obj
    因为 00449b20 < 0044a093 < 0044a300,所以 crash 的函数是:?OnEraseBkgnd@CDemoView@@QAEHPAVCDC@@@Z

c) 偏移量 = 崩溃地址 - 首选的加载地址 - 0x1000
          = 0x0044a093 - 0x00400000 - 0x1000 = 0x49093
    或者如下计算:
    偏移量 = 崩溃地址 - 崩溃函数起始地址 + 函数相对偏移
           = 0x0044a093 - 0x00449b20 + 0x00048b20 = 0x49093

d) 查找代码行:

 -- 方法1: 使用 map 文件进行查找
Line numbers for ./Release/DemoView.obj(f:/btdown/DemoView.cpp) segment .text
 536 0001:0004907d 537 0001:000490f2
    因为 4907d < 49093 < 490f2,所以 crash 代码行是:536 行。


 -- 方法2: 使用 cod 文件

    -- 生成源文件的 ASM 文件

    方法1: Project Property Pages => c/c++ => Output Files => Assembler Output 中直接选择。
    方法2: 在 Project Property Pages => c/c++ => Command Line => Additional Options 中键入:
    /FAs,编译器就会为每个源文件生成一个 ASM 文件。
    /FAcs,生成源文件代码和ASM代码对应的 cod 文件。
    以上选项可以为整个 Project 设置,也可以为某个源文件设置。

    -- 计算语句偏移量
函数内偏移量 = 崩溃地址 - 崩溃函数的起始地址
             = 0x0044a093 - 0x00449b20 = 0x573
崩溃语句在 cod 文件中的相对偏移 = 崩溃函数在 cod 文件中相对偏移 + 函数内偏移量
           = 0x0000 + 0x573

    -- 查找代码行
    因为崩溃语句在 cod 文件中的相对偏移为 0x573,由 cod 文件知为 536 行代码。

    -- 相关 cod 文件片段
?OnEraseBkgnd@CDemoView@@QAEHPAVCDC@@@Z PROC NEAR    ; CDemoView::OnEraseBkgnd, COMDAT
; _this$ = ecx
; 412  : {
  00000    6a ff         push     -1
; 语句汇编后的偏移地址 00000,二进制码 6a ff,汇编代码 push -1
; 其余省略......

; crash 语句
; 536  : CString str1 = player->GetNickname();
  0055d    8b 54 24 10     mov     edx, DWORD PTR _player$155238[esp+168]
  00561    8d 0c 3b     lea     ecx, DWORD PTR [ebx+edi]
  00564    89 7c 24 54     mov     DWORD PTR _rtName$[esp+168], edi
  00568    89 44 24 58     mov     DWORD PTR _rtName$[esp+172], eax
  0056c    89 4c 24 5c     mov     DWORD PTR _rtName$[esp+176], ecx
  00570    8b 72 10     mov     esi, DWORD PTR [edx+16]
  00573    8b 4e f0     mov     ecx, DWORD PTR [esi-16]
; 其余省略......


----- map 文件无能为力的地方 -----

1 指针指向一非法地址,然后对指针的内容进行了读或写的操作。
{
    int *pp;
    *pp = 222;
}
release 版本下出错:
" "0x6bc8b527" 指令引用的 "0x00000516" 内存。该内存不能为 "read"。"

2 函数或子程序中局部变量数组越界赋值,造成函数或子程序返回地址被覆盖,从而造成函数或子程序返回时崩溃。


----- 参考资料 -----

1 John Robbins. 应用程序调试技术. 清华大学出版社.
2 对“仅通过崩溃地址找出源代码的出错行”一文的补充与改进. http://www.vckbase.com/document/viewdoc/?id=1473
[Cortex-M3]-2-map文件解析 目录1 几个问题1.1 什么是map文件1.2 如何查看编译出的程序和数据的信息1.3 如何生成map文件1.4 map文件里面有哪些信息2 map文件信息详解2.1 Section Cross References 2.2 Removing Unused input sections from the image 2.3 Image Symbol Ta 阅读详情

相关推荐

Unity Shader-法线贴图(Normal Map)与视差贴图(Parallax Map)

简介 法线贴图技术至今一直是游戏增强画面效果的利器之一。随着移动设备的性能越来越好,曾经的在PC平台的各种高级技术在移动平台也都开始大规模使用了。最近印象最深刻的就是《镇魔曲》,场景地形全部都加了法线,可以说是无所不用其极了....之前还没见过哪个游戏在移动平台敢这么大规模地使用法线。而且人模的渲染也是走的次时代的流程。不得不说大厂就是牛,本屌丝只能望别人家的游戏兴叹啊。本篇文章主要是研

puppet_master的专栏 1万+

map 文件的使用

                 map 文件的使用             Horin|贺勤        Email: horin153@msn.com        Blog: http://blog.csdn.net/horin153/----- 前言 -----    在程序发布后,最怕的事情是什么?不是效率低,不是界面不好,而是 crash。当用户把一张程序 crash 后的 Wind

Horin与程序 1万+

各类渲染贴图map汇总

1,法线贴图,normal map Normal Mapping法线映射多用在CG动画的渲染以及游戏画面的制作上,将具有高细节的模型通过映射烘焙出法线贴图(Normal Map),贴在低端模型的法线贴图通道上,使之拥有更高细节的渲染效果。可降低渲染时需要的面数和计算内容,从而达到优化动画渲染和游戏渲染效果的目的。Normal Mapping法线映射是一种技术,是Shader 着色器用于渲染...

wangqing008的专栏 3907

关于Albedo贴图、颜色贴图、Metallic 贴图、Specular贴图、法线贴图、视差贴图、凹凸贴图、Height Map高度贴图、AO 贴图Occlusion 贴图、Emission 贴图等

在学习unity的过程中,被各种贴图弄得晕头转向,为了弄清楚各种贴图,查询了很多资料,粗略的整理如下,只要耐心看完,对贴图的基本用法基本上就没问题了。 1.Albedo 贴图 (可以看做是Diffuse颜色贴图) Albedo:反照率[贴图];用于体现模型的纹理,颜色。 反照率贴图本身是一张颜色与纹理的贴图。 该选项有贴图属性,也有颜色属性。 两个属性可以单独使用,也可以组合使用; 当颜色属性为纯白色时,则不影响贴图的效果; 当颜色属性为其他颜色时,则叠加贴图效果。 2.Metallic 贴图 ** 金属度

weixin_44191050的博客 4万+

PBR贴图基础知识

PBR贴图基础知识

噗噗噗的博客 2万+

学习threejs,tga格式图片文件贴图

本文详细介绍如何基于threejs在三维场景中使用tga格式图片文件贴图,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 1992

置换贴图(Displacement map),凹凸贴图(Bump map)与法线贴图(Normal map)的区别

英文原文地址《Difference between Displacement , Bump and Normap Maps》 By Pluralsight on August 14, 2014 你是否在学习如何为你的3D素材制作贴图的时候遇到了点小挫折?不要灰心!很多贴图或3D领域的艺术家在初次遇到凹凸贴图(Bump map),法线贴图(Normal map)以及置换贴图(Displaceme...

开发游戏的老王 4万+

置换贴图,法线贴图,凹凸贴图的区别

先自我介绍……你要是说这是自我炒作我也认了。首先说明,FXCarl是一个对3D美术一窍不同的家伙。虽然很想往技术美工方向发展了。因为是学程序出身,眼下能做的也就是写写Shaders。等到手上的项目做完,会公开始用的实时光照模型……不过那是后话了。现在只是想配合一下这两天大家讨论的热火朝天的Normal Map,在这里和占大多数的美术人员从另外一个角度来谈谈“凹凸贴图技术” 首先我想说,对于凹

把握自己。 1万+

学习threejs,使用Texture纹理贴图,canvas动态更新贴图

本文详细介绍如何基于threejs在三维场景中使用Texture纹理贴图,canvas动态更新贴图,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 1890

学习threejs,dds格式图片文件贴图

本文详细介绍如何基于threejs在三维场景中实现dds格式图片文件贴图,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 1645

unity material以及各种贴图介绍

在三维图形渲染中,贴图与shader组合成材质,用来告诉gpu如何进行绘制,决定了三维模型表面最终呈现出来的颜色。 贴图作为材质中使用的图像。 将它们映射到应用这个材质的表面,然后直接应用到诸如漫反射贴图之类的地方,或者在材质中将贴图的贴图像素值作为蒙板使用,或用于其它计算。

qq_41286360的博客 1万+

Three.js 纹理贴图 - 环境贴图 - 纹理贴图 - 透明贴图 - 高光贴图

描述几何体的顶点坐标描述纹理贴图的坐标位置关系是一一对应的,每一个顶点位置对应一个纹理贴图的位置根据纹理坐标将纹理贴图的对应位置裁剪映射到几何体的表面上。0, 0, 0, //顶点1坐标100, 0, 0, //顶点2坐标0, 100, 0, //顶点3坐标]);0, 0, //顶点1对应位置的纹理坐标uv1, 0, //顶点2对应位置的纹理坐标uv0, 1, //顶点3对应位置的纹理坐标uv]);

好好学习天天向上 4848

遮挡贴图(Occlusion Map)和微表面贴图(Microsurface Map)

在3D图形学中,遮挡(Occlusion)是指光被物体挡住。即便是在PBR中,环境光在某些应该被遮挡的地方,也会以古怪的方式被反射。遮挡贴图(Occlusion Map)可以让为这些地方增加阴影。绝大部分3D模型都会带Occlusion Map,使用遮挡贴图可以让物体表面看起来更加真是,也能增加Base Map和Bump Mapping无法表现出的细节阴影。

vivo01的专栏 3635

unity 3d中关于贴图、高光贴图、OA贴图、OCC贴图、凹凸贴图、法线贴图、 Ambient Occlusiont OA贴图介绍和使用步骤教程

基础介绍 diffuse map 漫反射贴图 将平面图像福附着在3d模型上,使模型的像素按uv坐标显示贴图上的颜色信息,从而使模型拥有跟多的细节。漫反射贴图包含物体最基本的色彩信息 Specular maps 高光贴图 高光贴图是用来处理当光线照射到模型表面时像素表现的 Ambient Occlusiont OA贴图 很重要 环境阻塞贴图,是一种通过计算物体间的距离,并根据距离产生一个8位的...

失业求捞! 1万+

Zbrush学习笔记九——制作贴图、展UV

在Zbrush中生成模型贴图一:在Tool菜单中制作贴图1,纹理贴图:制作纹理贴图需要在模型的最高细分等级下制作,点击创建下面的通过多边形绘制创建,然后点击克隆纹理,然后在Texture面板中将纹理导出即可。2,置换贴图:置换贴图制作时模型一定要有细分等级,且模型处于低等级状态时才可以制作。制作置换贴图是时的运算方式可以选择自适应或是DPSubpix模式,两者的区别在于自适应可能会出现人工修饰的痕...

qianshengcxj的博客 1万+

vs生成的map文件详解

目录 1.如何设置生成map文件 2.map文件内容 1.首部信息 2.段(section)信息——information about the sections in this module 1.sections的介绍: 2.内存分布 3.函数信息——actual symbolic information 4.静态符号 1.如何设置生成map文件 链接的时候生成map 打开项...

u012138730的专栏 1万+

unity标准Shader之十种贴图类型

十种贴图类型 介绍:标准 Shader 贴图 标准 Shader 使用的是 PBR 渲染,基于现实物理效果的渲染表现形式。 一个模型能不能使用标准 Shader 来进行渲染,是在做这个模型的贴图的时候 决定的。有没有按照 PBR 贴图的制作规范和模式来制作,决定了该模型是否可 以...

qq_42898629的博客 5146

利用Nginx反向代理实现GitLab自定义域名的高效配置

本文详细介绍了如何利用Nginx反向代理实现GitLab自定义域名的高效配置。通过统一域名管理、性能优化和安全加固,提升GitLab的访问效率和安全性。文章包含前期准备、GitLab基础配置、Nginx反向代理设置及常见问题排查,帮助开发者快速完成部署。

weixin_28834169的博客 164
上一篇: 利用map文件找到程序崩溃代码行
下一篇: CMenuButton控件
htt9931
博客等级 码龄24年 43粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值