在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Wine常用調試方法

深度操作系統 ? 來源:深度操作系統 ? 2025-01-16 09:52 ? 次閱讀

本文主要以 Wine 官網的這篇文章 《Debugging Wine》來講解。大部分內容是對該文的翻譯,修正了原文的一些書寫錯誤,刪除了原文跟最新的 Wine 不適應的內容。

介紹

常用調試方法

Wine 為調試問題提供了多種方法。大多數 Wine 開發人員更喜歡使用 Wine 的調試通道收集日志來解決問題。您可以在開發人員調試日志使用指南中了解如何使用調試通道來記錄日志的更多內容。

本文的剩余部分將詳細介紹Wine 的內部調試器 winedbg 的使用。

在底層操作系統和 Windows 中的進程和線程

在深入講解 Wine 的調試之前,下面是 Wine 中對進程和線程處理的小概述。必須清楚的是,我們有兩種不同的模型:從 Unix 角度看到的進程/線程,從 Windows 角度看到的進程/線程。

每個 Windows 線程都用一個 Unix 線程來實現,這意味著同一個 Windows 進程的所有線程共享相同的 Unix 進程地址空間。以下:

W-process 表示 Windows 中的進程

U-process 表示 Unix 中的進程

W-thread 表示 Windows 中的線程

一個W-process 由一個或多個W-thread 組成。每個W-thread 映射到一個且只有一個U-process。同一個W-process 的所有U-process 共享相同的地址空間。

所以每個 Unix 進程都可以用兩個值來標識:

Unix 進程 ID ( 簡稱upid)

Windows 線程 ID (簡稱tid)

每個 Windows 進程還具有 Windows 進程 ID (簡稱wpid)。必須清楚,upid 和wpid 是不同的,不能相互替代。wpid 和tid 是 Windows 系統層面定義的,它們不能與進程或線程句柄混淆,因為任何句柄都指向系統對象(在本例中為進程或線程)。同一個進程可以對同一個內核對象有多個不同的句柄。句柄可以定義為局部(值僅在同一個進程中有效),也可以定義為系統范圍的(任何W-process都可以使用相同的句柄)。

Wine、調試和 Winedbg

在 Wine 中談到調試時,至少需要考慮兩個層次:

Windows 調試 API。

Wine 集成調試器,被稱為winedbg

Wine 實現了大多數 Windows 調試 API。調試 API 的第一部分在 KERNEL32.DLL 中實現,允許稱為調試器的W-process 控制另一個被調試的W-process 的執行。控制意味著停止/恢復執行、啟用/禁用單步、設置斷點、讀寫內存等等。調試 API 的另一部分在 DBGHELP.DLL (依賴 IMGHLP.DLL) 中實現,允許調試器查看任何模塊中的符號和符號類型(如果模塊已使用調試選項編譯)。

Winedbg 就是一個使用這些 API 的 Winelib 應用程序,允許調試任何 Wine 或 Winelib 應用程序以及 Wine 本身。

調試教程

這些教程針對的是了解 C 語言編程,但剛剛開始參與開發 Wine 的人。旨在演示當應用程序不工作時怎樣調試問題。

調試 Reason 3 - 一個簡單的"未處理異常"錯誤消息。介紹了調試跟蹤、shell32.dll 和 SEH/異常跟蹤。 https://wiki.winehq.org/Debugging_Reason_3

調試 PE Explorer - 修復文件打開對話框中的簡單掛起(另一個shell32 錯誤)。介紹了 winedbg 的堆棧回溯用法和不同類型的錯誤碼。 https://wiki.winehq.org/Debugging_PE_Explorer

調試 Wild Metal Country - 查找游戲崩潰的原因以及如何確認錯誤。 https://wiki.winehq.org/Debugging_Wild_Metal_Country

Anastasius Focht 提交的 bug 報告里詳細描述了他如何發現問題,以下網址可查看他的 bug 報告: http://bugs.winehq.org/buglist.cgi?query_format=advanced&emailreporter1=1&emaillongdesc1=1&email1=focht&emailtype1=substring

Winedbg 啟動方法

啟動一個進程

任何程序(原生的 Windows 程序或鏈接 Winelib 的程序)都可以用 winedbg 來運行,命令行選項跟 Wine 一樣的:

winedbg telnet.exe
winedbg hl.exe -windowed

附加一個進程

Winedbg 也可以不加任何命令行參數來啟動: 此時 winedbg 以沒有附加任何進程方式啟動。您可以使用info proc 命令獲取正在運行的W-process(及其wpid)的列表,然后使用attach 命令跟一個要調試的W-process的wpid 參數。這功能允許您調試已經啟動的應用程序。

在發生異常的時候

當出現問題時,Windows 會將它作為異常進行跟蹤。比如有分段違例、堆棧溢出、除零等異常。

發生異常時,Wine 會檢查W-process 是否被調試。如果是,異常事件將發送到調試器,調試器負責是否傳遞該異常。此機制是標準 Windows 調試 API 的一部分。

如果W-process 沒有被調試,Wine 會嘗試啟動調試器。此調試器(通常是 winedbg,請參閱下一節的配置以了解更多詳細信息),在啟動時附加到生成異常事件的W-process 。在這種情況下,您可以查看異常的原因,并修復原因(和繼續執行)或深入挖掘以了解出錯的原因。

如果 winedbg 是標準調試器,則pass 和cont 命令是讓進程進一步處理異常事件的兩種方法。

更精確地說:當發生故障時(分段違例、堆棧溢出……),該事件首先發送到調試器(這稱為第一次異常處理機會)。調試器可以給出兩個答案:

continue 調試器能夠修復這個異常,并且能夠讓程序繼續執行。

pass 調試器在第一次異常處理機會時不能修復這個異常。Wine 將嘗試遍歷異常處理程序列表,查看其中一個處理程序是否可以處理該異常。如果未找到異常處理程序,則再次將這個異常發送到調試器,以指示異常處理失敗。

注意:由于某些 Wine 代碼使用異常和 try/catch 塊來實現某些功能,因此在這種情況下winedbg 收到 segv 異常而停下來。例如,使用 IsBadReadPtr 函數時會發生這種情況。在這種情況下,應使用pass 命令,以便由 IsBadReadPtr 中的 catch 塊處理異常。

中斷

您可以在winedbg 窗口同時按下 Ctrl+C 來停止正在運行的被調試程序,并允許您在 winedbg 里面操作被調試程序的進程上下文。

退出

Wine 支持新的 XP API,允許調試器從被調試程序上分離(見下文的detach 命令)。

使用 Wine 調試器

這一節介紹從何處開始調試 Wine。如果您在任何時候卡住了并且需要幫助,請閱讀 Wine 用戶指南之如何報告 bug 一節。

崩潰

崩潰時我們常看到類似這樣的對話框:

Unhandled exception: page fault on write access to 0x00000000 in 32-bit code (0x0043369e).
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:0043369e ESP:0b3ee90c EBP:0b3ee938 EFLAGS:00010246( R- -- I Z- -P- )
 EAX:00000072 EBX:7b8acff4 ECX:00000000 EDX:6f727265
 ESI:7ba3b37c EDI:7ffa0000
