admin 管理员组文章数量: 1184232
最近的工程在用vs2005进行调试, 现在可以Attach到Release版带调试符号的目标程序进行调试, 但是在非开发机上就没这条件了.
看了以下几篇资料, 做个实验.
Finding crash information using the MAP file <vc6版好使>
调试Release发布版程序的Crash错误 (转)<这个资料说全了, 可以在vs2005中做事后调试>
自己写了一个demo, 进行了验证, 可行. 但是没有实战性, 准备找个实际的程序来验证.
我在CodeProject 找了一个扫雷程序:
<<Adapted WinMine Source for Teaching Win32 API Programming>>
本来想搞个数组越界的错误,人家的程序写的太坚固了,弄了数组越界操作,也不报错。
只好弄了一个除零错~
编译选项是Release版不优化带调试符号,为了根据转储信息定位到代码中的行, 设置了MAPInfo和COD文件.
在Win7上程序报错是有崩溃对话框的, 但是我的WinXp上崩溃对话框没出来,只有一个报错对话框, 没有转储信息.
安装系统自带的drwtsn32.exe作为调试工具.
<<如何禁用或启用 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"
设置华生医生转储选项
再运行程序时,程序报错后,直接崩溃消失了。到那时,就可以从非开发机(大部分情况是客户现场)拿到转储信息转到开发机进行分析.
如果drwtsn32.exe设置了"视觉通知", 当程序报错时,会有转储提示对话框弹出.如果错误不是每次必现或在客户现场运行不用设置"视觉通知"选项.
如果不设置 "视觉通知", 程序报错后,直接退出了.这时可以去取程序报错时的转储信息。
将转储对话框中的文本全选,复制弄回来.
发生应用程序意外错误:
应用程序: 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 ..@.........t...
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 <.....@.h......w
000000000012fe08 d0 1f 40 00 48 06 06 00 - 02 02 00 00 00 00 00 00 ..@.H...........
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文件,转储信息文件放在一起,都打开,分析代码错误行.
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这么容易的判断是什么具体错误~.
如果有崩溃对话框弹出, 连华生医生也不用了,那时也有转储信息. 可以用来了解客户那的操作系统信息, 当时运行的程序(有没有杀毒软件之类的程序).
版权声明:本文标题:深入探讨:在VS2005中定位winmine.exe错误,从MAP文件开始 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1773370543a3561169.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论