[ Main Page ]

Windows Debug tips

Runtime Debugger (JIT debugger)

レジストリで設定する。Debugger_*は例なので、Debuggerキーに変える。

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="0"
"Debugger_DrWatson"="drwtsn32 -p %ld -e %ld -g"
"Debugger_Olly"="\"C:\\Program Files\\usr\\OllyDbg\\OLLYDBG.EXE\" -AEDEBUG %ld %ld"
"Debugger_GDB"="C:\\MinGW\\bin\\gdb.exe --pid=%ld"
"Debugger"="drwtsn32 -p %ld -e %ld -g"

sprintfっぽい文法です。

Dr. Watson (Windows付属)

drwtsn32 -i

で設定。

C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson\drwtsn32.log
C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson\user.dmp

OllyDebug

"C:\Program Files\OllyDbg\OLLYDBG.EXE" -AEDEBUG %ld %ld

で設定。V2系列では、OllyDebugの設定から行える。

GDB

C:\\MinGW\\bin\\gdb.exe --pid=%ld

いくつかの理由(ntdll内RaiseExceptionとか)により、トラップ時にはまず使い物にならない。 MinGWビルドでなおかつgdbではじめから走らせる場合はそうでもないようだが。

デバッグの実際

foobar2000など、例外時にログとミニダンプを残すものがある。それらも含めて簡単に見てみる。

Dr. Watson

Windows標準でついてきますし、意外に使えます。

例: Freeverb3_Impulser2.dll (VST plugin) SOL2上でデバッグ中に例外が発生。

わかっているので、先に述べておくと、原因は、classをインライン化したためにメンバ関数の オフセット/スタックがalignment不定となっておきるようになったSSE movapsのalignmentエラーによるもので、 MinGW 4.1以降で採用された__attribute__((force_align_arg_pointer))をclass宣言時に使用するようにして解決しました。

C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson\drwtsn32.log

