experiment:Finding crash information using the MAP file on vs2005

最近的工程在用vs2005进行调试, 现在可以Attach到Release版带调试符号的目标程序进行调试, 但是在非开发机上就没这条件了.

看了以下几篇资料, 做个实验.

http://www.codeproject.com/KB/debug/mapfile.aspx?msg=1315494
Finding crash information using the MAP file <vc6版好使>

http://www.cppblog.com/Walker/articles/146153.html
调试Release发布版程序的Crash错误 (转)<这个资料说全了, 可以在vs2005中做事后调试>


自己写了一个demo, 进行了验证, 可行. 但是没有实战性, 准备找个实际的程序来验证.

我在CodeProject 找了一个扫雷程序:

http://www.codeproject.com/KB/cpp/Mine4Edu.aspx
<<Adapted WinMine Source for Teaching Win32 API Programming>>


本来想搞个数组越界的错误,人家的程序写的太坚固了,弄了数组越界操作,也不报错。

只好弄了一个除零错~

experiment:Finding crash information using the MAP file on vs2005_第1张图片

编译选项是Release版不优化带调试符号,为了根据转储信息定位到代码中的行, 设置了MAPInfo和COD文件.

experiment:Finding crash information using the MAP file on vs2005_第2张图片

experiment:Finding crash information using the MAP file on vs2005_第3张图片


在Win7上程序报错是有崩溃对话框的, 但是我的WinXp上崩溃对话框没出来,只有一个报错对话框, 没有转储信息.

experiment:Finding crash information using the MAP file on vs2005_第4张图片

安装系统自带的drwtsn32.exe作为调试工具.

http://support.microsoft.com/kb/188296/zh-cn
<<如何禁用或启用 Windows 的 Dr. Watson>>

默认调试器的注册表备份

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="1"
"Debugger"="drwtsn32 -p %ld -e %ld -g"



experiment:Finding crash information using the MAP file on vs2005_第5张图片

experiment:Finding crash information using the MAP file on vs2005_第6张图片

设置华生医生转储选项

experiment:Finding crash information using the MAP file on vs2005_第7张图片

再运行程序时,程序报错后,直接崩溃消失了。到那时,就可以从非开发机(大部分情况是客户现场)拿到转储信息转到开发机进行分析.

如果drwtsn32.exe设置了"视觉通知", 当程序报错时,会有转储提示对话框弹出.如果错误不是每次必现或在客户现场运行不用设置"视觉通知"选项.

experiment:Finding crash information using the MAP file on vs2005_第8张图片

如果不设置 "视觉通知", 程序报错后,直接退出了.这时可以去取程序报错时的转储信息。

experiment:Finding crash information using the MAP file on vs2005_第9张图片

experiment:Finding crash information using the MAP file on vs2005_第10张图片

experiment:Finding crash information using the MAP file on vs2005_第11张图片

将转储对话框中的文本全选,复制弄回来.

发生应用程序意外错误:
        应用程序: D:\LsPrj\subjectResearch\DebugAcrossMap\WinMine4Edu\Unicode Release\WinMine.exe (pid=3528)
        时间: 2011-12-26 @ 00:51:45.265
        意外情况编号: c0000094 (除以零)

*----> 系统信息 <----*
        计算机名: 20110616-2328
        用户名: Administrator
        终端会话 Id: 0
        处理器数量: 2
        处理器类型: x86 Family 6 Model 15 Stepping 6
        Windows 版本: 5.1
        当前内部版本号: 2600
        Service Pack: 3
        当前类型: Multiprocessor Free
        注册的单位: 微软中国
        注册的所有者: 微软用户

*----> 任务列表 <----*
   0 System Process
   4 System
 840 smss.exe
 908 csrss.exe
 932 winlogon.exe
 976 services.exe
 988 lsass.exe
1192 nvsvc32.exe
1252 svchost.exe
1300 svchost.exe
 252 svchost.exe
 484 svchost.exe
 584 svchost.exe
 620 zhudongfangyu.exe
1620 spoolsv.exe
1852 Explorer.EXE
1932 RTHDCPL.EXE
1948 360Tray.exe
2000 bjcacertd_ft11.exe
2016 vmware-tray.exe
2024 ctfmon.exe
 128 360sd.exe
 184 263em.exe
 288 Snagit32.exe
1728 TSCHelp.exe
 368 SnagPriv.exe
2004 snagiteditor.exe
1336 GSvr.exe
1384 wdfmgr.exe
1432 vmware-usbarbitrator.exe
 364 vmnat.exe
 700 vmnetdhcp.exe
