日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Windbg教程-调试非托管程序的基本命令中

發布時間:2024/4/11 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windbg教程-调试非托管程序的基本命令中 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面的文章調試非托管程序的基本命令上講到如何在windbg里面啟動一個程序并且加載調試符號文件。一旦符號文件加載完畢以后,就可以進行調試了,例如設置斷點,查看堆棧信息等等。

?

因為是剛剛啟動程序(main函數還沒有機會執行),可以查看源代碼了解要設置斷點的地方。設置斷點可以使用bpbubm來做,其中bp可以根據函數名、指令地址以及源代碼文件地址來設置斷點。

?

bp命令是在設置斷點過程用的比較多的一個命令,下面的表格演示了它的簡單用法:

命令格式

示例

說明

bp?函數名

bp Usage

在函數Usage的入口中斷程序的執行。

bp?指令地址

bp 010113c0

在執行地址在010113c0的指令前中斷程序的執行。

bp `源文件地址`

bp `nativedebug.cpp:21`

在源代碼nativedebug.cpp的第21行設置斷點,請注意符號“`”(感嘆號鍵左邊的反引號)。

?

?

???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

如果你有源代碼的話,通過windbg的菜單“FileOpen Source File”打開源文件,找到相應的代碼行,按下鍵盤的F9就可以設置斷點了(當然前提條件是你已經設置好正確的符號文件,符號文件請參考文章Visual Studio調試之符號文件)。

?

看起來好像沒有什么特別的,只不過是設置斷點的方法比Visual studio復雜一些罷了,不過在windbg中,bp等命令允許在觸發斷點的時候執行一系列的調試命令。例如中斷程序后,打印堆棧,保存內存文件然后退出,或者執行一個小的調試命令腳本程序等等,這個過程與visual studio里面的跟蹤斷點(Trace Point)非常相像,當然操作起來稍微復雜一些(visual studio的跟蹤斷點的用法請參考文章Visual Studio調試之斷點技巧篇)。windbg中設置觸發斷點執行其他命令的方法會在后續的文章里面講到。

?

例如在調試本文的示例程序(示例程序在文章調試非托管程序的基本命令上里面),可以執行以下的命令:

bp Usage

#

#?沒有輸出結果,正所謂沒有消息就是好消息,如果斷點成功設置,

#?windbg不會顯示任何信息。

#

?

如果在設置斷點時,出現類似下面的消息:

?

bp UsageA

#

#?輸出結果

#

Bp expression 'UsageA' could not be resolved, adding deferred bp

?

那么有兩個檢查步驟,第一是檢查符號文件是否正確加載,第二步是檢查設置斷點的函數名是否真的存在于程序當中。

?

第一步,檢查符號文件是否正確加載,可以使用lm命令查看已加載模塊的詳細信息,例如在上面的例子中,我們相信UsageA命令應該在模塊nativedebug.exe中,可以執行下面的命令來查看nativedebug模塊的詳細信息(請注意模塊名是緊跟在vm選項后面的,沒有空格,沒有后綴名,也沒有蛀牙):

?

lm vmnativedebug

#

#?輸出結果

#

start??? end??????? module name

#?注意下面這一行里面的private pdb symbols,說明我們已經加載了正確的符號文件。

#?至于private的含義,會在以后的文章里面講到。

01000000 0101b000?? nativedebug C (private pdb symbols)?D:\Debuggers\sym\nativedebug.pdb\E873A517513C4CC9BA5C805D1A709F206\nativedebug.pdb

??? Loaded symbol image file: nativedebug.exe

# Image path指明了模塊加載的路徑,在64位機器上調試程序的時候,

#這個信息是蠻有用的?。因為你需要知道一些系統模塊是在system32還是

# SysWow64文件夾里加載的。

??? Image path: nativedebug.exe

??? Image name: nativedebug.exe

??? Timestamp:??????? Sat Feb 20 20:05:20 2010 (4B7FD000)

??? CheckSum:???????? 00000000

??? ImageSize:??????? 0001B000

??? Translations:???? 0000.04b0 0000.04e4 0409.04b0 0409.04e4

?

順便說一下,因為nativedebug是我們自己編譯的,有一些版本方面的信息在編譯的時候沒有加進去。如果你查看一個Windows自帶的模塊的詳細信息的話,你可能會看到類似下面的輸出:

?

lm vmntdll

#

#?輸出結果

#

start??? end??????? module name

775f0000 7772c000?? ntdll????? (pdb symbols)?????????D:\Debuggers\sym\ntdll.pdb\F0164DA71FAF4765B8F3DB4F2D7650EA2\ntdll.pdb

??? Loaded symbol image file: ntdll.dll

??? Image path: ntdll.dll

??? Image name: ntdll.dll

??? Timestamp:??????? Tue Jul 14 09:09:47 2009 (4A5BDADB)

??? CheckSum:???????? 0014033F

ImageSize:????????0013C000

#?模塊的版本號,如果你的程序象微軟的產品那樣有多個版本,而且需要對多個

#?版本提供技術支持的話,下面的信息對于找到正確版本的符號文件非常非常非常

#?重要。

??? File version:???? 6.1.7600.16385

??? Product version:?6.1.7600.16385

File flags:???????0 (Mask 3F)

#?模塊要求的子系統

??? File OS:????????? 40004 NT Win32

??? File type:??????? 2.0 Dll

??? File date:??????? 00000000.00000000

??? Translations:???? 0409.04b0

??? CompanyName:????? Microsoft Corporation

??? ProductName:????? Microsoft? Windows? Operating System

??? InternalName:???? ntdll.dll

??? OriginalFilename: ntdll.dll

ProductVersion:???6.1.7600.16385

#?下面只顯示了已發布的產品的信息,版本號已經在前面的注釋里介紹過了。

# win7_rtm的意思是當前的模塊是從win7_rtm這個源代碼分支里編譯出來的。

#?版本分支的概念在團隊軟件產品開發過程中是一個平常的做法,大部分版本

#?控制軟件都支持代碼分支的做法。這個過程解釋起來有點復雜,現在你需要

#?知道的是,如果你現在工作的公司沒有采取版本分支的做法,那么祝賀你,

#?至少在尋找符號文件的過程里,你會比較輕松(不需要考慮分支的影響),

#?雖然會在后面發布高質量的軟件產品你的團隊會死的比較難看。

#?如果你工作的公司正在采取版本分支的做法的話,那么你一定要在正確的分支

#?下尋找對應版本的符號文件,否則你會死的很難看。

#

#?另外,下面一行的輸出里還有一個重要的信息沒有顯示,那就是模塊是否為調試版

#?,還是發布版。與軟件分支一樣,如果考慮進去,也是一樣無法加載到正確的

#?符號文件的。

#

#?如果使用類似微軟的方法編譯軟件,會在后面的文章中講到。

??? FileVersion:????? 6.1.7600.16385 (win7_rtm.090713-1255)

??? FileDescription:?NT Layer DLL

#?這個嘛,地球人都知道。

????LegalCopyright:?? ? Microsoft Corporation. All rights reserved.

?

既然知道符號文件已經被正確加載,那么下一步就是確認設置的函數名是否存在于模塊中,可以使用x命令來檢查符號文件保存的名字信息就是函數名呀,全局變量名之類的信息。如果直接調用x命令,windbg會顯示模塊里面所有的名字。一般都是使用x加上一個匹配模式來查找指定的名字在模塊中是否已定義。比如,為了檢查UsageA這個名字在nativedebug.exe模塊中是否已定義,可以執行下面的命令來查看(感嘆號前面是告訴x命令要在哪一個模塊中查找名字,感嘆號后面就是要查找的名字):

?

x nativedebug!UsageA

#

#?輸出結果沒有輸出結果

#

?

如果x沒有找到指定的名字,就不會輸出任何信息,否則,會有類似下面的輸出:

?

x nativedebug!Usage

#

#?輸出結果,前面的地址是函數入口在內存中的地址,而后面則顯示了函數的聲明信息。

#

010113c0 nativedebug!Usage (void)

?

X命令允許你在查找過程中使用通配符進行匹配,例如,在我們的示例程序中,被用來執行轉換的“函數”_ttol不是一個真實的函數,而是一個宏。下面是這個宏的定義:

?

#ifdef?_UNICODE

#?? define?_ttol?????? _wtol

#else

#?? define?_ttol?????? atol

#endif

?

而宏是在編譯期間就被編譯器擴展,并不會被加到符號文件中去,因此如果你試圖使用bp命令在_ttol入口設置斷點的話,是會失敗的。因此你可以使用類似下面的通配符來查找正確的函數名:

x MSVCR90D!*tol*

#

#?輸出結果(注意黃色高亮的名字)

#

65cd1bb0 MSVCR90D!__STRINGTOLD (struct _LDOUBLE *, char **, char *, int)

65d47c80 MSVCR90D!_ld12told (struct _LDBL12 *, struct _LDOUBLE *)

65cd1900 MSVCR90D!_atoldbl (struct _LDOUBLE *, char *)

65cd6790 MSVCR90D!_wcstol_l (wchar_t *, wchar_t **, int, struct localeinfo_struct *)

65cd4400 MSVCR90D!strtol (char *, char **, int)

65d4bac0 MSVCR90D!__mtold12 (char *, unsigned int, struct _LDBL12 *)

65cd5030 MSVCR90D!_tolower_l (int, struct localeinfo_struct *)

65cd6300 MSVCR90D!wcstol (wchar_t *, wchar_t **, int)

65ca0d50 MSVCR90D!atol (char *)

65cd4940 MSVCR90D!_strtol_l (char *, char **, int, struct localeinfo_struct *)

65ca12d0 MSVCR90D!_wtol (wchar_t *)

65d4a980 MSVCR90D!__wstrgtold12_l (struct _LDBL12 *, wchar_t **, wchar_t *, int, int, int, int, struct localeinfo_struct *)

65d544e0 MSVCR90D!_ftol (void)

65cd5010 MSVCR90D!_tolower (int)

65cd5210 MSVCR90D!tolower (int)

65ca12f0 MSVCR90D!_wtol_l (wchar_t *, struct localeinfo_struct *)

65d48fd0 MSVCR90D!__dtold (struct _LDOUBLE *, double *)

65ce3c30 MSVCR90D!_mbctolower_l (unsigned int, struct localeinfo_struct *)

65d48dc0 MSVCR90D!__STRINGTOLD_L (struct _LDOUBLE *, char **, char *, int, struct localeinfo_struct *)

65cd17f0 MSVCR90D!_atoldbl_l (struct _LDOUBLE *, char *, struct localeinfo_struct *)

65ce3d80 MSVCR90D!_mbctolower (unsigned int)

65ca0d70 MSVCR90D!_atol_l (char *, struct localeinfo_struct *)

65d38670 MSVCR90D!__lc_strtolc (struct tagLC_STRINGS *, char *)

65cdd8e0 MSVCR90D!CPtoLCID (int)

65d47d40 MSVCR90D!__strgtold12_l (struct _LDBL12 *, char **, char *, int, int, int, int, struct localeinfo_struct *)

65c6109c MSVCR90D!_imp__FileTimeToLocalFileTime = <no type information>

?

在上面的輸出,可以看到atol_wtolmsvcr90d.dll這個模塊中都定義了,而我們現在不是很確定當時程序編譯的時候,_UNICODE這個宏是否被定義了。因此我們即可以采用一個笨方法,就是使用bp命令在atol_wtol兩個函數入口上都設置斷點,運行看看到底程序會中斷在哪一個函數上。

?

或者,可以使用bm命令,bm命令相當于bp命令的擴展,允許用戶使用一個通配符設置斷點。例如:

?

bm *tol*

?

#

#?輸出結果?– Windbg會在所有匹配的函數入口上設置斷點。

#?很多,的確很多,因此請慎用bm命令。

#

?4: 65cd1bb0 @!"MSVCR90D!__STRINGTOLD"

?5: 65d47c80 @!"MSVCR90D!_ld12told"

?6: 65cd1900 @!"MSVCR90D!_atoldbl"

?7: 65cd6790 @!"MSVCR90D!_wcstol_l"

?8: 65cd4400 @!"MSVCR90D!strtol"

?9: 65d4bac0 @!"MSVCR90D!__mtold12"

?10: 65cd5030 @!"MSVCR90D!_tolower_l"

?11: 65cd6300 @!"MSVCR90D!wcstol"

?12: 65ca0d50 @!"MSVCR90D!atol"

?13: 65cd4940 @!"MSVCR90D!_strtol_l"

?14: 65ca12d0 @!"MSVCR90D!_wtol"

?15: 65d4a980 @!"MSVCR90D!__wstrgtold12_l"

?16: 65d544e0 @!"MSVCR90D!_ftol"

?17: 65cd5010 @!"MSVCR90D!_tolower"

?18: 65cd5210 @!"MSVCR90D!tolower"

?19: 65ca12f0 @!"MSVCR90D!_wtol_l"

?20: 65d48fd0 @!"MSVCR90D!__dtold"

?21: 65ce3c30 @!"MSVCR90D!_mbctolower_l"

?22: 65d48dc0 @!"MSVCR90D!__STRINGTOLD_L"

?23: 65cd17f0 @!"MSVCR90D!_atoldbl_l"

?24: 65ce3d80 @!"MSVCR90D!_mbctolower"

?25: 65ca0d70 @!"MSVCR90D!_atol_l"

?26: 65d38670 @!"MSVCR90D!__lc_strtolc"

?27: 65cdd8e0 @!"MSVCR90D!CPtoLCID"

?28: 65d47d40 @!"MSVCR90D!__strgtold12_l"

?

設置好斷點后,可以使用bl命令(breakpoint list)來查看已經設置好的斷點:

?

bl

#

#?輸出結果

#?第一列是斷點的編號;

#?第二列,e表示(enabled),u表示(unresolved),因此如果那一列的值為e,則說明

#?斷點是啟用狀態,如果為d表示(disabled),則表示禁用狀態。如果有u,則基本上

#?說明這個斷點是沒有設置成功的,雖然windbg會在后續加載每一個模塊的時候,都嘗試

#?根據那個名字設置斷點;

#?后面幾列,放在后面的文章講。

#

?0 e 010113c0???? 0001 (0001)?0:**** nativedebug!Usage

?1 eu???????????? 0001 (0001) (UsageA)

#?這個斷點沒有設置正確

?2 eu???????????? 0001 (0001) (`22`)

?4 e 65cd1bb0???? 0001 (0001)?0:**** MSVCR90D!__STRINGTOLD

?5 e 65d47c80???? 0001 (0001)?0:**** MSVCR90D!_ld12told

?6 e 65cd1900???? 0001 (0001)?0:**** MSVCR90D!_atoldbl

?7 e 65cd6790???? 0001 (0001)?0:**** MSVCR90D!_wcstol_l

?8 e 65cd4400???? 0001 (0001)?0:**** MSVCR90D!strtol

?9 e 65d4bac0???? 0001 (0001)?0:**** MSVCR90D!__mtold12

10 e 65cd5030?????0001 (0001)?0:**** MSVCR90D!_tolower_l

11 e 65cd6300?????0001 (0001)?0:**** MSVCR90D!wcstol

12 e 65ca0d50?????0001 (0001)?0:**** MSVCR90D!atol

13 e 65cd4940?????0001 (0001)?0:**** MSVCR90D!_strtol_l

14 e 65ca12d0?????0001 (0001)?0:**** MSVCR90D!_wtol

15 e 65d4a980?????0001 (0001)?0:**** MSVCR90D!__wstrgtold12_l

16 e 65d544e0?????0001 (0001)?0:**** MSVCR90D!_ftol

17 e 65cd5010?????0001 (0001)?0:**** MSVCR90D!_tolower

18 e 65cd5210?????0001 (0001)?0:**** MSVCR90D!tolower

19 e 65ca12f0?????0001 (0001)?0:**** MSVCR90D!_wtol_l

20 e 65d48fd0?????0001 (0001)?0:**** MSVCR90D!__dtold

21 e 65ce3c30?????0001 (0001)?0:**** MSVCR90D!_mbctolower_l

22 e 65d48dc0?????0001 (0001)?0:**** MSVCR90D!__STRINGTOLD_L

23 e 65cd17f0?????0001 (0001)?0:**** MSVCR90D!_atoldbl_l

24 e 65ce3d80?????0001 (0001)?0:**** MSVCR90D!_mbctolower

25 e 65ca0d70?????0001 (0001)?0:**** MSVCR90D!_atol_l

26 e 65d38670?????0001 (0001)?0:**** MSVCR90D!__lc_strtolc

27 e 65cdd8e0?????0001 (0001)?0:**** MSVCR90D!CPtoLCID

28 e 65d47d40?????0001 (0001)?0:**** MSVCR90D!__strgtold12_l

?

在上面的輸出中,可以看到斷點12是無效的斷點,因此可以使用bcbreakpoint clear)這個命令刪除掉這兩個斷點:

?

bc 1

#

#?沒有輸出結果沒有消息就是好消息

#

bc 2

#

#?沒有輸出結果沒有消息就是好消息

#

?

因此在前面的bm命令中,設置了太多的斷點,為了避免在不必要的函數上中斷,我們既可以使用bc命令將它們刪掉,也可以使用bdbreakpoint disabled)命令將其禁用。因為命令實在太多,所以我們可以使用一個小技巧使用一個范圍來禁用一批斷點:

?

bd 4-10

#

#?沒有輸出結果沒有消息就是好消息,

#?這個命令將從斷點4到斷點10的所有斷點都禁用了。

#

?

bdbc命令的語法是一樣的,既可以根據指定的范圍禁用或刪除一批斷點,也可以根據指定的通配符來操作一批斷點,還可以使用一種稀奇古怪的語法來操作斷點(這個稀奇古怪的語法會在后面的文章中講到)。

設置好斷點以后,可以繼續進程的運行了,斷點觸發以后,我們才能查看進程的堆棧以及一些變量的數據。這些內容放在下一篇文章調試非托管程序的基本命令下講解。

總結

以上是生活随笔為你收集整理的Windbg教程-调试非托管程序的基本命令中的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。