にどんどん追加される設定だと探すのがちょっと面倒かもしれません。フォールト ->という部分を 探せば原因がわかります。

	*----> スレッド Id 0xa00 の状態のダンプ  <----*
	
	eax=00000000 ebx=012eba80 ecx=000001e0 edx=00000000 esi=012ebb08 edi=012ebaa4
	eip=66a6c233 esp=0289fb1c ebp=0289fb94 iopl=0         nv up ei pl nz na pe nc
	cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
	
	*** ERROR: Symbol file could not be found.  Defaulted to export symbols for \
	C:\Program Files\YAMAHA\Vstplugins\Wind\Freeverb3VST_Impulser2.dll - 
	ファンクション: Freeverb3VST_Impulser2
        66a6c20c 90               nop
        66a6c20d 90               nop
        66a6c20e 90               nop
        66a6c20f 90               nop
        66a6c210 0f57c0           xorps   xmm0,xmm0
        66a6c213 c783bc00000000000000 mov dword ptr [ebx+0xbc],0x0
        66a6c21d 0f2e83b4000000   ucomiss xmm0,dword ptr [ebx+0xb4]
        66a6c224 f30f100d689dbd66 movssx xmm1,dword ptr [Freeverb3VST_Impulser2+0x399d68 (66bd9d68)]
        66a6c22c 727b             jb      Freeverb3VST_Impulser2+0x22c2a9 (66a6c2a9)
        66a6c22e f30f1155b8       movssx  dword ptr [ebp-0x48],xmm2
	フォールト ->66a6c233 0f295dc8 movaps oword ptr [ebp-0x38],xmm3 \
	ss:0023:0289fb5c=7c8024b77c94da2a0000000300000180
        66a6c237 f30f1165a8       movssx  dword ptr [ebp-0x58],xmm4
        66a6c23c f30f110424       movssx  dword ptr [esp],xmm0
        66a6c241 e8ca710000       call    Freeverb3VST_Impulser2+0x233410 (66a73410)
        66a6c246 d95da4           fstp    dword ptr [ebp-0x5c]
        66a6c249 f30f106da4       movssx  xmm5,dword ptr [ebp-0x5c]
        66a6c24e f30f1083c0000000 movssx  xmm0,dword ptr [ebx+0xc0]
        66a6c256 f30f108bc4000000 movssx  xmm1,dword ptr [ebx+0xc4]
        66a6c25e 0f28f5           movaps  xmm6,xmm5
        66a6c261 f30f5ef0         divss   xmm6,xmm0
        66a6c265 f30f59c8         mulss   xmm1,xmm0

	≪以降はobjdump -Sで得られる内容で、静的なコードなら↑と同じはずです。≫
	≪c++filtを通すと、C++ demangleできます。≫
	
	66a6c20f:       90                      nop
	66a6c210:       0f 57 c0                xorps  %xmm0,%xmm0
	66a6c213:       c7 83 bc 00 00 00 00    movl   $0x0,0xbc(%ebx)
	66a6c21a:       00 00 00
	66a6c21d:       0f 2e 83 b4 00 00 00    ucomiss 0xb4(%ebx),%xmm0
	66a6c224:       f3 0f 10 0d 68 9d bd    movss  0x66bd9d68,%xmm1
	66a6c22b:       66
	66a6c22c:       72 7b                   jb     66a6c2a9 \
	<__ZN3fv312limitmodel_f14processreplaceEPfS1_S1_S1_l+0x449>
	66a6c22e:       f3 0f 11 55 b8          movss  %xmm2,-0x48(%ebp)
	66a6c233:       0f 29 5d c8             movaps %xmm3,-0x38(%ebp)
	66a6c237:       f3 0f 11 65 a8          movss  %xmm4,-0x58(%ebp)
	66a6c23c:       f3 0f 11 04 24          movss  %xmm0,(%esp)
	66a6c241:       e8 ca 71 00 00          call   66a73410 <_logf>
	66a6c246:       d9 5d a4                fstps  -0x5c(%ebp)
	66a6c249:       f3 0f 10 6d a4          movss  -0x5c(%ebp),%xmm5
	66a6c24e:       f3 0f 10 83 c0 00 00    movss  0xc0(%ebx),%xmm0
	66a6c255:       00
	66a6c256:       f3 0f 10 8b c4 00 00    movss  0xc4(%ebx),%xmm1
	66a6c25d:       00
	66a6c25e:       0f 28 f5                movaps %xmm5,%xmm6
	66a6c261:       f3 0f 5e f0             divss  %xmm0,%xmm6
	66a6c265:       f3 0f 59 c8             mulss  %xmm0,%xmm1
	66a6c269:       f3 0f 10 83 c8 00 00    movss  0xc8(%ebx),%xmm0
	66a6c270:       00
	66a6c271:       f3 0f 58 c6             addss  %xmm6,%xmm0
	66a6c275:       f3 0f 5e c8             divss  %xmm0,%xmm1
	66a6c279:       f3 0f 10 83 cc 00 00    movss  0xcc(%ebx),%xmm0
	66a6c280:       00
	66a6c281:       f3 0f 5c c1             subss  %xmm1,%xmm0
	66a6c285:       f3 0f 5c c5             subss  %xmm5,%xmm0
	66a6c289:       f3 0f 11 04 24          movss  %xmm0,(%esp)
	66a6c28e:       e8 ad 71 00 00          call   66a73440 <_expf>
	66a6c293:       f3 0f 10 65 a8          movss  -0x58(%ebp),%xmm4
	66a6c298:       f3 0f 10 55 b8          movss  -0x48(%ebp),%xmm2
	66a6c29d:       0f 28 5d c8             movaps -0x38(%ebp),%xmm3
	66a6c2a1:       d9 5d a4                fstps  -0x5c(%ebp)
	66a6c2a4:       f3 0f 10 4d a4          movss  -0x5c(%ebp),%xmm1
	66a6c2a9:       0f 2e e1                ucomiss %xmm1,%xmm4
	66a6c2ac:       0f 86 ae 02 00 00       jbe    66a6c560 \
	<__ZN3fv312limitmodel_f14processreplaceEPfS1_S1_S1_l+0x700>
	66a6c2b2:       f3 0f 11 8b 14 01 00    movss  %xmm1,0x114(%ebx)
    

ebp=0289fb94で、movaps %xmm3,-0x38(%ebp)だと、アクセス先である289EB5Cはalignment不整合なので、 Segmentation Faultになります。movupsだとOKなんですがね。

