Finding crash information using the Map file

Brief introduction

Write clean applications is one thing. But when the user tells you when your software has crashed, you know best to solve the problem before adding other features. If you're lucky, there will be a collapse of the user address. This will greatly help to solve this problem. But how can you address this crash to determine what's the problem?

Create a Map file

First, you need a Map file. If not, use a crash almost impossible to find the location address application crashes. First, I will show you how to create a good Map file. To this end, I will create a new project (MAPFILE). You can do the same, or adjust your own projects. I use the Win32 application in VC ++ 6.0 the option to create a new project, select the "typical" Hello World! application'.

 And in the following vs2013, vs2005 from the beginning is not supported/MAPINFO:LINES

 

 

Now you can compile and link your project. Link, you will find in the middle of a .map file directory (along with your EXE file).

Map reading file

We will use the example of a crash to achieve this. So first of all: How to crash your application. I InitInstance () function is added at the end of these two lines:

char* pEmpty = NULL;
*pEmpty = 'x';	// This is line 119

I'm sure you can find other instructions will make your application fail. Now re-compile and link. If you start the application, it crashes, you will receive the following message: "The instruction at 0x004011a1" referenced memory "0x00000000" at. Can not "write" memory.

Now is the time to open the Map file with Notepad or something like that. Map your file would be as follows: top Map file contains the module name, and time stamp indicating the project links the preferred load address (unless you use the DLL, or it may be 0x00400000). After the head is a section of information from a variety of linker introduced OBJ and LIB files section.

MAPFILE

 Timestamp is 3df6394d (Tue Dec 10 19:58:21 2002)

 Preferred load address is 00400000

 Start         Length     Name                   Class
 0001:00000000 000038feH .text                   CODE
 0002:00000000 000000f4H .idata$5                DATA
 0002:000000f8 00000394H .rdata                  DATA
 0002:0000048c 00000028H .idata$2                DATA
 0002:000004b4 00000014H .idata$3                DATA
 0002:000004c8 000000f4H .idata$4                DATA
 0002:000005bc 0000040aH .idata$6                DATA
 0002:000009c6 00000000H .edata                  DATA
 0003:00000000 00000004H .CRT$XCA                DATA
 0003:00000004 00000004H .CRT$XCZ                DATA
 0003:00000008 00000004H .CRT$XIA                DATA
 0003:0000000c 00000004H .CRT$XIC                DATA
 0003:00000010 00000004H .CRT$XIZ                DATA
 0003:00000014 00000004H .CRT$XPA                DATA
 0003:00000018 00000004H .CRT$XPZ                DATA
 0003:0000001c 00000004H .CRT$XTA                DATA
 0003:00000020 00000004H .CRT$XTZ                DATA
 0003:00000030 00002490H .data                   DATA
 0003:000024c0 000005fcH .bss                    DATA
 0004:00000000 00000250H .rsrc$01                DATA
 0004:00000250 00000720H .rsrc$02                DATA

After the festival information, you will receive a public function information. Note that "public" part. If you have a static C function declarations, they do not appear in the mapping file. Fortunately, the line numbers will reflect a static function. An important part of the information is a public function information and the function name column Rva + Base, Rva + Base column is the starting address of the function.

Address         Publics by Value              Rva+Base     Lib:Object

0001:00000000       _WinMain@16                00401000 f   MAPFILE.obj
0001:000000c0       ?MyRegisterClass@@YAGPAUHINSTANCE__@@@Z 004010c0 f   MAPFILE.obj
0001:00000150       ?InitInstance@@YAHPAUHINSTANCE__@@H@Z 00401150 f   MAPFILE.obj
0001:000001b0       ?WndProc@@YGJPAUHWND__@@IIJ@Z 004011b0 f   MAPFILE.obj
0001:00000310       ?About@@YGJPAUHWND__@@IIJ@Z 00401310 f   MAPFILE.obj
0001:00000350       _WinMainCRTStartup         00401350 f   LIBC:wincrt0.obj
0001:00000446       __amsg_exit                00401446 f   LIBC:wincrt0.obj
0001:0000048f       __cinit                    0040148f f   LIBC:crt0dat.obj
0001:000004bc       _exit                      004014bc f   LIBC:crt0dat.obj
0001:000004cd       __exit                     004014cd f   LIBC:crt0dat.obj
0001:00000591       __XcptFilter               00401591 f   LIBC:winxfltr.obj
0001:00000715       __wincmdln                 00401715 f   LIBC:wincmdln.obj
//SNIPPED FOR BETTER READING
0003:00002ab4       __FPinit                   00408ab4     <common>
0003:00002ab8       __acmdln                   00408ab8     <common>

entry point at        0001:00000350

Static symbols

