Windows程式調試器 – WinDbg

來源:互聯網
上載者:User

windbg是一個強大win平台上的調試工具,現在介紹一下它的準系統。

加入要偵錯工具代碼debugee.cpp如下:

// debugee.cpp : Defines the entry point for the console application.//#include "stdafx.h"void loop(void){for (int i = 0; i < 1000; i ++){printf("loop [%d]\n", i);}}int main(int argc, char* argv[]){printf("Hello World!\n");loop();return 0;}

===============================================================

斷點

===============================================================

設定符號斷點,如果正確載入了符號表檔案(-y 指定, 或者ctrl+s)。

bm debugee!main

在main函數入口的位置設定斷點,用用tab鍵看看,還有提示哦。

在源檔案的行號上設定斷點,如果正確指定了源檔案路徑(-srcpath指定,或者ctrl+p)

bp `debugee.cpp:10` 

bp `:10`

條件斷點指令, 當i=500的時候停止,否則從斷點開始繼續執行gc:

bp `debugee.cpp:10` "j (poi(i)=500) ' ' ;  'gc' "

執行到800以上的時候停止

bp `debugee.cpp:10` "j (poi(i)>0n800) ' ' ;  'gc' "


硬體資料斷點,很酷的功能哦(真正的硬體斷點有個數限制,cpu的dr寄存器個數)

在變數i的記憶體位置開始寫入4個位元組大小的時候,斷點

ba w 4 i

在變數i的記憶體位置開始讀取4個位元組大小的時候,斷點

ba r 4 i

指令斷點

先u一段loop函數的反組譯碼看看

0:000> u debugee!loopdebugee!loop [H:\temp\debugee\debugee.cpp @ 7]:0040d6f0 55              push    ebp0040d6f1 8bec            mov     ebp,esp0040d6f3 83ec44          sub     esp,44h0040d6f6 53              push    ebx0040d6f7 56              push    esi0040d6f8 57              push    edi0040d6f9 8d7dbc          lea     edi,[ebp-44h]0040d6fc b911000000      mov     ecx,11h0:000> udebugee!loop+0x11 [H:\temp\debugee\debugee.cpp @ 7]:0040d701 b8cccccccc      mov     eax,0CCCCCCCCh0040d706 f3ab            rep stos dword ptr es:[edi]0040d708 c745fc00000000  mov     dword ptr [ebp-4],00040d70f eb09            jmp     debugee!loop+0x2a (0040d71a)0040d711 8b45fc          mov     eax,dword ptr [ebp-4]0040d714 83c001          add     eax,10040d717 8945fc          mov     dword ptr [ebp-4],eax0040d71a 817dfce8030000  cmp     dword ptr [ebp-4],3E8h0:000> udebugee!loop+0x31 [H:\temp\debugee\debugee.cpp @ 8]:0040d721 7d13            jge     debugee!loop+0x46 (0040d736)0040d723 8b4dfc          mov     ecx,dword ptr [ebp-4]0040d726 51              push    ecx0040d727 681c204200      push    offset debugee!`string' (0042201c)0040d72c e82f39ffff      call    debugee!printf (00401060)0040d731 83c408          add     esp,80040d734 ebdb            jmp     debugee!loop+0x21 (0040d711)0040d736 5f              pop     edi0:000> udebugee!loop+0x47 [H:\temp\debugee\debugee.cpp @ 12]:0040d737 5e              pop     esi0040d738 5b              pop     ebx0040d739 83c444          add     esp,44h0040d73c 3bec            cmp     ebp,esp0040d73e e89d39ffff      call    debugee!_chkesp (004010e0)0040d743 8be5            mov     esp,ebp0040d745 5d              pop     ebp0040d746 c3              ret

好的,接下來在,調用printf的時候給它斷住。

bc * 

ba e 1 0x0040d72c 
注意:ba e指令斷點的時候,位元組限制必須是1,

===============================================================

語句控制

===============================================================

執行一句,遇到函數,飛過去,相當於gdb的next,vc的f10

執行一句,遇到函數,跟進去,相當於gdb的step,vc的f11

t

執行到一個ret語句停止,一般用來完成一個子函數, 執行到子函數即將返回的位置

pt 或者tt 區別是如果當前是ret指令怎麼辦

執行到下一個call指令

pc

0:000> pceax=cccccccc ebx=7ffdd000 ecx=00000000 edx=003710d8 esi=00000000 edi=0012ff70eip=004010d6 esp=0012ff20 ebp=0012ff80 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206>   19: printf("Hello World!\n");debugee!main+0x36:004010d6 e875000000      call    debugee!printf (00401150)0:000> udebugee!main+0x36 [H:\temp\debugee\debugee.cpp @ 19]:004010d6 e875000000      call    debugee!printf (00401150)004010db 83c404          add     esp,4004010de c745fc00000000  mov     dword ptr [ebp-4],0004010e5 e820ffffff      call    debugee!ILT+5(?loopYAXXZ) (0040100a)004010ea eb13            jmp     debugee!main+0x5f (004010ff)004010ec 682c504200      push    offset debugee!`string' (0042502c)004010f1 e85a000000      call    debugee!printf (00401150)004010f6 83c404          add     esp,4