foobar2000

foobar2000\crash reportsにlog(Log)とdmp(User Mini Dump)が残る。

例1: Freeverb3_Impulser2.dll (VST plugin) LOG

結論から言うと、明示的に認められるまで解放してはいけないクラスを 不定の状態にしたままVST構造体内に保持していた上に、ポインタへのポインタを 書くべきところをただのポインタと間違って書いていたために、突然のアクセスによって Segmentation Faultとなったものです。ちょっとわかりにくいです。ログの大事なところは下の通りです。

	Illegal operation:
	Code: C0000005h, flags: 00000000h, address: 77BF60B4h
	Access violation, operation: write, address: 6687C2DDh

	Registers:
	EAX: 6687C2DD, EBX: 6687C240, ECX: 66B8AA1B, EDX: 00395E20
	ESI: 00000002, EDI: 6687C2DD, EBP: 02E2F6B0, ESP: 02E2F690

	Crash location:
	Module: msvcrt
	Offset: 360B4h
	Symbol: "strcat" (+74h)

	Stack dump analysis:
	Address: 668449A3h (Freeverb3VST_Impulser2+49A3h)
	Address: 6687C2DDh (Freeverb3VST_Impulser2+3C2DDh)
	Address: 66B8AA1Ah (Freeverb3VST_Impulser2+34AA1Ah)
    

残念ながら、MinGWシンボルはWindows非互換なので、objdump -Sなりで見つかる関数のアドレス をソースと対応させる作業が必要になります。Visual C++だとそんな必要はないです。 foobar2000はダンプファイル(*.dmp)も残してくれるので、使ってみましょう。WinDBGで読み込めます。 Disassemblyでコードを見られます。msvcrt内で起きたので、MSVCRTのバグかと 誤認するかもしれませんが、そうではありません。

	77bf60a5 f7c103000000    test    ecx,3
	77bf60ab 7419            je      msvcrt!strcat+0x86 (77bf60c6)
	77bf60ad 8a11            mov     dl,byte ptr [ecx]
	77bf60af 41              inc     ecx
	77bf60b0 84d2            test    dl,dl
	77bf60b2 7464            je      msvcrt!strcat+0xd8 (77bf6118)
	77bf60b4 8817            mov     byte ptr [edi],dl
	77bf60b6 47              inc     edi
	77bf60b7 f7c103000000    test    ecx,3
	77bf60bd 75ee            jne     msvcrt!strcat+0x6d (77bf60ad)
	77bf60bf eb05            jmp     msvcrt!strcat+0x86 (77bf60c6)
	77bf60c1 8917            mov     dword ptr [edi],edx
	77bf60c3 83c704          add     edi,4
	77bf60c6 bafffefe7e      mov     edx,7EFEFEFFh
	77bf60cb 8b01            mov     eax,dword ptr [ecx]
	77bf60cd 03d0            add     edx,eax
    

77bf60b4でediに書き込むのですが、その書き込み先は6687C2DDで、 関数のオフセットで、あからさまにおかしいですね。&(アドレス演算子)を足して解決しました。 関数の型チェックは重要です。

例2: Freeverb3_WindCompressor.dll (VST plugin) LOG

