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文件