從子函數中執行到調用子函數語句的下一句位置 go up

gu

在子函數的開始位置執行wt, 顯示子函數的所有執行路徑,最後給出統計資訊

wt

   34     0 [  4]         debugee!write_char   70    68 [  3]       debugee!write_string   34     0 [  4]         debugee!write_char   84   102 [  3]       debugee!write_string  742   520 [  2]     debugee!_output   34     0 [  3]       debugee!write_char  789   554 [  2]     debugee!_output   34     0 [  3]       debugee!write_char  808   588 [  2]     debugee!_output   29  1469 [  1]   debugee!printf    7     0 [  2]     debugee!_ftbuf641971 instructions were executed in 641970 events (0 from other threads)Function Name                               Invocations MinInst MaxInst AvgInstdebugee!_aulldiv                                    790      17      17      17debugee!_aullrem                                    790      15      15      15debugee!_flush                                      299      51      51      51debugee!_ftbuf                                      300       7      44      43debugee!_isatty                                     300      14      14      14debugee!_output                                     300     726     808     792debugee!_stbuf                                      300      59      59      59debugee!_write                                      299     330     380     370debugee!get_int_arg                                 300      12      12      12debugee!loop                                          1    3323    3323    3323debugee!printf                                      300      29      37      36debugee!write_char                                 3190      34      34      34debugee!write_multi_char                            300      10      10      10debugee!write_string                                600      12      84      43kernel32!WriteConsoleA                              299      11      11      11kernel32!WriteConsoleInternal                       299      60      61      60kernel32!WriteFile                                  299      30      30      30kernel32!_SEH_epilog                                598       9       9       9kernel32!_SEH_prolog                                598      19      19      19kernel32!__security_check_cookie                    299       5       5       5ntdll!CsrClientCallServer                           299      39      39      39ntdll!KiFastSystemCall                              299       2       2       2ntdll!NtRequestWaitReplyPort                        598       1       2       1ntdll!ZwRequestWaitReplyPort                        299       1       1       1299 system calls were executedCalls  System Call  299  ntdll!KiFastSystemCall

===============================================================

資料顯示

===============================================================

0:000> dt i

Local var @ 0x12ff28 Type int8030:000> ?? iint 8030:000> ? poi(i)Evaluate expression: 803 = 00000323

===============================================================

記憶體

===============================================================

顯示記憶體

0:000> db i L200012ff18  16 00 00 00 80 ff 12 00-ea 10 40 00 00 00 00 00  ..........@.....0012ff28  00 00 00 00                                      ....0:000> ds i L200012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0012ff80  "..."0:000> dd i L200012ff18  00000016 0012ff80 004010ea 000000000012ff28  00000000 7ffd4000 cccccccc cccccccc0012ff38  cccccccc cccccccc cccccccc cccccccc0012ff48  cccccccc cccccccc cccccccc cccccccc0012ff58  cccccccc cccccccc cccccccc cccccccc

記憶體搜尋

0:000> n16 ; s i L20 ccbase is 160012ff30  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff31  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff32  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff33  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff34  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff35  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff36  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................0012ff37  cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc  ................

記憶體編輯

設定變數i的值為20

n 20; ed i 20 設定10進位,在i的記憶體位置(變數名之時記憶體位址,poi(i)表示i的值)編輯雙字, 設定成20


設定源檔案選項

l+ls 設定在命令視窗提示源檔案代碼


===============================================================

寄存器

===============================================================

查看所有寄存器的資訊

r

修改寄存器的值

r @eax=0x00000323 或者r eax=0x00000323 或者 n 16 ; r eax=323

n命令的意思是切換數的進位,n 16表示使用16進位,323的字面就是16進位的0x323

顯示和設定浮點數

0:000> rFfpcw=027F: rn 53 puozdi  fpsw=0000: top=0 cc=0000 --------  fptw=FFFFfopcode=0000  fpip=0000:00000000  fpdp=0000:00000000st0= 0.000000000000000000000e+0000  st1= 0.000000000000000000000e+0000st2= 0.000000000000000000000e+0000  st3= 0.000000000000000000000e+0000st4= 0.000000000000000000000e+0000  st5= 0.000000000000000000000e+0000st6= 0.000000000000000000000e+0000  st7= 0.000000000000000000000e+0000

rF st0=123.5e10


顯示和設定sse寄存器

0:000> rXxmm0=0 0 0 0xmm1=0 0 0 0xmm2=0 0 0 0xmm3=0 0 0 0xmm4=0 0 0 0xmm5=0 0 0 0xmm6=0 0 0 0xmm7=0 0 0 0

rX xmm0=1 2 3 4

===============================================================