Stack dump:
0x0b3ee90c: 7b82ced8 00000000 7ba3b348 7b884401
0x0b3ee91c: 7b883cdc 00000008 00000000 7bc36e7b
0x0b3ee92c: 7b8acff4 7b82ceb9 7b8acff4 0b3eea18
0x0b3ee93c: 7b82ce82 00000000 00000000 00000000
0x0b3ee94c: 00000000 0b3ee968 70d7ed7b 70c50000
0x0b3ee95c: 00000000 0b3eea40 7b87fd40 7b82d0d0
Backtrace:
=>0 0x0043369e in elementclient (+0x3369e) (0x0b3ee938)
 1 0x7b82ce82 CONSOLE_SendEventThread+0xe1(pmt=0x0(nil)) [/usr/src/debug/wine-1.5.14/dlls/kernel32/console.c:1989] in kernel32 (0x0b3eea18)
 2 0x7bc76320 call_thread_func_wrapper+0xb() in ntdll (0x0b3eea28)
 3 0x7bc7916e call_thread_func+0x7d(entry=0x7b82cda0, arg=0x0(nil), frame=0xb3eeb18) [/usr/src/debug/wine-1.5.14/dlls/ntdll/signal_i386.c:2522] in ntdll (0x0b3eeaf8)
 4 0x7bc762fe RtlRaiseException+0x21() in ntdll (0x0b3eeb18)
 5 0x7bc7f3da start_thread+0xe9(info=0x7ffa0fb8) [/usr/src/debug/wine-1.5.14/dlls/ntdll/thread.c:408] in ntdll (0x0b3ef368)
 6 0xf7597adf start_thread+0xce() in libpthread.so.0 (0x0b3ef468)
0x0043369e: movl  %edx,0x0(%ecx)
Modules:
Module Address     Debug info Name (143 modules)
PE  340000- 3af000  Deferred    speedtreert
PE  3b0000- 3d6000  Deferred    ftdriver
PE  3e0000- 3e6000  Deferred    immwrapper
PE  400000- b87000  Export     elementclient
PE  b90000- e04000  Deferred    elementskill
PE  e10000- e42000  Deferred    ifc22
PE 10000000-10016000  Deferred    zlibwapi
ELF 41f75000-41f7e000  Deferred    librt.so.1
ELF 41ff9000-42012000  Deferred    libresolv.so.2
PE 48080000-480a8000  Deferred    msls31
PE 65340000-653d2000  Deferred    oleaut32
PE 70200000-70294000  Deferred    wininet
PE 702b0000-70328000  Deferred    urlmon
PE 70440000-704cf000  Deferred    mlang
PE 70bd0000-70c34000  Deferred    shlwapi
PE 70c50000-70ef3000  Deferred    mshtml
PE 71930000-719b8000  Deferred    shdoclc
PE 78130000-781cb000  Deferred    msvcr80
ELF 79afb000-7b800000  Deferred    libnvidia-glcore.so.304.51
ELF 7b800000-7ba3d000  Dwarf      kernel32
 -PE 7b810000-7ba3d000          kernel32
ELF 7bc00000-7bcd5000  Dwarf      ntdll
 -PE 7bc10000-7bcd5000          ntdll
ELF 7bf00000-7bf04000  Deferred    
ELF 7c288000-7c400000  Deferred    libvorbisenc.so.2
PE 7c420000-7c4a7000  Deferred    msvcp80
ELF 7c56d000-7c5b6000  Deferred    dinput
 -PE 7c570000-7c5b6000          dinput
ELF 7c5b6000-7c600000  Deferred    libdbus-1.so.3
ELF 7c70e000-7c715000  Deferred    libasyncns.so.0
ELF 7c715000-7c77e000  Deferred    libsndfile.so.1
ELF 7c77e000-7c7e5000  Deferred    libpulsecommon-1.1.so
ELF 7c7e5000-7c890000  Deferred    krnl386.exe16.so
PE 7c7f0000-7c890000  Deferred    krnl386.exe16
ELF 7c890000-7c900000  Deferred    ieframe
 -PE 7c8a0000-7c900000          ieframe
ELF 7ca00000-7ca1a000  Deferred    rasapi32
 -PE 7ca10000-7ca1a000          rasapi32
ELF 7ca1a000-7ca21000  Deferred    libnss_dns.so.2
ELF 7ca21000-7ca25000  Deferred    libnss_mdns4_minimal.so.2
ELF 7ca25000-7ca2d000  Deferred    libogg.so.0
ELF 7ca2d000-7ca5a000  Deferred    libvorbis.so.0
ELF 7cd5d000-7cd9c000  Deferred    libflac.so.8
ELF 7cd9c000-7cdea000  Deferred    libpulse.so.0
ELF 7cdfe000-7ce23000  Deferred    iphlpapi
 -PE 7ce00000-7ce23000          iphlpapi
ELF 7cff1000-7cffd000  Deferred    libnss_nis.so.2
ELF 7d60d000-7d629000  Deferred    wsock32
 -PE 7d610000-7d629000          wsock32
ELF 7d80d000-7d828000  Deferred    libnsl.so.1
ELF 7d8cf000-7d8db000  Deferred    libgsm.so.1
ELF 7d8db000-7d903000  Deferred    winepulse
 -PE 7d8e0000-7d903000          winepulse
ELF 7d95c000-7d966000  Deferred    libwrap.so.0
ELF 7d966000-7d96d000  Deferred    libxtst.so.6
ELF 7d96d000-7d992000  Deferred    mmdevapi
 -PE 7d970000-7d992000          mmdevapi
ELF 7d9b3000-7d9d0000  Deferred    msimtf
 -PE 7d9c0000-7d9d0000          msimtf
ELF 7d9d0000-7d9e5000  Deferred    comm.drv16.so
PE 7d9e0000-7d9e5000  Deferred    comm.drv16
ELF 7da83000-7db5f000  Deferred    libgl.so.1
ELF 7db60000-7db63000  Deferred    libx11-xcb.so.1
ELF 7db63000-7db78000  Deferred    system.drv16.so
PE 7db70000-7db78000  Deferred    system.drv16
ELF 7db98000-7dca1000  Deferred    opengl32
 -PE 7dbb0000-7dca1000          opengl32
ELF 7dca1000-7dcb6000  Deferred    vdmdbg
 -PE 7dcb0000-7dcb6000          vdmdbg
ELF 7dcce000-7dd04000  Deferred    uxtheme
 -PE 7dcd0000-7dd04000          uxtheme
ELF 7dd04000-7dd0a000  Deferred    libxfixes.so.3
ELF 7dd0a000-7dd15000  Deferred    libxcursor.so.1
ELF 7dd16000-7dd1f000  Deferred    libjson.so.0
ELF 7dd24000-7dd38000  Deferred    psapi
 -PE 7dd30000-7dd38000          psapi