0001:000035d0       LeadUp1                    004045d0 f   LIBC:memmove.obj
0001:000035fc       LeadUp2                    004045fc f   LIBC:memmove.obj
 //SNIPPED FOR BETTER READING
0001:00000577       __initterm                 00401577 f   LIBC:crt0dat.obj
0001:0000046b       _fast_error_exit           0040146b f   LIBC:wincrt0.obj

public function部分后面是行信息(如果您在链接选项卡中使用了/MAPINFO:LINES,在C/C++选项卡中选择了“行号”,Vs2005开始没有了)。之后,如果项目包含导出的函数,并且在“链接”选项卡中包含/MAPINFO:EXPORTS,则将获得导出信息。

Line numbers for .\Release\MAPFILE.obj(F:\MAPFILE\MAPFILE.cpp) segment .text

    24 0001:00000000    30 0001:00000004    31 0001:0000001b    32 0001:00000027
    35 0001:0000002d    53 0001:00000041    40 0001:00000047    43 0001:00000050
    45 0001:00000077    47 0001:00000088    48 0001:0000008f    52 0001:000000ad
    53 0001:000000b3    71 0001:000000c0    80 0001:000000c3    81 0001:000000c8
    82 0001:000000ff    86 0001:00000114    88 0001:00000135    89 0001:00000145
   102 0001:00000150   108 0001:00000155   110 0001:00000188   122 0001:0000018d
   115 0001:0000018e   116 0001:0000019a   119 0001:000001a1   121 0001:000001a8
   122 0001:000001ae   135 0001:000001b0   143 0001:000001cc   172 0001:000001ee
   175 0001:0000020d   149 0001:00000216   157 0001:0000022c   175 0001:00000248
   154 0001:00000251   174 0001:0000025f   175 0001:00000261   151 0001:0000026a
   174 0001:00000287   175 0001:00000289   161 0001:00000294   164 0001:000002a8
   165 0001:000002b6   166 0001:000002d8   174 0001:000002e7   175 0001:000002e9
   169 0001:000002f2   174 0001:000002fa   175 0001:000002fc   179 0001:00000310
   186 0001:0000031e   193 0001:0000032e   194 0001:00000330   188 0001:00000333
   183 0001:00000344   194 0001:00000349

现在我们来看看坠机地点。首先,我们将确定哪个函数包含崩溃地址。在“Rva+Base”列中搜索第一个地址大于崩溃地址的函数。映射文件中的前一项是导致崩溃的函数。在我们的示例中,崩溃地址是0x004011a1。这在0x00401150和0x004011b0之间,所以我们知道崩溃函数是?InitInstance@@YAHPAUHINSTANCE__@@H@Z 。以问号开头的任何函数名都是C++修饰的名称。要转换名称,请将其作为命令行参数传递给平台SDK程序UNDNAME.EXE(在bin dir中)。大多数时候,您不需要这样做,因为您可以通过查看它来了解它(这里是MAPFILE.obj中的InitInstance())。
这是追踪错误的一大步。但情况变得更好了:我们可以查出车祸发生在哪条线上!我们需要做一些基本的十六进制数学,所以没有计算器就做不到的人:现在是使用它的时候了。第一步是以下计算:crash_address-preferred_load_address-0x1000。
地址是从第一个代码段开始的偏移量,因此我们需要进行此计算。减去首选加载地址是合乎逻辑的,但为什么我们需要再减去一个0x1000?崩溃地址是代码段开头的偏移量,但二进制文件的第一部分不是代码段!二进制文件的第一部分是可移植可执行文件(PE),长度为0x1000字节。谜团解开了。在我们的示例中,这是:0x004011a1-0x00400000-0x1000=0x1a1
现在是时候查看Map文件的行信息部分了。这些行如下所示:30 0001:00000004。第一个数字是行号,第二个数字是该行所在代码段开头的偏移量。如果我们想查找行号,我们只需做与函数相同的事情:确定第一次出现的偏移量大于我们刚刚计算的偏移量。崩溃发生在前面的条目中。在我们的示例中:0x1a1在0x1a8之前。所以我们的崩溃发生在MAPFILE.CPP的119行。

如果我们是VS2005及以后的版本,只能借助其他手段来获取代码行了。

保留Map文件

每个版本都有自己的映射文件。在EXE发行版中包含映射文件并不是一个坏主意。这样,您就可以确定这个EXE的映射文件是正确的。你可以在你的系统中保留每个带有EXE的映射文件,但是我们都知道这可能会给以后带来一些麻烦。映射文件不包含任何您不希望用户看到的信息(除非可能是类和函数名?)。用户将无法使用它,但如果您自己没有副本,至少可以请求映射文件。

 

Guess you like

Origin www.cnblogs.com/yilang/p/11994448.html