線程和棧

===============================================================

線程和棧操作指令:

切換到3號線程(順序是按照線程建立的順序編碼的)

~3s

掛起當前線程

~n 

掛起所有線程

~*n

掛起10號線程

~10n

喚醒當前線程

~m

喚醒所有線程

~*m

喚醒10號線程

~10m

顯示棧, 類似於gdb的bt命令

k kd kn ~kd ~*kn


移動棧幀到第10層,0層是當前執行位置

0:000> ~kn # ChildEBP RetAddr  00 0012ff80 00401209 debugee!main+0x2a [H:\temp\debugee\debugee.cpp @ 19]01 0012ffc0 77e6f23b debugee!mainCRTStartup+0xe9 [crt0.c @ 206]02 0012fff0 00000000 kernel32!BaseProcessStart+0x230:000> .frame 202 0012fff0 00000000 kernel32!BaseProcessStart+0x23

===============================================================

windbg的快速鍵

===============================================================

ctrl+s 設定符號表

ctrl+p 設定源檔案路徑

ctrl+e 建立子進程開始調試

f6 附加進程進行調試

f5 繼續執行go

shift+f5 停止

ctrl+shift+f5 重啟

f10 單步

F11, F8 步入

shift+f11 步出函數

alt+1 命令視窗

alt+2 局部變數

alt+3 觀察watch

alt+4 寄存器

alt+5 記憶體

alt+6 調用棧

alt+7 反組譯碼

alt+8 記事本

alt+9 進程和線程 

===============================================================

異常處理

===============================================================

// debugee.cpp : Defines the entry point for the console application.

//#include "stdafx.h"void loop(void){for (int i = 0; i < 1000; i ++){printf("loop [%d]\n", i);}*(int *)0 = 0;}int main(int argc, char* argv[]){printf("Hello World!\n");try{loop();}catch (...){printf("exception caught.\n");}return 0;}

如果在調試狀態下,調試器首先接管異常處理,這個時候,

1, 如果執行gN,調試器會放棄處理,讓棧回溯代碼繼續尋找異常處理handler,這個時候如果你在執行gN之前,在catch裡面的printf上打一個斷點,可以攔截到異常處理。

2, 如果執行gh, 那麼調試器告訴作業系統說,異常已經處理好了,於是作業系統傻傻的來重啟異常語句,於是又異常。。。轉悠吧。。。但是,如果你在這個時候,手動處理一下異常,比如說,把eip設定到一個安全的位置,例如,下一個語句。

0040105c e8ef000000      call    debugee!printf (00401150)00401061 83c408          add     esp,800401064 ebdb            jmp     debugee!loop+0x21 (00401041)>>>異常在這一句 00401066 c7050000000000000000 mov dword ptr ds:[0],0  ds:0023:00000000=????????00401070 5f              pop     edi00401071 5e              pop     esi00401072 5b              pop     ebx00401073 83c444          add     esp,44h00401076 3bec            cmp     ebp,esp00401078 e853010000      call    debugee!_chkesp (004011d0)0040107d 8be5            mov     esp,ebp0040107f 5d              pop     ebp00401080 c3              ret

修改 r eip=0x00401070 設定到下一句,恢複執行的時候,就ok了(當然也可以真正的把異常修複了,例如把寫入地址的指標賦給正確的值)

===============================================================

dump檔案

===============================================================

產生小dump

.dump /m f:\debugee_mini.dmp

產生大dump

.dump /ma f:\debugee_large.dmp 


===============================================================

源檔案和符號表

===============================================================

0:000> lmstart    end        module name00400000 0042f000   debugee  C (private pdb symbols)  H:\temp\debugee\Debug\debugee.pdb77e40000 77f42000   kernel32   (pdb symbols)          f:\symbols\kernel32.pdb\DAE455BF1E4B4E249CA44790CD7673182\kernel32.pdb7c800000 7c8c0000   ntdll      (pdb symbols)          f:\symbols\ntdll.pdb\93E72E109DC84F16AA54797E4DA8C1682\ntdll.pdb0:000> ls     1: // debugee.cpp : Defines the entry point for the console application.     2: //     3:      4: #include "stdafx.h"     5:      6: void loop(void)     7: {     8: for (int i = 0; i < 1000; i ++)     9: {    10: printf("loop [%d]\n", i);0:000> lscCurrent: H:\temp\debugee\debugee.cpp(11)0:000> lsf debugee.cpp

===============================================================

符號伺服器

===============================================================

在windbg或者vs啟動時候設定環境變數,可以調試windows系統的dll

Set _NT_SYMBOL_PATH = symsrv*symsrv.dll*f:\localsymbols*http://msdl.microsoft.com/download/symbols

可以先把符號表下載下來

symchk.exe /r c:\windows\system32 /s SRV*c:\symbolcache\*http://msdl.microsoft.com/download/symbols



參考文獻:

http://www.windbg.info/doc/1-common-cmds.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.