ELF 7dd78000-7dda1000  Deferred    libexpat.so.1
ELF 7dda1000-7ddd6000  Deferred    libfontconfig.so.1
ELF 7ddd6000-7dde6000  Deferred    libxi.so.6
ELF 7dde6000-7ddef000  Deferred    libxrandr.so.2
ELF 7ddef000-7de11000  Deferred    libxcb.so.1
ELF 7de11000-7df49000  Deferred    libx11.so.6
ELF 7df49000-7df5b000  Deferred    libxext.so.6
ELF 7df5b000-7df75000  Deferred    libice.so.6
ELF 7df75000-7e005000  Deferred    winex11
 -PE 7df80000-7e005000          winex11
ELF 7e005000-7e0a5000  Deferred    libfreetype.so.6
ELF 7e0a5000-7e0c5000  Deferred    libtinfo.so.5
ELF 7e0c5000-7e0ea000  Deferred    libncurses.so.5
ELF 7e123000-7e1eb000  Deferred    crypt32
 -PE 7e130000-7e1eb000          crypt32
ELF 7e1eb000-7e235000  Deferred    dsound
 -PE 7e1f0000-7e235000          dsound
ELF 7e235000-7e2a7000  Deferred    ddraw
 -PE 7e240000-7e2a7000          ddraw
ELF 7e2a7000-7e3e3000  Deferred    wined3d
 -PE 7e2b0000-7e3e3000          wined3d
ELF 7e3e3000-7e417000  Deferred    d3d8
 -PE 7e3f0000-7e417000          d3d8
ELF 7e417000-7e43b000  Deferred    imm32
 -PE 7e420000-7e43b000          imm32
ELF 7e43b000-7e46f000  Deferred    ws2_32
 -PE 7e440000-7e46f000          ws2_32
ELF 7e46f000-7e49a000  Deferred    msacm32
 -PE 7e470000-7e49a000          msacm32
ELF 7e49a000-7e519000  Deferred    rpcrt4
 -PE 7e4b0000-7e519000          rpcrt4
ELF 7e519000-7e644000  Deferred    ole32
 -PE 7e530000-7e644000          ole32
ELF 7e644000-7e6f7000  Deferred    winmm
 -PE 7e650000-7e6f7000          winmm
ELF 7e6f7000-7e7fa000  Deferred    comctl32
 -PE 7e700000-7e7fa000          comctl32
ELF 7e7fa000-7ea23000  Deferred    shell32
 -PE 7e810000-7ea23000          shell32
ELF 7ea23000-7eaf9000  Deferred    gdi32
 -PE 7ea30000-7eaf9000          gdi32
ELF 7eafb000-7eaff000  Deferred    libnvidia-tls.so.304.51
ELF 7eaff000-7eb09000  Deferred    libxrender.so.1
ELF 7eb09000-7eb0f000  Deferred    libxxf86vm.so.1
ELF 7eb0f000-7eb18000  Deferred    libsm.so.6
ELF 7eb18000-7eb32000  Deferred    version
 -PE 7eb20000-7eb32000          version
ELF 7eb32000-7ec87000  Deferred    user32
 -PE 7eb40000-7ec87000          user32
ELF 7ec87000-7ecf1000  Deferred    advapi32
 -PE 7ec90000-7ecf1000          advapi32
ELF 7ecf1000-7ed8f000  Deferred    msvcrt
 -PE 7ed00000-7ed8f000          msvcrt
ELF 7ef8f000-7ef9c000  Deferred    libnss_files.so.2
ELF 7ef9c000-7efc7000  Deferred    libm.so.6
ELF 7efc8000-7efe5000  Deferred    libgcc_s.so.1
ELF 7efe5000-7f000000  Deferred    crtdll
 -PE 7eff0000-7f000000          crtdll
ELF f73d0000-f73d4000  Deferred    libxinerama.so.1
ELF f73d4000-f73d8000  Deferred    libxau.so.6
ELF f73da000-f73df000  Deferred    libdl.so.2
ELF f73df000-f7591000  Dwarf      libc.so.6
ELF f7591000-f75ab000  Dwarf      libpthread.so.0
ELF f75ab000-f76ef000  Dwarf      libwine.so.1
ELF f7722000-f7728000  Deferred    libuuid.so.1
ELF f7729000-f774a000  Deferred    ld-linux.so.2
ELF f774a000-f774b000  Deferred    [vdso].so
Threads:
process tid   prio (all id:s are in hex)
00000008 (D) C:Perfect World EntertainmentPerfect World Internationalelementelementclient.exe
  00000031  0 <==
 ? ?00000035 ? 15
 ? ?00000012 ? ?0
 ? ?00000021 ? ?0
 ? ?00000045 ? ?0
 ? ?00000044 ? ?0
 ? ?00000043 ? ?0
 ? ?00000038 ? 15
 ? ?00000037 ? ?0
 ? ?00000036 ? 15
 ? ?00000034 ? ?0
 ? ?00000033 ? ?0
 ? ?00000032 ? ?0
 ? ?00000027 ? ?0
 ? ?00000009 ? ?0
0000000e services.exe
 ? ?0000000b ? ?0
 ? ?00000020 ? ?0
 ? ?00000017 ? ?0
 ? ?00000010 ? ?0
 ? ?0000000f ? ?0
00000014 winedevice.exe
 ? ?0000001e ? ?0
 ? ?0000001b ? ?0
 ? ?00000016 ? ?0
 ? ?00000015 ? ?0
0000001c plugplay.exe
 ? ?00000022 ? ?0
 ? ?0000001f ? ?0
 ? ?0000001d ? ?0
00000023 explorer.exe
 ? ?00000024 ? ?0

調試崩潰的步驟。您可能在任何步驟中崩潰,但請報告 bug,并在 bug 報告中提供收集到的盡可能多的信息。

了解崩潰的原因。通常是頁面錯誤、調用了Wine 中未實現的函數,或類似的原因。報告崩潰時,報告整個崩潰轉儲,即使它對您沒有意義。(在這個例子里面,在寫入 0x0000000 時出現頁面錯誤。最有可能的是 Wine 將 NULL 傳遞給應用程序或類似問題。)

確定崩潰的原因。由于通常是 Wine 實現的函數執行失敗或者行為不正確導致的主要/次要反應,因此使用WINEDEBUG=+relay 環境變量重新運行 Wine。這將生成相當多的日志輸出,但通常原因是位于最后一個函數調用中。這些日志通常如下所示: 8661d716-d329-11ef-9310-92fbcf53809c.png

如果你已經發現了一個行為不正常的 Wine 函數,嘗試找出它行為不正常的原因。在源代碼中查找函數。試著理解傳遞的函數參數。通常有一個WINE_DEFAULT_DEBUG_CHANNEL(channel); 在源文件的開頭。使用WINEDEBUG=+xyz,+relay 環境變量重新運行 Wine。有時,在源文件的開頭以WINE_DECLARE_DEBUG_CHANNEL(channel)的形式定義了其他調試通道;如果是這樣,有問題的函數也可能使用了這些備用通道之一。在該函數中搜索TRACE_(channel)(".../n"); 并將找到的這些額外的通道添加到 WINEDEBUG 環境變量里面。

