rc %1.rc ml /c /coff /Zd %1.asm link /subsystem:windows /mapinfo:exports /mapinfo:lines /map:%1.map %1.obj %1.res |
/Zd 表示在编译的时候生成行信息 /map[:filename] 表示生成 MAP 文件的路径和文件名 /mapinfo:lines 表示生成 MAP 文件时,加入行信息 /mapinfo:exports 表示生成 MAP 文件时,加入 exported functions (如果生成的是 DLL 文件,这个选项就要加上) |
01 //**************************************************************** 02 //程序名 称:演示如何通过崩溃地址找出源代码的出错行 03 //作者: 罗聪 04 //日 期:2003-2-7 05 //出 处:http://www.luocong.com(老罗的缤纷天地) 06 //本程序 会产生“除0错误”,以至于会弹出“非法操作”对话框。 07 //“除0 错误”只会在 Debug 版本下产生,本程序为了演示而尽量简化。 08 //注意事 项:如欲转载,请保持本程序的完整,并注明: 09 //转载自 “老罗的缤纷天地”(http://www.luocong.com) 10 //**************************************************************** 11 12 void Crash(void) 13 { 14 int i = 1; 15 int j = 0; 16 i /= j; 17 } 18 19 void main(void) 20 { 21 Crash(); 22 } |
CrashDemo Timestamp is 3e430a76 (Fri Feb 07 09:23:02 2003) Preferred load address is 00400000 Start Length Name Class 0001:00000000 0000de04H .text CODE 0001:0000de04 0001000cH .textbss CODE 0002:00000000 00001346H .rdata DATA 0002:00001346 00000000H .edata DATA 0003:00000000 00000104H .CRT$XCA DATA 0003:00000104 00000104H .CRT$XCZ DATA 0003:00000208 00000104H .CRT$XIA DATA 0003:0000030c 00000109H .CRT$XIC DATA 0003:00000418 00000104H .CRT$XIZ DATA 0003:0000051c 00000104H .CRT$XPA DATA 0003:00000620 00000104H .CRT$XPX DATA 0003:00000724 00000104H .CRT$XPZ DATA 0003:00000828 00000104H .CRT$XTA DATA 0003:0000092c 00000104H .CRT$XTZ DATA 0003:00000a30 00000b93H .data DATA 0003:000015c4 00001974H .bss DATA 0004:00000000 00000014H .idata$2 DATA 0004:00000014 00000014H .idata$3 DATA 0004:00000028 00000110H .idata$4 DATA 0004:00000138 00000110H .idata$5 DATA 0004:00000248 000004afH .idata$6 DATA Address Publics by Value Rva+Base Lib:Object 0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo.obj 0001:00000070 _main 00401070 f CrashDemo.obj 0004:00000000 __IMPORT_DESCRIPTOR_KERNEL32 00424000 kernel32:KERNEL32.dll 0004:00000014 __NULL_IMPORT_DESCRIPTOR 00424014 kernel32:KERNEL32.dll 0004:00000138 __imp__GetCommandLineA@0 00424138 kernel32:KERNEL32.dll 0004:0000013c __imp__GetVersion@0 0042413c kernel32:KERNEL32.dll 0004:00000140 __imp__ExitProcess@4 00424140 kernel32:KERNEL32.dll 0004:00000144 __imp__DebugBreak@0 00424144 kernel32:KERNEL32.dll 0004:00000148 __imp__GetStdHandle@4 00424148 kernel32:KERNEL32.dll 0004:0000014c __imp__WriteFile@20 0042414c kernel32:KERNEL32.dll 0004:00000150 __imp__InterlockedDecrement@4 00424150 kernel32:KERNEL32.dll 0004:00000154 __imp__OutputDebugStringA@4 00424154 kernel32:KERNEL32.dll 0004:00000158 __imp__GetProcAddress@8 00424158 kernel32:KERNEL32.dll 0004:0000015c __imp__LoadLibraryA@4 0042415c kernel32:KERNEL32.dll 0004:00000160 __imp__InterlockedIncrement@4 00424160 kernel32:KERNEL32.dll 0004:00000164 __imp__GetModuleFileNameA@12 00424164 kernel32:KERNEL32.dll 0004:00000168 __imp__TerminateProcess@8 00424168 kernel32:KERNEL32.dll 0004:0000016c __imp__GetCurrentProcess@0 0042416c kernel32:KERNEL32.dll 0004:00000170 __imp__UnhandledExceptionFilter@4 00424170 kernel32:KERNEL32.dll 0004:00000174 __imp__FreeEnvironmentStringsA@4 00424174 kernel32:KERNEL32.dll 0004:00000178 __imp__FreeEnvironmentStringsW@4 00424178 kernel32:KERNEL32.dll 0004:0000017c __imp__WideCharToMultiByte@32 0042417c kernel32:KERNEL32.dll 0004:00000180 __imp__GetEnvironmentStrings@0 00424180 kernel32:KERNEL32.dll 0004:00000184 __imp__GetEnvironmentStringsW@0 00424184 kernel32:KERNEL32.dll 0004:00000188 __imp__SetHandleCount@4 00424188 kernel32:KERNEL32.dll 0004:0000018c __imp__GetFileType@4 0042418c kernel32:KERNEL32.dll 0004:00000190 __imp__GetStartupInfoA@4 00424190 kernel32:KERNEL32.dll 0004:00000194 __imp__HeapDestroy@4 00424194 kernel32:KERNEL32.dll 0004:00000198 __imp__HeapCreate@12 00424198 kernel32:KERNEL32.dll 0004:0000019c __imp__HeapFree@12 0042419c kernel32:KERNEL32.dll 0004:000001a0 __imp__VirtualFree@12 004241a0 kernel32:KERNEL32.dll 0004:000001a4 __imp__RtlUnwind@16 004241a4 kernel32:KERNEL32.dll 0004:000001a8 __imp__GetLastError@0 004241a8 kernel32:KERNEL32.dll 0004:000001ac __imp__SetConsoleCtrlHandler@8 004241ac kernel32:KERNEL32.dll 0004:000001b0 __imp__IsBadWritePtr@8 004241b0 kernel32:KERNEL32.dll 0004:000001b4 __imp__IsBadReadPtr@8 004241b4 kernel32:KERNEL32.dll 0004:000001b8 __imp__HeapValidate@12 004241b8 kernel32:KERNEL32.dll 0004:000001bc __imp__GetCPInfo@8 004241bc kernel32:KERNEL32.dll 0004:000001c0 __imp__GetACP@0 004241c0 kernel32:KERNEL32.dll 0004:000001c4 __imp__GetOEMCP@0 004241c4 kernel32:KERNEL32.dll 0004:000001c8 __imp__HeapAlloc@12 004241c8 kernel32:KERNEL32.dll 0004:000001cc __imp__VirtualAlloc@16 004241cc kernel32:KERNEL32.dll 0004:000001d0 __imp__HeapReAlloc@16 004241d0 kernel32:KERNEL32.dll 0004:000001d4 __imp__MultiByteToWideChar@24 004241d4 kernel32:KERNEL32.dll 0004:000001d8 __imp__LCMapStringA@24 004241d8 kernel32:KERNEL32.dll 0004:000001dc __imp__LCMapStringW@24 004241dc kernel32:KERNEL32.dll 0004:000001e0 __imp__GetStringTypeA@20 004241e0 kernel32:KERNEL32.dll 0004:000001e4 __imp__GetStringTypeW@16 004241e4 kernel32:KERNEL32.dll 0004:000001e8 __imp__SetFilePointer@16 004241e8 kernel32:KERNEL32.dll 0004:000001ec __imp__SetStdHandle@8 004241ec kernel32:KERNEL32.dll 0004:000001f0 __imp__FlushFileBuffers@4 004241f0 kernel32:KERNEL32.dll 0004:000001f4 __imp__CloseHandle@4 004241f4 kernel32:KERNEL32.dll 0004:000001f8 177KERNEL32_NULL_THUNK_DATA 004241f8 kernel32:KERNEL32.dll entry point at 0001:000000f0 Line numbers for .DebugCrashDemo.obj(d:msdevmyprojectscrashdemocrashdemo.cpp) segment .text 13 0001:00000020 14 0001:00000038 15 0001:0000003f 16 0001:00000046 17 0001:00000050 20 0001:00000070 21 0001:00000088 22 0001:0000008d |
0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo.obj |
13 0001:00000020 |
崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000 |
崩溃行偏移 = 0x0040104a - 0x00400000 - 0x1000 = 0x4a |
16 0001:00000046 |
16 i /= j; |
首先配置vc2005生成map文件和cod文件:(1).map文件:property->Configuration Properties->Linker->Debugging 中的Generate Map File选择Yes(/MAP);
(2).cod文件:property->Configuration Properties->C/C++->output Files中Assembler OutPut中选择Assembly,Maching Code and Source(/FAcs),生成机器,源代码。
简单例子:
(1) #include "stdafx.h"
void errorFun(int * p)
{
*p=1;
}
int _tmain(int argc, _TCHAR* argv[])
{
int * p=NULL;
errorFun(p);
return
0;
}
在errorFun中函数中,*p=1这一行出错,由于p没有申请空间,运行时出错,弹出
Unhandled exception at 0x004113b1 in testError.exe: 0xC0000005: Access violation writing location 0x00000000.
在0x004113b1程序发生崩溃。
(2)debug文件下打开map文件,定位崩溃函数.
map文件开头是一些链接信息,然后我们要找函数和实始地址信息。地址是函始的开始地址
Address Publics by Value Rva+Base Lib:Object
0000:00000000 ___safe_se_handler_count 00000000
<absolute>
0000:00000000 ___safe_se_handler_table
00000000 <absolute>
0000:00000000
___ImageBase 00400000 <linker-defined>
0001:00000000
__enc$textbss$begin 00401000 <linker-defined>
0001:00010000
__enc$textbss$end 00411000 <linker-defined>
0002:00000390
?errorFun@@YAXPAH@Z
00411390 f testError.obj
0002:000003d0
_wmain 004113d0 f testError.obj
0002:00000430
__RTC_InitBase 00411430 f MSVCRTD:init.obj
0002:00000470
__RTC_Shutdown 00411470 f MSVCRTD:init.obj
0002:00000490
__RTC_CheckEsp 00411490 f MSVCRTD:stack.obj
0002:000004c0
@_RTC_CheckStackVars@8 004114c0 f MSVCRTD:stack.obj
0002:00000540
@_RTC_AllocaHelper@12 00411540 f MSVCRTD:stack.obj
....
程序崩溃地址0x004113b1,我们找到第一个比这个地址大的004113d0,前一个是00411390,地址是函数的开始地址,所以发生 的崩溃的的函数是errorFun,这个函数的初始地址00411390.
(3)找出具体崩溃行号.
由(2)可知,发生错误函数是errorFun,在testError.obj,打开testError.cod文件,找到errorFun函数生 成的机器码.
?errorFun@@YAXPAH@Z PROC ; errorFun, COMDAT
; 7 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81
ec c0 00 00
00 sub esp, 192 ; 000000c0H
00009 53 push
ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd
40 ff ff
ff lea edi, DWORD PTR [ebp-192]
00012 b9 30 00 00
00 mov ecx, 48 ; 00000030H
00017 b8 cc cc cc cc mov eax,
-858993460 ; ccccccccH
0001c f3 ab rep stosd
; 8 : *p=1;
0001e 8b 45 08 mov eax, DWORD PTR _p$[ebp]
00021 c7 00 01 00
00
00 mov DWORD PTR [eax], 1
; 9 : }
00027 5f pop edi
00028 5e pop esi
00029 5b pop
ebx
0002a 8b e5 mov esp, ebp
0002c 5d pop ebp
0002d c3 ret 0
(说明: 7,8,9是表示在源代码的行号。
00000 55 push ebp,000000是相对偏移地地,55是机器码号,push ebp,000000是汇编码。)
通过(2)我们计算相对偏移地址,即崩溃地址-函数起始地址,0x004113b1-0x00411390=0x21(16进制的计数)
找到0x21这一行对应的机器码是 00021 c7 00 01 00 00,向上看它是由第8行*p=1;生成的汇编码,由此可见是这一行程序发生崩溃。
结束语:当然这只是一个简单的例子,实际上一运行便知道是这一行出错,但是对于一个比较大的工程,特别是在多线程并发情况下,要找出那一行出错比 较困难,便可以使用map和cod文件找到程序崩溃原因。