1468 vmware-authd.exe
2168 wmiprvse.exe
2224 vmware-hostd.exe
2568 alg.exe
4000 360rp.exe
4072 firefox.exe
3452 NOTEPAD.EXE
3652 drwtsn32.exe
4080 drwtsn32.exe
3528 WinMine.exe
3036 drwtsn32.exe

*----> 模块清单 <----*
(0000000000400000 - 0000000000416000: D:\LsPrj\subjectResearch\DebugAcrossMap\WinMine4Edu\Unicode Release\WinMine.exe
(0000000000920000 - 000000000098d000: C:\Program Files\360\360Safe\safemon\safemon.dll
(000000005d170000 - 000000005d20a000: C:\WINDOWS\system32\comctl32.dll
(0000000062c20000 - 0000000062c29000: C:\WINDOWS\system32\LPK.DLL
(0000000071a10000 - 0000000071a18000: C:\WINDOWS\system32\WS2HELP.dll
(0000000071a20000 - 0000000071a37000: C:\WINDOWS\system32\WS2_32.dll
(0000000073640000 - 000000007366e000: C:\WINDOWS\system32\msctfime.ime
(0000000073fa0000 - 000000007400b000: C:\WINDOWS\system32\USP10.dll
(0000000074680000 - 00000000746cc000: C:\WINDOWS\system32\MSCTF.dll
(0000000075ff0000 - 0000000076055000: C:\WINDOWS\system32\MSVCP60.dll
(0000000076300000 - 000000007631d000: C:\WINDOWS\system32\IMM32.DLL
(00000000765e0000 - 0000000076673000: C:\WINDOWS\system32\CRYPT32.dll
(0000000076680000 - 0000000076726000: C:\WINDOWS\system32\WININET.dll
(0000000076990000 - 0000000076ace000: C:\WINDOWS\system32\ole32.dll
(0000000076bc0000 - 0000000076bcb000: C:\WINDOWS\system32\PSAPI.DLL
(0000000076d70000 - 0000000076d92000: C:\WINDOWS\system32\Apphelp.dll
(0000000076db0000 - 0000000076dc2000: C:\WINDOWS\system32\MSASN1.dll
(00000000770f0000 - 000000007717b000: C:\WINDOWS\system32\OLEAUT32.dll
(0000000077180000 - 0000000077283000: C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.6028_x-ww_61e65202\comctl32.dll
(0000000077bd0000 - 0000000077bd8000: C:\WINDOWS\system32\VERSION.dll
(0000000077be0000 - 0000000077c38000: C:\WINDOWS\system32\msvcrt.dll
(0000000077d10000 - 0000000077da0000: C:\WINDOWS\system32\USER32.dll
(0000000077da0000 - 0000000077e49000: C:\WINDOWS\system32\ADVAPI32.dll
(0000000077e50000 - 0000000077ee3000: C:\WINDOWS\system32\RPCRT4.dll
(0000000077ef0000 - 0000000077f39000: C:\WINDOWS\system32\GDI32.dll
(0000000077f40000 - 0000000077fb6000: C:\WINDOWS\system32\SHLWAPI.dll
(0000000077fc0000 - 0000000077fd1000: C:\WINDOWS\system32\Secur32.dll
(000000007c800000 - 000000007c91e000: C:\WINDOWS\system32\kernel32.dll
(000000007c920000 - 000000007c9b6000: C:\WINDOWS\system32\ntdll.dll
(000000007d590000 - 000000007dd84000: C:\WINDOWS\system32\SHELL32.dll

*----> 线程 ID 0xcc0 的状态转储 <----*

eax=00000006 ebx=00000000 ecx=0012fd10 edx=00000000 esi=00401fd0 edi=0012fe3c
eip=00401761 esp=0012fd48 ebp=0012fd54 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216

*** ERROR: Module load completed but symbols could not be loaded for D:\LsPrj\subjectResearch\DebugAcrossMap\WinMine4Edu\Unicode Release\WinMine.exe
函数: WinMine
        00401749 7423             jz      WinMine+0x176e (0040176e)
        0040174b 6a03             push    0x3
        0040174d 8b450c           mov     eax,[ebp+0xc]
        00401750 50               push    eax
        00401751 8b4d08           mov     ecx,[ebp+0x8]
        00401754 51               push    ecx
        00401755 e8b6060000       call    WinMine+0x1e10 (00401e10)
        0040175a 83c40c           add     esp,0xc
        0040175d 8b4508           mov     eax,[ebp+0x8]
        00401760 99               cdq
错误 ->00401761 f77d0c           idiv  dword ptr [ebp+0xc] ss:0023:0012fd60=00000000
        00401764 894508           mov     [ebp+0x8],eax
        00401767 33c0             xor     eax,eax
        00401769 e9be000000       jmp     WinMine+0x182c (0040182c)
        0040176e 8b15e8c84000     mov     edx,[WinMine+0xc8e8 (0040c8e8)]
        00401774 83c201           add     edx,0x1
        00401777 8915e8c84000     mov     [WinMine+0xc8e8 (0040c8e8)],edx
        0040177d 8b450c           mov     eax,[ebp+0xc]
        00401780 50               push    eax
        00401781 8b4d08           mov     ecx,[ebp+0x8]
        00401784 51               push    ecx

*----> 堆栈反向跟踪 <---*
WARNING: Stack unwind information not available. Following frames may be wrong.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\USER32.dll - 
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
ChildEBP RetAddr  Args to Child              
0012fd54 0040118f 00000006 00000000 00000006 WinMine+0x1761
0012fd74 004020d7 00000202 00a30012 000000ef WinMine+0x118f
0012fdd4 77d18734 00060648 00000202 00000000 WinMine+0x20d7
0012fe00 77d18816 00401fd0 00060648 00000202 USER32!GetDC+0x6d
0012fe68 77d189cd 00000000 00401fd0 00060648 USER32!GetDC+0x14f
0012fec8 77d18a10 0012ff0c 00000000 0012ff28 USER32!GetWindowLongW+0x127
0012fed8 00401fb4 0012ff0c 00000000 00401fd0 USER32!DispatchMessageW+0xf
0012ff28 00402e78 00400000 00000000 000207e0 WinMine+0x1fb4
0012ffc0 7c817077 0065002e 00650078 7ffdf000 WinMine+0x2e78
0012fff0 00000000 00402ee1 00000000 78746341 kernel32!RegisterWaitForInputIdle+0x49

*----> 原始堆栈转储 <----*
000000000012fd48  bc 13 40 00 06 00 00 00 - 00 00 00 00 74 fd 12 00  [email protected]...
000000000012fd58  8f 11 40 00 06 00 00 00 - 00 00 00 00 06 00 00 00  ..@.............
000000000012fd68  12 00 00 00 a3 00 00 00 - 00 00 00 00 d4 fd 12 00  ................
000000000012fd78  d7 20 40 00 02 02 00 00 - 12 00 a3 00 ef 00 00 00  . @.............
000000000012fd88  68 01 00 00 30 02 00 00 - 48 06 06 00 01 00 00 00  h...0...H.......
000000000012fd98  b0 fd 12 00 01 b4 d2 77 - 58 03 62 00 00 00 00 00  .......wX.b.....
000000000012fda8  00 00 00 00 01 00 00 00 - f4 fd 12 00 d4 13 69 74  ..............it
000000000012fdb8  ee 00 03 00 00 00 00 00 - 01 00 00 00 d9 13 69 74  ..............it
000000000012fdc8  00 00 00 00 00 e0 fd 7f - ac 98 96 db 00 fe 12 00  ................
000000000012fdd8  34 87 d1 77 48 06 06 00 - 02 02 00 00 00 00 00 00  4..wH...........
000000000012fde8  12 00 a3 00 d0 1f 40 00 - cd ab ba dc 00 00 00 00  ......@.........
000000000012fdf8  3c fe 12 00 d0 1f 40 00 - 68 fe 12 00 16 88 d1 77  <[email protected]
000000000012fe08  d0 1f 40 00 48 06 06 00 - 02 02 00 00 00 00 00 00  [email protected]...........
000000000012fe18  12 00 a3 00 14 ff 12 00 - 0c ff 12 00 a8 64 67 00  .............dg.
000000000012fe28  14 00 00 00 01 00 00 00 - 00 00 00 00 00 00 00 00  ................
000000000012fe38  10 00 00 00 00 00 00 00 - 8f 04 d4 77 00 00 00 00  ...........w....
000000000012fe48  00 00 00 00 00 00 00 00 - 1c fe 12 00 74 f9 12 00  ............t...
000000000012fe58  b8 fe 12 00 8f 04 d4 77 - 30 88 d1 77 00 00 00 00  .......w0..w....
000000000012fe68  c8 fe 12 00 cd 89 d1 77 - 00 00 00 00 d0 1f 40 00  .......w......@.
000000000012fe78  48 06 06 00 02 02 00 00 - 00 00 00 00 12 00 a3 00  H...............

*----> 符号表 <----*
D:\LsPrj\subjectResearch\DebugAcrossMap\WinMine4Edu\Unicode Release\WinMine.exe

在转储信息中,可以看到报错的地址.

错误 ->00401761 f77d0c           idiv  dword ptr [ebp+0xc] ss:0023:0012fd60=00000000
将编译这个程序时产生的.map文件,.cod文件,转储信息文件放在一起,都打开,分析代码错误行.

experiment:Finding crash information using the MAP file on vs2005_第12张图片

map文件中看到程序的基址 = 0x400000

Preferred load address is 00400000

报错地址0x401761附近的函数名称如下:

Address         Publics by Value              Rva+Base       Lib:Object

 0001:000004c0       _GameWon                   004014c0 f   MineGame.obj
 0001:00000570       _GameLost                  00401570 f   MineGame.obj
 0001:00000650       _CountMines                00401650 f   MineGame.obj
 0001:000006f0       _StepBox                   004016f0 f   MineGame.obj
 0001:00000830       _FillRectStockBrush        00401830 f   MinePaint.obj
 0001:00000870       _DrawMargin                00401870 f   MinePaint.obj
 0001:000008b0       _DrawBorder                004018b0 f   MinePaint.obj
计算包含0x401761地址的函数

_StepBox 0x400000 + 0x1000 + 0x6f0 = 0x4016f0

0x401761 报错的代码行

_FillRectStockBrush 0x400000 + 0x1000 + 0x830 = 0x401830

可以看到 0x401761地址在函数_StepBox和_FillRectStockBrush之间, 说明代码中出错的位置在_StepBox函数中~

从转储信息中计算出错位置离函数入口的偏移:

*** ERROR: Module load completed but symbols could not be loaded for D:\LsPrj\subjectResearch\DebugAcrossMap\WinMine4Edu\Unicode Release\WinMine.exe
函数: WinMine
        00401749 7423             jz      WinMine+0x176e (0040176e)
        0040174b 6a03             push    0x3
        0040174d 8b450c           mov     eax,[ebp+0xc]
        00401750 50               push    eax
        00401751 8b4d08           mov     ecx,[ebp+0x8]
        00401754 51               push    ecx
        00401755 e8b6060000       call    WinMine+0x1e10 (00401e10)
        0040175a 83c40c           add     esp,0xc
        0040175d 8b4508           mov     eax,[ebp+0x8]
        00401760 99               cdq
错误 ->00401761 f77d0c           idiv  dword ptr [ebp+0xc] ss:0023:0012fd60=00000000
        00401764 894508           mov     [ebp+0x8],eax

出错位置离函数入口的偏移(报错地址-_StepBox入口地址) = 0x00401761 - 0x4016f0 = 0x71

从包含_StepBox函数的MineGame.cod中找到离_StepBox入口偏移为0x71的代码行:

_TranslateMouseMsg ENDP
_TEXT	ENDS
PUBLIC	_GameLost
PUBLIC	_GameWon
PUBLIC	_StepBox

;	COMDAT _StepBox
_TEXT	SEGMENT
_r$78102 = -12						; size = 4
_c$78103 = -8						; size = 4
_cMinesSurround$ = -4					; size = 4
_row$ = 8						; size = 4
_col$ = 12						; size = 4
_StepBox PROC						; COMDAT

; 282  : {

  00000	55		 push	 ebp
  00001	8b ec		 mov	 ebp, esp
  00003	83 ec 0c	 sub	 esp, 12			; 0000000cH

; 283  :     UINT cMinesSurround;
; 284  : 
; 285  :     if (board.Box[row][col].State != BS_INITIAL && 
; 286  :         board.Box[row][col].State != BS_DICEY)

  00006	8b 45 08	 mov	 eax, DWORD PTR _row$[ebp]
  00009	6b c0 78	 imul	 eax, 120		; 00000078H
  0000c	8b 4d 0c	 mov	 ecx, DWORD PTR _col$[ebp]
  0000f	8b 94 88 b8 00
	00 00		 mov	 edx, DWORD PTR _board[eax+ecx*4+184]
  00016	c1 e2 1a	 shl	 edx, 26			; 0000001aH
  00019	c1 fa 1b	 sar	 edx, 27			; 0000001bH
  0001c	74 25		 je	 SHORT $LN11@StepBox
  0001e	8b 45 08	 mov	 eax, DWORD PTR _row$[ebp]
  00021	6b c0 78	 imul	 eax, 120		; 00000078H
  00024	8b 4d 0c	 mov	 ecx, DWORD PTR _col$[ebp]
  00027	8b 94 88 b8 00
	00 00		 mov	 edx, DWORD PTR _board[eax+ecx*4+184]
  0002e	c1 e2 1a	 shl	 edx, 26			; 0000001aH
  00031	c1 fa 1b	 sar	 edx, 27			; 0000001bH
  00034	83 fa 02	 cmp	 edx, 2
  00037	74 0a		 je	 SHORT $LN11@StepBox

; 287  :     {
; 288  :         // previously stepped, must be safe, and no need to step second time
; 289  :         return TRUE;

  00039	b8 01 00 00 00	 mov	 eax, 1
  0003e	e9 f9 00 00 00	 jmp	 $LN12@StepBox
$LN11@StepBox:

; 290  :     }
; 291  : 
; 292  :     if (board.Box[row][col].fMine)

  00043	8b 45 08	 mov	 eax, DWORD PTR _row$[ebp]
  00046	6b c0 78	 imul	 eax, 120		; 00000078H
  00049	8b 4d 0c	 mov	 ecx, DWORD PTR _col$[ebp]
  0004c	8b 94 88 b8 00
	00 00		 mov	 edx, DWORD PTR _board[eax+ecx*4+184]
  00053	c1 e2 1f	 shl	 edx, 31			; 0000001fH
  00056	c1 fa 1f	 sar	 edx, 31			; 0000001fH
  00059	74 23		 je	 SHORT $LN10@StepBox

; 293  :     {
; 294  :         // stepped on a mine!
; 295  :         SetAndDispBoxState(row, col, BS_BLAST);

  0005b	6a 03		 push	 3
  0005d	8b 45 0c	 mov	 eax, DWORD PTR _col$[ebp]
  00060	50		 push	 eax
  00061	8b 4d 08	 mov	 ecx, DWORD PTR _row$[ebp]
  00064	51		 push	 ecx
  00065	e8 00 00 00 00	 call	 _SetAndDispBoxState
  0006a	83 c4 0c	 add	 esp, 12			; 0000000cH

; 296  : 
; 297  : 		/** 制造一个BUG, 踩了雷程序就报错, 数组越界
; 298  : 		* 程序编译选项不选优化, 否则这里制造的BUG就被干掉了
; 299  : 		*/
; 300  : 		row = row / col;/**< 零列出现雷的时候报除零错 */

  0006d	8b 45 08	 mov	 eax, DWORD PTR _row$[ebp]
  00070	99		 cdq
  00071	f7 7d 0c	 idiv	 DWORD PTR _col$[ebp]
  00074	89 45 08	 mov	 DWORD PTR _row$[ebp], eax

; 301  : 
; 302  :         return FALSE;

  00077	33 c0		 xor	 eax, eax
  00079	e9 be 00 00 00	 jmp	 $LN12@StepBox
$LN10@StepBox:

; 303  :     }
; 304  : 

离入口偏移为0x71的行找到了,果真是一句除零~.

  00071	f7 7d 0c	 idiv	 DWORD PTR _col$[ebp]
这句汇编对应的代码上就在他的上面:  row = row / col;/**< 零列出现雷的时候报除零错 */

; 300  : 		row = row / col;/**< 零列出现雷的时候报除零错 */

  0006d	8b 45 08	 mov	 eax, DWORD PTR _row$[ebp]
  00070	99		 cdq
  00071	f7 7d 0c	 idiv	 DWORD PTR _col$[ebp]
  00074	89 45 08	 mov	 DWORD PTR _row$[ebp], eax

好, 已经找到报错的代码行了。

如果是在开发机上, 就直接可以在Release版不优化带调试符号的工程上单步了.

如果没有条件单步,在报错的代码上上,用调试日志记录关心的上下文,问题就能解决了。


这个扫雷游戏做的太坚固了,还没想到弄个别的非除零错之外的不明显的BUG来找找看.

以后在实际工程中再验证,那时就不会让drwtsn32这么容易的判断是什么具体错误~.


如果有崩溃对话框弹出, 连华生医生也不用了,那时也有转储信息. 可以用来了解客户那的操作系统信息, 当时运行的程序(有没有杀毒软件之类的程序).










你可能感兴趣的:(c,windows,File,Microsoft,System,Crash)