有關如何使用 winedbg 進行調試的其他信息,請參閱源碼programs/winedbg/README。

如果這些信息不夠清晰,或者您想知道該函數發生的更多信息,請嘗試使用WINEDEBUG=+all重新運行 Wine ,這將轉儲 Wine 里面包含調試信息在內的所有日志。通常需要限制生成的調試輸出。這可以通過管道把輸出日志發給grep 過濾,或者使用注冊表項來完成。有關詳細信息,請參閱下文的配置 +relay 行為 一節。

如果這還不夠,可以在您認為相關的函數中手動添加更多調試日志。有關詳細信息,請參閱開發人員調試日志使用指南。您也可以嘗試在 gdb 中運行該程序,代替使用 Wine 調試器。如果這樣做,請在~/.gdbinit 文件里面增加這句handle SIGSEGV nostop noprint 來禁用 gdb 對seg fault 錯誤的處理(Win16 需要)。

您還可以為該函數設置斷點。用 winedbg 啟動調試程序而不是 Wine。一旦調試器運行起來,在命令行提示符輸入命令:break RegOpenKeyExW (將 RegOpenKeyExW 替換成您要調試的函數,區分大小寫)以設置斷點。然后,使用continue 命令啟動程序正常執行。程序運行到斷點位置,程序將停止;如果程序還沒有運行到該函數崩潰的那次調用,再次使用continue 命令繼續運行程序直到達到該函數即將崩潰的那次調用。現在,您可以用單步執行命令來繼續運行程序,直到達到崩潰點,然后使用其他調試器命令來查看寄存器值和相關變量值等等。

程序掛起,沒有反應

用 winedbg 啟動程序而不是 Wine 。當程序沒有反應的時候,切換到 winedbg 窗口,并按 Ctrl+C 。這將停止程序,并允許您調試該程序,就像崩潰時候一樣。

程序彈出錯誤消息框

有時候程序會使用或多或少的非描述性消息框報告失敗。我們可以使用與崩潰相同的方法進行調試,但有一個問題,為了設置消息框,程序會多出大量的調試日志。

由于故障通常發生在設置消息框之前,您可以啟動 winedbg 并在 MessageBoxA (由 Win16 和 Win32 程序調用)處設置斷點,然后繼續運行。程序將在設置消息框之前停止。

您也可以使用這個命令來運行程序:WINEDEBUG=+relay wine program.exe 2>&1 | less -i然后在 less 里面搜索 MessageBox 。

匯編程序

您也可以嘗試反匯編有問題的程序,以檢查沒有公開的功能或使用它們。

理解匯編代碼主要是一個練習問題。Win16 函數入口通常如下所示:

push bp
mov bp, sp
... 函數代碼 ..
retf XXXX  <--------- XXXX 是函數參數的總字節數

這是一個沒有局部變量的 FAR 函數。參數通常從[bp+6] 開始,偏移量增加。請注意,對于使用 PASCAL 調用約定導出的 Win16 函數,[bp+6] 屬于最右側的參數。因此,如果我們使用帶a 和b 的strcmp(a,b) 來說,則參數b 的存儲位置在[bp+6],參數a 的存儲位置在[bp+10] 。

大多數函數用棧存儲局部變量:

enter 0086, 00
... 函數代碼 ...
leave
retf XXXX

這與上述內容基本相同,但還添加了 0x86 字節的棧存儲,使用[bp-xx] 進行訪問。在調用該函數之前,使用如下所示的代碼把參數壓到棧上:

push word ptr [bp-02]  <- 壓到 [bp+8] 處
push di ? ? ? ? ? ? ? ? <- 壓到 [bp+6] 處
call KERNEL.LSTRLEN

在這里,首先壓人選擇器地址,然后壓入傳遞的字符串的偏移量。

調試示例

讓我們調試臭名昭著的 WORD SHARE.EXE 消息框:

|marcus@jet $ wine winword.exe
|      +---------------------------------------------+
|      | ! You must leave Windows and load SHARE.EXE|
|      |  before starting Word.          |
|      +---------------------------------------------+
|marcus@jet $ WINEDEBUG=+relay,-debug wine winword.exe
|CallTo32(wndproc=0x40065bc0,hwnd=000001ac,msg=00000081,wp=00000000,lp=00000000)
|Win16 task 'winword': Breakpoint 1 at 0x01d7:0x001a
|CallTo16(func=0127:0070,ds=0927)
|Call WPROCS.24: TASK_RESCHEDULE() ret=00b7:1456 ds=0927
|Ret WPROCS.24: TASK_RESCHEDULE() retval=0x8672 ret=00b7:1456 ds=0927
|CallTo16(func=01d7:001a,ds=0927)
|   AX=0000 BX=3cb4 CX=1f40 DX=0000 SI=0000 DI=0927 BP=0000 ES=11f7
|Loading symbols: /home/marcus/wine/wine...
|Stopped on breakpoint 1 at 0x01d7:0x001a
|In 16 bit mode.
|Wine-dbg>break MessageBoxA             c                      <---- Continue
|Call KERNEL.91: INITTASK() ret=0157:0022 ds=08a7
| ? ? AX=0000 BX=3cb4 CX=1f40 DX=0000 SI=0000 DI=08a7 ES=11d7 EFL=00000286
|CallTo16(func=090f:085c,ds=0dcf,0x0000,0x0000,0x0000,0x0000,0x0800,0x0000,0x0000,0x0dcf)
|... ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <----- Much debug output
|Call KERNEL.136: GETDRIVETYPE(0x0000) ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^^^^^^ Drive 0 (A:)
|Ret ?KERNEL.136: GETDRIVETYPE() retval=0x0002 ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^ ?DRIVE_REMOVEABLE
 ? ? ? ? ? ? ? ? ? ? ? ?(It is a floppy diskdrive.)