結論から言うと、上の方でのべたSSE alignmentエラーと同じです。重要なところはWinDBGを含めて以下の通りです。

	Illegal operation:
	Code: C0000005h, flags: 00000000h, address: 64B6AEF8h
	Access violation, operation: read, address: FFFFFFFFh

	Registers:
	EAX: 00000001, EBX: 040503B0, ECX: 0012F390, EDX: 7C94E514
	ESI: 040503EC, EDI: 040503B0, EBP: 0012F490, ESP: 0012F408
	
	Crash location:
	Module: Freeverb3VST_WindCompressor
	Offset: 22AEF8h

	Loaded modules:
	(中略)
	Freeverb3VST_WindCompressor      loaded at 64940000h - 64E22000h

	Stack dump analysis:
	Address: 6497B681h (Freeverb3VST_WindCompressor+3B681h)
	Address: 77EDED69h (GDI32+ED69h), symbol: "CreateFontIndirectA" (+46h)
    
	WinDBG Disassembly 64940000+22AEF8 (=OffsetとDllのロードアドレスで計算)

	64b6aebe e88d88e0ff      call    Freeverb3VST_WindCompressor+0x33750 (64973750)
	64b6aec3 8b83ac000000    mov     eax,dword ptr [ebx+0ACh]
	64b6aec9 8b550c          mov     edx,dword ptr [ebp+0Ch]
	64b6aecc 89442404        mov     dword ptr [esp+4],eax
	64b6aed0 891424          mov     dword ptr [esp],edx
	64b6aed3 e8a887e0ff      call    Freeverb3VST_WindCompressor+0x33680 (64973680)
	64b6aed8 0f57c0          xorps   xmm0,xmm0
	64b6aedb c745c000000000  mov     dword ptr [ebp-40h],0
	64b6aee2 c745cc00000000  mov     dword ptr [ebp-34h],0
	64b6aee9 8db42600000000  lea     esi,[esi]
	64b6aef0 f30f100d4828c764 movss   xmm1,dword ptr [Freeverb3VST_WindCompressor+0x332848 (64c72848)]
	ここ≫64b6aef8 0f2945a8        movaps  xmmword ptr [ebp-58h],xmm0
	64b6aefc f30f594dcc      mulss   xmm1,dword ptr [ebp-34h]
	64b6af01 f30f5c0d3c28c764 subss   xmm1,dword ptr [Freeverb3VST_WindCompressor+0x33283c (64c7283c)]
	64b6af09 f30f110c24      movss   dword ptr [esp],xmm1
	64b6af0e f30f114d98      movss   dword ptr [ebp-68h],xmm1
	64b6af13 e858f3ddff      call    Freeverb3VST_WindCompressor+0xa270 (6494a270)
	64b6af18 f30f104d98      movss   xmm1,dword ptr [ebp-68h]
	64b6af1d f30f110c24      movss   dword ptr [esp],xmm1
	64b6af22 d95dd0          fstp    dword ptr [ebp-30h]
	64b6af25 e846f3ddff      call    Freeverb3VST_WindCompressor+0xa270 (6494a270)
	64b6af2a 0f2845a8        movaps  xmm0,xmmword ptr [ebp-58h]
	64b6af2e d95d94          fstp    dword ptr [ebp-6Ch]
	64b6af31 f30f105594      movss   xmm2,dword ptr [ebp-6Ch]
	64b6af36 0f28ca          movaps  xmm1,xmm2
	64b6af39 0f540d5028c764  andps   xmm1,xmmword ptr [Freeverb3VST_WindCompressor+0x332850 (64c72850)]
	64b6af40 0f2f0d6028c764  comiss  xmm1,dword ptr [Freeverb3VST_WindCompressor+0x332860 (64c72860)]
    

計算すると、alignmentがあいませんね。これも先ほど同じ解法で解決しました。

その他

エラーの箇所がわかっても、その原因の場所が異なっていたりして、気付くまでは結構骨がおれるものです。 Windowsバイナリは特別の理由がないかぎりVC++でビルドしたほうがよいですね。MinGWを使っていると、 例外をDLL外に出してはいけなくなったり、DLL間ではExceptionはやりとりできなくなったり(正確には、 共有ライブラリを利用すればできないことはないけれど、ユーザにインストールさせるのが面倒だとか)だとか、 重箱の隅的な内容が増えてしまいます。

リンク

OllyDbg Q&A (Digital Travesia)

Digital Travesia 〜 でじたる とらべしあ 〜 推薦図書/パッケージソフト一覧

速習講座: クラッシュを分析してアプリケーションにおけるセキュリティの脆弱性を検出する

コードの臭い - Wikipedia

Wizard Bible

Question: if a website crashes in the middle of the night and there are no
support people to roll in the crash cart, will anyone hear it play
C:\WINNT\Media\Windows 2003 Critical Stop.wav to call the nurse, or does it
wait till morning for the doctors' rounds?

    -- Ira Abramov
    -- Linux-IL Message: "Re: Bank Leumi site finalls works from Linux" ( http://www.mail-archive.com/linux-il@cs.huji.ac.il/msg54167.html )

Q:	Are we not men?
A:	We are Vaxen.


Powered by UNIX fortune(6)
[ Main Page ]