|Call KERNEL.136: GETDRIVETYPE(0x0001) ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^^^^^^ Drive 1 (B:)
|Ret ?KERNEL.136: GETDRIVETYPE() retval=0x0000 ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^ ?DRIVE_CANNOTDETERMINE
 ? ? ? ? ? ? ? ? ? ? ? ?(I don't have drive B: assigned)

|Call KERNEL.136: GETDRIVETYPE(0x0002) ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^^^^^^^ Drive 2 (C:)
|Ret ?KERNEL.136: GETDRIVETYPE() retval=0x0003 ret=060f:097b ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^ DRIVE_FIXED
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (specified as a hard disk)

|Call KERNEL.97: GETTEMPFILENAME(0x00c3,0x09278364"doc",0x0000,0927:8248) ret=060f:09b1 ds=0927
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^^^^^^ ? ? ? ? ? ^^^^^ ? ? ? ?^^^^^^^^^
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ?| ? ? ? ? ? ?|buffer for fname
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ?|temporary name ~docXXXX.tmp
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |Force use of Drive C:.

|Warning: GetTempFileName returns 'C:~doc9281.tmp', which doesn't seem to be writable.
|Please check your configuration file if this generates a failure.

哎呀,日志中發現了問題 (OPENFILE 失敗):

|Ret KERNEL.97: GETTEMPFILENAME() retval=0x9281 ret=060f:09b1 ds=0927
                     ^^^^^^ Temporary storage ID

|Call KERNEL.74: OPENFILE(0x09278248"C:~doc9281.tmp",0927:82da,0x1012) ret=060f:09d8 ds=0927
                  ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^
                  |filename    |OFSTRUCT |open mode:

                    OF_CREATE|OF_SHARE_EXCLUSIVE|OF_READWRITE

這里失敗的原因是我的 C 盤是只讀的:

|Ret KERNEL.74: OPENFILE() retval=0xffff ret=060f:09d8 ds=0927
                  ^^^^^^ HFILE_ERROR16, yes, it failed.

|Call USER.1: MESSAGEBOX(0x0000,0x09278376"You must close Windows and load SHARE.EXE before you start Word.",0x00000000,0x1030) ret=060f:084f ds=0927

并且在 MessageBoxA 的入口停下來了:

|Stopped on breakpoint 2 at 0x40189100 (MessageBoxA [msgbox.c:190])
|190   {   

代碼看起來要找一個可寫磁盤,并試圖在該磁盤創建一個文件。要解決此 Bug,可以將 C 盤定義為網絡驅動器,上述代碼將忽略該驅動器。

調試技巧

以下是一些其他調試技巧:

1. 如果您有一個程序在加載前期崩潰,以至于您無法正常使用 Wine 調試器來調試,但 Wine 已執行該程序的啟動代碼,則可以使用特殊的技巧。您應該執行WINEDEBUG=+relay wine program獲取程序在啟動函數中調用的所有函數清單。然后執行:winedbg winfile.exe這樣,您就進入 winedbg。現在,您可以在 start 函數中調用的任何函數上設置斷點,然后不斷按 c 以跳過 Winfile 對此函數的正常調用,直到您最終到達此函數調用崩潰的位置。您就可以像平常一樣繼續調試該程序。 2. 如果嘗試運行程序,程序在彈出錯誤消息框后就退出,則問題的原因通常可以檢查在 MessageBox 之前調用的一些函數的返回值發現。您應該用下面的方式重新運行程序:WINEDEBUG=+relay wine program_name &>relmsg接著執行more relmsg 然后搜索最后一個出現的MESSAGEBOX,類似這樣的:Call USER.1: MESSAGEBOX(0x0000,0x01ff1246 "Runtime error 219 at 0004:1056.",0x00000000,0x1010) ret=01f7:2160 ds=01ff在我的例子里面,在調用MessageBox 函數之前的代碼類似這樣:

Call KERNEL.96: FREELIBRARY(0x0347) ret=01cf:1033 ds=01ff
CallTo16(func=033f:0072,ds=01ff,0x0000)
Ret KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:1033 ds=01ff
Call KERNEL.96: FREELIBRARY(0x036f) ret=01cf:1043 ds=01ff
CallTo16(func=0367:0072,ds=01ff,0x0000)
Ret KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:1043 ds=01ff
Call KERNEL.96: FREELIBRARY(0x031f) ret=01cf:105c ds=01ff
CallTo16(func=0317:0072,ds=01ff,0x0000)
Ret KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:105c ds=01ff
Call USER.171: WINHELP(0x02ac,0x01ff05b4 "COMET.HLP",0x0002,0x00000000) ret=01cf:1070 ds=01ff
CallTo16(func=0117:0080,ds=01ff)
Call WPROCS.24: TASK_RESCHEDULE() ret=00a7:0a2d ds=002b
Ret WPROCS.24: TASK_RESCHEDULE() retval=0x0000 ret=00a7:0a2d ds=002b
Ret USER.171: WINHELP() retval=0x0001 ret=01cf:1070 ds=01ff
Call KERNEL.96: FREELIBRARY(0x01be) ret=01df:3e29 ds=01ff
Ret KERNEL.96: FREELIBRARY() retval=0x0000 ret=01df:3e29 ds=01ff
Call KERNEL.52: FREEPROCINSTANCE(0x02cf00ba) ret=01f7:1460 ds=01ff
Ret KERNEL.52: FREEPROCINSTANCE() retval=0x0001 ret=01f7:1460 ds=01ff
Call USER.1: MESSAGEBOX(0x0000,0x01ff1246 "Runtime error 219 at 0004:1056.",0x00000000,0x1010) ret=01f7:2160 ds=01ff

我認為本示例中對 MessageBox 的調用不是由以前調用的函數返回錯誤值引起的(經常發生這樣的情況),而是消息框里面提到的:0x0004:0x1056 處出現運行時錯誤。由于地址的段值僅為 4,因此我認為這只是一個內部值。但偏移地址揭示了一些非常有趣的內容,偏移 0x1056 非常接近 FREELIBRARY 的返回地址:

Call KERNEL.96: FREELIBRARY(0x031f) ret=01cf:105c ds=01ff
                       ^^^^

如果段 0x0004 確實是段 0x1cf,我們可以反匯編調用 FreeLibrary 的地址,分析發生運行時錯誤之前的某些行。

3. 如果希望設置某個位置的斷點,但該斷點所在的模塊還沒有映射到內存里面,則可以將斷點設置為 GetVersion16/32 函數,因為這些函數被調用很頻繁,斷點停下來的時候執行continue 命令直到您能夠設置此斷點而不再顯示錯誤消息。

調試器的基本用法

使用winebg myprog.exe 啟動程序后,程序加載并在起點處停止,終端顯示 winedbg 命令行提示符。然后,您可以這樣設置斷點:

b RoutineName (按函數名稱加斷點)或
b *0x812575  (按地址加斷點)

然后,您輸入 c(continue命令簡寫)來運行程序。當它停在斷點處后,您可以鍵入:

step      (一次步進一行)或
stepi      (一次步進一個機器指令;它有助于了解386基本指令集)
info reg    (查看寄存器)
info stack   (查看堆棧中的十六進制值)
info local   (查看局部變量)
list 行號    (列出源代碼)
x 變量名稱   (檢查變量;僅當代碼關閉優化編譯時候有效)
x 0x4269978   (檢查內存位置的內容)
?        (幫助)
q        (退出)

直接按 Enter,您可以重復最后一個命令。

有用的程序

一些有用的程序:

IDA:IDA Pro 是強烈推薦的,但不是免費的。

pedump:http://pedump.me/,轉儲 PE 格式的 DLL 的導入和導出。

winedump:(包括在 Wine 中),轉儲 PE 格式的 DLL 的導入和導出。

配置

Windows 調試配置

Windows 調試 API 使用這個注冊表項來指明發生未處理異常時要調用哪個調試器。

[MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug]

有兩個值來決定行為:

Debugger 指定用于啟動調試器的命令行(它使用兩個 printf 格式占位符 %ld將上下文相關信息傳遞給調試器)。您應該在這里放置一個您的調試器的完整路徑 ( winedbg 當然可以使用,但任何其他使用 Windows 調試 API 的調試器也可以 )。您選擇使用的調試器的路徑必須通過 Wine 容器根目錄的 dosdevices 子目錄里面配置的 DOS 驅動器之一進行訪問。

Auto 如果此值為零,在發生未處理異常時將彈出對話框詢問用戶是否希望啟動調試器。否則,調試器將自動啟動。

默認的 Wine 注冊表如下所示:

[MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug] 957636538
"Auto"=dword:00000001
"Debugger"="winedbg %ld %ld"

注意 1: 創建這個注冊表項是必需的。如果不這樣做,在發生異常時不會觸發調試器。

注意 2: wineinstall(Wine 附帶的) 創建這個注冊表項。但是由于安裝的注冊表存在一些限制,如果存在以前的 Wine 安裝,則先刪除整個[MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug] ,再運行 wineinstall 以重新創建才是安全的。

Winedbg 配置

Winedbg 可通過多種選項進行配置。這些選項按用戶存儲在注冊表中:[HKCU\Software\Wine\WineDbg]

這些選項可以在 winedbg 里面讀取/寫入,作為調試器表達式的一部分。要引用這些選項之一,其名稱必須以$ 符號為前綴。例如:

set $BreakAllThreadsStartup = 1

將BreakAllThreadsStartup 選項設置為 TRUE。

所有選項在 winedbg 啟動時從注冊表中讀取(如果未找到相應的值,則使用默認值),并在 winedbg 退出時寫回注冊表。

下面是所有選項的列表:

BreakAllThreadsStartup 如果為 TRUE 則在所有線程啟動時調試器停止;如果為 FALSE 僅在給定進程的第一個線程啟動時調試器停止。默認情況下為 FALSE。

BreakOnCritSectTimeOut 如果為 TRUE 則當臨界區超時(5 分鐘)時調試器停止;默認情況下為 TRUE。

BreakOnAttach 如果為 TRUE 則在未處理異常發生后 winedbg 附加到進程時,在第一個附加事件中停下來。由于附加事件在異常事件的上下文中沒有意義,因此該選項最好是 FALSE。

BreakOnFirstChance 異常生成兩個調試事件。第一個是在異常發生之后傳遞到調試器(稱為第一次機會)。調試器可以決定恢復執行(通過 winedbg cont 命令)或將異常傳遞給程序中的異常處理程序鏈(如果存在)(winedbg 通過 pass 命令)。如果異常處理程序沒有處理異常,則異常事件將再次發送到調試器(稱為最后一次機會)。調試器不能傳遞最后一次機會的異常。如果 BreakOnFirstChance 為 TRUE ,則第一次機會異常和最后一次機會異常發生時 winedbg 都停止;如果為 FALSE,僅在最后一次機會異常是停止。

配置 +relay 行為

將WINEDEBUG 設置為+relay 調試時,可能會得到大量輸出日志。您可以通過把注冊表中[HKCU\Software\Wine\Debug] 下的 RelayExclude 鍵值設置為用分號分隔的要排除的函數列表,例如:

"RtlEnterCriticalSection;RtlLeaveCriticalSection;kernel32.97;kernel32.98"

RelayInclude 和RelayExclude 類似,只不過列出的函數將是輸出中僅包含的函數。

如果應用程序使用+relay 運行速度太慢無法獲得有意義的輸出,并且對生成的幾 GB 的日志文件束手無策,不確定要排除哪些函數,下面是一個技巧。首先,運行應用程序一分鐘左右,將其輸出重定向到磁盤上的文件:

WINEDEBUG=+relay wine appname.exe &>relay.log

然后運行此命令以查看調用最多的函數:

awk -F'(' '{print $1}' < relay.log | awk '{print $2}' | sort | uniq -c | sort

在確保這些函數不相關后使用RelayExclude 排除調用最多的函數,然后再次運行應用程序。

Winedbg 表達式和變量

表達式

Winedbg 中的表達式大多以 C 形式編寫。但是有一些差異:

標識符的名稱中可以加一個!,這主要區分不同 DLL 的符號,如USER32!CreateWindowExA 表示 USER32.DLL 里面的 CreateWindowExA 函數。

在強制轉換操作中,在指定結構或聯合時,必須使用struct 或union 關鍵字(即使程序使用typedef)。

當按名稱指定標識符時,如果存在多個相同名稱的符號,調試器將提示用戶要選擇哪個符號,輸入你想要的那個符號前面的數字序號即可。

變量

Winedbg 定義自己的變量集。上面的配置變量是其中的一部分。其他包括:

$ThreadId 當前調試的W-thread 的 ID

$ProcessId 當前調試的W-process 的 ID

寄存器變量 所有 CPU 寄存器用"$"前綴加寄存器名來訪問。您可以使用info regs 來獲取 CPU 寄存器的名稱列表。

$ThreadId 和$ProcessId變量可以很方便地在指定的線程或進程上設置條件斷點。

Winedbg 命令參考

雜項

abort      中止調試器
quit      退出調試器
attach N    附加到 `W-process` 進程(N 是其 ID,10進制數字或十六進制 (0xN))。
         ID 可以使用 `info process` 命令獲取。請注意,`info process` 命令返回的是十六進制值。
detach     從 `W-process` 進程分離。
help      打印一些幫助
help info    打印一些 info 命令的幫助

流程控制

cont,c     繼續運行直到下一個斷點或異常。
pass      將異常事件傳遞給異常處理鏈。
step,s     繼續執行,直到下一行"C"代碼(進入函數內部)
next,n     繼續執行,直到下一行"C"代碼(不進入函數內部)
stepi,si    執行下一個指令(進入函數內部)
nexti,ni    執行下一個指令(不進入函數內部)
finish,f    執行,直到當前函數返回

cont、step、next、stepi、nexti 命令后面可以加一個數字 (N) 參數,表示命令執行 N 次。

斷點、監視點

enable N    啟用編號為 N 的斷點或監視點
disable N    禁用編號為 N 的斷點或監視點
delete N    刪除編號為 N 的斷點或監視點
cond N     刪除編號為 N 的斷點或監視點的條件
cond N expr   設置編號為 N 的斷點或監視點的條件;每次斷點命中時,都會計算表達式 expr ,如果結果為零值,則不觸發斷點。
break *N    在地址 N 處添加斷點
break ID    在符號 ID 的地址添加斷點
break N     在當前源文件的第 N 行添加斷點
watch *N    在地址 N 處添加寫監視點
watch id    在符號 ID 的地址添加寫監視點
info break   列出所有斷點或監視點的狀態

您可以使用符號 EntryPoint 代表 DLL 的入口點。

在按符號名稱設置斷點或監視點時,如果找不到符號(例如,符號所在模塊還沒有加載),winedbg 將記住符號的名稱,并在每次加載新模塊時嘗試設置該斷點(直到成功)。

棧幀操作

bt       打印當前線程的調用棧
bt N      打印線程ID為 N 的線程的調用堆棧(注意:這不會更改當前幀的位置,因為它們由down和up命令操縱)
up       當前線程棧中向上移動一幀
up N      當前線程棧中向上移動 N 幀
down      當前線程棧中向下移動一幀
down N     當前線程棧中向下移動 N 幀
frame N     設置 N 為當前線程棧的當前幀
info local   列出當前幀的局部變量信息

目錄和源文件操作

show dir    打印查找源文件的目錄列表
dir pathname  將 pathname 指定的目錄添加到查找源文件的目錄列表里面
dir       清空查找源文件的目錄列表
list      列出當前位置開始的10行源碼
list -     列出當前位置往后的10行源碼
list N     列出當前文件中從 N 行開始的10行源碼
list path:N   列出 path 指定的文件的第N行開始的10行源碼
list id     列出函數 ID 的10行源碼
list *N     列出地址 N 開始的10行源碼

您還可以使用逗號分隔來指定一段范圍。例如:

list 123,234    列出當前文件的第 123 行到 234 行
list foo.c:1,56   列出foo.c文件的第 1 行到 56 行

顯示

顯示是在執行任何 winedbg 命令后計算并打印的表達式。

Winedbg 將自動檢測您輸入的表達式是否包含局部變量。如果包含,則僅當上下文所在函數與設置顯示表達式時所在的函數一樣時,才會顯示該局部變量的值。

info display    列出所有的活動顯示
display       查看所有活動顯示的值(在每次調試器停止時都執行)
display expr    添加表達式 expr 的顯示
display /fmt expr  添加給定格式打印 expr 的值的顯示(有關格式的更多信息,請參閱下文的打印命令用法)
undisplay N     刪除顯示編號為 N 的顯示

反匯編

disas        從當前位置反匯編
disas expr     從 expr 指定的地址反匯編
disas expr,expr   在兩個 expr 指定的地址之間反匯編

內存(讀取、寫入、查看)

x expr             查看 expr 指定的地址處的內存
x /fmt expr           使用格式 fmt 查看 expr 指定的地址處的內存
print expr           打印 expr 的值(可能使用其類型)
print /fmt expr         使用格式 fmt 打印 expr 的值
set lval=expr          在 lval 中寫入 expr 的值
whatis expr           打印表達式 expr 的 C 類型
set !symbol_picker interactive 在打印值時,如果找到多個符號,詢問用戶要選取哪個符號(默認)
set !symbol_picker scoped    在打印值時,局部符號優先于全局符號

fmt 是字母或個數加字母(個數和字母之間沒有空格),其中字母可以是以下字符:

s 表示 ASCII 字符串

u 表示 Unicode UTF16 字符串

i 表示一個指令 (反匯編)

d 表示十進制顯示 32位符號整數

x 表示十六進制顯示 32位無符號整數

w 表示十六進制顯示 16位無符號整數

b 表示十六進制顯示 8位無符號整數

c 表示 ASCII 字符(僅打印可打印的 0x20-0x7f 之間的字符)

g 表示 GUID

查看 Wine 內部信息

info class   列出在 Wine 中注冊的所有 Windows 類
info class id  打印 Windows 類 ID 上的信息
info share   列出調試程序加載的所有模塊信息(包括 .so 文件、NE 和 PE DLL)
info share N  打印地址 N 對應的模塊的信息
info regs    打印 CPU 寄存器的值
info all-regs  打印的CPU和浮點寄存器的值
info stack   打印棧頂部96個字節
info map    列出調試程序使用的所有虛擬映射
info map N   列出 wpid 為 N 程序使用的所有虛擬映射
info wnd    列出從桌面窗口開始的所有窗口層次結構
info wnd N   打印句柄為 N 的窗口的信息
info process  列出當前容器里面的所有 W-process 進程信息
info thread   列出當前容器里面的所有 W-thread 線程信息
info exception 列出異常幀(從當前棧幀開始)

調試通道

在進行調試時,可以使用 set 命令打開和關閉調試通道(僅適用于WINEDEBUG環境變量中指定的調試通道)。有關調試通道的更多詳細信息,請參閱 Wine 開發者指南 第 2 章。

set + warn channel   打開指定通道的 warn 類日志
set + channel      打開指定通道的 warn/fixme/err/trace 類日志
set - channel      關閉指定通道的 warn/fixme/err/trace 類日志
set - fixme       關閉`fixme`類日志

bt 命令列出的調用堆棧說明

一般情況下,bt 命令輸出如下的信息:

Wine-dbg>bt
Backtrace:
=>0 0x7b83c640 UnhandledExceptionFilter(epointers=0x65f948) [/home/deepin/deepin-wine/dlls/kernel32/except.c:426] in kernel32 (0x0065f958)
 1 0x7bc7ef39 call_exception_handler+0x28() in ntdll (0x0065f988)
 2 0x7bc7ef0b EXC_CallHandler+0x1a() in ntdll (0x0065f9a8)
 3 0x7bc7f851 raise_exception+0x3a0(rec=0x65fd58, context=0x65fa8c, first_chance=) [/home/deepin/deepin-wine/dlls/ntdll/signal_i386.c:698] in ntdll (0x0065fa18)
 4 0x7bc8172e NtRaiseException+0x2d(rec=, context=, first_chance=) [/home/deepin/deepin-wine/dlls/ntdll/signal_i386.c:2840] in ntdll (0x0065fa38)
 5 0x7bc81e3b raise_generic_exception+0x2a(rec=, context=) [/home/deepin/deepin-wine/dlls/ntdll/signal_i386.c:2167] in ntdll (0x0065fa78)
 6 0xdeadbabe (0x0065fdd8)
 7 0x0040138b in a (+0x138a) (0x0065fe68)
 8 0x7b85f7ec call_process_entry+0xb() in kernel32 (0x0065fe88)
 9 0x7b860769 start_process+0x68(entry=) [/home/deepin/deepin-wine/dlls/kernel32/process.c:1124] in kernel32 (0x0065fec8)
 10 0x7bc7eebc call_thread_func_wrapper+0xb() in ntdll (0x0065fedc)
 11 0x7bc82069 call_thread_func+0xa8(entry=0x7b860700, arg=0x4014a0, frame=0x65ffec) [/home/deepin/deepin-wine/dlls/ntdll/signal_i386.c:2962] in ntdll (0x0065ffcc)
 12 0x7bc7ee9a call_thread_entry_point+0x11() in ntdll (0x0065ffec)

其中

第1列的數字是函數調用棧的幀號,比如上面的輸出有13層調用,當前棧幀號是0,也就是調用棧的最底層的函數。這個編號的用途是用來切換棧幀的,執行命令frame N N是要查看的棧幀編號就可以切換到指定的棧幀。

第2列是每層調用棧幀的上一層函數返回地址的16進制表示,,比如上面的輸出里面編號是12的棧幀的第2列數字是0x7bc7ee9a 就是表示在函數call_thread_entry_point內部調用函數call_thread_func之后的返回地址。

第3列是第2列函數返回地址的符號名稱,目的是增加可讀性,有2種情況:

函數名稱+偏移地址來表示,比如上面的棧幀12的call_thread_entry_point+0x11;

如果 winedbg 就找不到地址對應的函數名稱,就用所在函數所在的模塊名加一個偏移地址表示, 比如上面的棧幀7的in a (+0x138a) 表示函數調用地址是在 a 模塊的首地址+0x138a字節處。

第4列是函數參數,如果沒有調試符號或者函數本身沒有參數,就不顯示;對于顯示參數的,參數值可能讀取不到的會以來表示。

第5列是對應的源碼,如果找不到源碼,就不顯示。

in 后面的單詞名稱是所在的模塊,比如棧幀12所在模塊是 ntdll.dll 。

最后一列括號括起來的數字是當前棧幀的 ESP 寄存器值,即局部變量的起始內存區域。

從上面這個堆棧來看,我們可以得到如下信息:

程序是在執行到 0xdeadbabe 觸發了異常,異常信息保存在 raise_exception的 第1個參數 rec 結構體里面。

調用 0xdeadbabe 的函數返回地址是0x0040138b。該異常沒有對應的處理函數,最終交由 UnhandledExceptionFilter 函數處理。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 調試
    +關注

    關注

    7

    文章

    586

    瀏覽量

    34001
  • 函數
    +關注

    關注

    3

    文章

    4344

    瀏覽量

    62809
  • 進程
    +關注

    關注

    0

    文章

    204

    瀏覽量

    13971

原文標題:Wine 開發系列 —— 如何調試 Wine

文章出處:【微信號:linux_deepin,微信公眾號:深度操作系統】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    調試嵌入式處理器常用方法有哪些?

    調試嵌入式處理器常用方法有哪些?
    發表于 12-24 06:08

    分享一些以太網常用調試方法

    對于單phy的平臺以太網技術已經很成熟,這里提供一些以太網常用調試方法。幫助客戶快速定位常見問題。 以太網常用的命令有哪些呢?如何對其進行調試
    發表于 12-29 07:32

    調試嵌入式處理器的幾種常用方法

    調試嵌入式處理器的幾種常用方法 前言 在任何產品
    發表于 03-11 12:25 ?1621次閱讀
    <b class='flag-5'>調試</b>嵌入式處理器的幾種<b class='flag-5'>常用</b><b class='flag-5'>方法</b>

    常用網絡調試工具

    [4]常用網絡調試工具_v1.0rc
    發表于 12-27 16:26 ?0次下載

    linux下wine的使用

    Wine 仍在發展階段,僅能執行少部份的 Windows 軟體,大部份的軟體仍然無法正常執行。 Wine的官方站點是http://www.winehq.com/,雖然你可以在它的官方站點下載源代碼
    發表于 11-07 15:37 ?14次下載

    Wine 5.4版本更新更多新功能

    IT之家了解到,WineWine Is Not an Emulator)是一個能夠在多種 POSIX-compliant 操作系統(包括 Linux,Mac OSX 及 BSD 等)上運行 Windows 應用的兼容層。
    的頭像 發表于 03-14 09:33 ?2365次閱讀

    Wine中將提供Windows應用程序與USB更好支持

    Wine 中運行的 Windows 應用程序直接與 USB 設備交互將會有更好的支持。Wine 項目的提交記錄顯示,最新合并的 WineUSB 初始部分將成為 Wine USB 驅動,類似于微軟的 WinUSB。
    的頭像 發表于 04-19 09:52 ?2576次閱讀
    <b class='flag-5'>Wine</b>中將提供Windows應用程序與USB更好支持

    單片機程序常用的幾種調試方法

    單片機程序常用的幾種調試方法,這些調試方法都需要結合電腦上位機,以下我羅列一些調試
    發表于 07-17 09:31 ?1.3w次閱讀

    介紹常用調試命令、利用在線匯編、各種設置斷點進行程序調試方法資料下載

    電子發燒友網為你提供介紹常用調試命令、利用在線匯編、各種設置斷點進行程序調試方法資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指
    發表于 04-16 08:42 ?19次下載
    介紹<b class='flag-5'>常用</b>的<b class='flag-5'>調試</b>命令、利用在線匯編、各種設置斷點進行程序<b class='flag-5'>調試</b>的<b class='flag-5'>方法</b>資料下載

    shell腳本常用調試方法介紹

    軟件、配置編譯環境,可以說使用起來非常的方便,但是它在調試方面常常令人頭大,本文主要介紹shell腳本常用調試方法 調試
    的頭像 發表于 09-01 10:43 ?3312次閱讀

    常用藍牙調試工具分享

    該部分主要分享一下常用的藍牙調試工具,方便后續藍牙抓包及分析。
    的頭像 發表于 07-25 10:16 ?6765次閱讀

    單片機常用調試方法

    在單片機程序調試過程中,串口打印調試方法是非常重要的手段,在使用串口調試時,我們更多的是使用printf。但是下面我們不介紹printf,介紹一下另外幾種我們
    的頭像 發表于 04-04 14:58 ?4964次閱讀

    常用的遠程控制方法總結

    開個新系列,寫一下在調試工作中,常用的遠程控制方法
    的頭像 發表于 09-06 15:32 ?2278次閱讀
    <b class='flag-5'>常用</b>的遠程控制<b class='flag-5'>方法</b>總結

    Wine原理介紹和開發教程

    說起 Wine,稍微資深一點的 Linux 用戶應該都聽過,但是真要說起 Wine 到底是怎么回事,可能大多數人不見得說得清。這篇文章會簡單地介紹 Wine 的工作原理,以及如何開始 Wine
    的頭像 發表于 12-31 10:06 ?220次閱讀

    Wine開發系列——如何使用Wine日志調試問題

    ? 輸出調試日志是調試程序的一種常見方法,尤其是處理那些難以捉摸的多線程錯誤、隨機崩潰等問題時。 通過在合適的位置輸出調試日志,可以幫助我們更快地定位問題所在。 對于不熟悉的代碼,經常
    的頭像 發表于 01-06 11:29 ?103次閱讀
    主站蜘蛛池模板: 欧美午夜影院| 免费一看一级毛片| 久久天天干| 超级狂色而且免费又超好看| 日本护士撒尿| 91九色蝌蚪在线| 91大神免费视频| 干干干日日日| 免费观看一级特黄欧美大片| 新天堂网| 国产色爽女小说免费看| 青草青草视频2免费观看| 婷婷99| 欧美影院| 成人理伦| 国产精品资源在线观看网站| 涩色影院| 午夜国产视频| 欲色淫香| 不卡中文字幕在线| 午夜视频观看| 天天做天天爱天天干| 91久久另类重口变态| ww欧洲ww在线视频看| 仙踪林欧美另类视频| 久久人人视频| 91av视频在线| 特黄aa级毛片免费视频播放| 丁香六月啪啪| 女69女人poren25| 日本人xxxxxxxx6969| 97精品久久天干天天蜜| 高清影院在线欧美人色| 亚洲欧美视频在线播放| 午夜三级网站| 一级做a爰片久久毛片毛片| 影院成人区精品一区二区婷婷丽春院影视 | 国产伦子一区二区三区四区| 国产精品女仆装在线播放| 国产高清视频在线播放www色| 天天做天天爽|