WINE 使用及其調試

一、Wine

 

1、 wine 實現了大多數的windows API,集成了winedbg

2、 windows API

1) kernel32.dll 

允許一個W-process作爲debugger 去執行另一個W-process,作爲debuggee,包括設置breakpoint,單步執行等等

2) DBGHELP.DLL

讓一個debbuger從任意模塊查找符號和類型

3、 異常解決

怎麼根據下面信息查找crash原因

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  71930000-719b8000   Deferred        shdoclc

PE  78130000-781cb000   Deferred        msvcr80

ELF 79afb000-7b800000   Deferred        libnvidia-glcore.so.304.51

ELF 7b800000-7ba3d000   Dwarf           kernel32<elf>

  \-PE  7b810000-7ba3d000   \               kernel32

ELF 7bc00000-7bcd5000   Dwarf           ntdll<elf>

  \-PE  7bc10000-7bcd5000   \               ntdll

ELF 7bf00000-7bf04000   Deferred        <wine-loader>

ELF 7c288000-7c400000   Deferred        libvorbisenc.so.2

PE  7c420000-7c4a7000   Deferred        msvcp80

ELF 7c56d000-7c5b6000   Deferred        dinput<elf>

 

Threads:

process  tid      prio (all id:s are in hex)

00000008 (D) C:\Perfect World Entertainment\Perfect World International\element\elementclient.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

 

下面信息的含義:

000d:Call advapi32.RegOpenKeyExW(00000090,7eb94da0 L"Patterns",00000000,00020019,0033f968) ret=7eb39af8

 

000d: 線程id

advapi32: 被調用模塊

RegOpenKeyExW: 被調用函數

後面幾個都是參數

ret :返回地址

 

4、 Useful memory address

1)  32

linux: 0x08000000 0x00400000 0x40000000  

 

2)  16位(增強模式): segment:offset

segment 如果最低三比特位都是1,就是一個selector,如果最低三筆特除了最低位外都是1,可能是全局內存

0x1f7 (0x40320000, 0x0000ffff, r-x) : 分別是基地址,最大偏移,訪問權限 r-x 表示可讀可執行

實際地址: selector基地址+offset

 

3)  16位(標準模式):segment:offset

segmentoffset可以是0~0xffff

實際地址: segment×16+offset

 

5、 配置

 

1)  配置debuger

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

"Auto"=dword:00000001

"Debugger"="winedbg %ld %ld"

 

2)  配置winedbg

[HKCU\\Software\\Wine\\WineDbg]

BreakAllThreadsStartup TRUE:所有線程停止  FALSE:第一個線程停止

BreakOnCritSectTimeOut TRUE:在臨界區超時5分鐘停止 FALSE:不停止

BreakOnAttach 

BreakOnFirstChance  

一個異常產生兩個debug 事件,或者說兩次chance

first chance:發生異常之後傳遞給debuggerdebugger 要麼繼續執行(cont),要麼交給exception handler chainpass

last chance:如果沒有exception handler 處理異常,會再次傳遞給debugger,這一次不能pass

 

TRUE: 兩次機會都會處理 FALSE :僅僅進入last chance

 

AlwaysShowThunk  TRUE:根據名稱顯示所有thunks   FALSE

 

3)  +relay 行爲配置

可能輸出會很多,但可以進行設置

[HKCU\\Software\\Wine\\Debug]

RelayExclude  列出不需要的輸出

RelayInclude  僅輸出列出的輸出

怎麼知道哪些輸出是不需要的?

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

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

 

 

二、WineDbg

1、 WineDbg表達式

同 格式總體相同,有少量差異。

1) 表達式名稱裏可以用 ! 

2) 轉換操作時 結構體或聯合體都需要帶 struct union 關鍵字

 

winedbg 特殊變量:$ThreadId 即 W-thread id

$ProcessId 即 W-process id

所有CPU寄存器值也是變量

2、 WineDbg 命令

Misc commands

NO.

command

Details

1

abort

abort the debbuger

2

quit

Quit the debbuger

3

Attach W-process ID

附加到另一個進程

4

Detach

分離進程

5

help

 

6

help info

 

 

Flow control commands

NO.

command

Details

1

cont, c

繼續執行

2

pass

傳遞異常給filter chain

3

steps

單步,進入函數調用

4

stepi,si

單個指令

5

next ,n

單步,不進入函數

6

nexti ,ni

單個指令,不進入調用

7

finish ,f

執行直到當前函數退出

Breakpoints, watch points

NO.

command

Details

1

enable N

激活break|watch point N 

2

disable N 

禁用 break|watch point N

3

delete N

刪除 break|watch point N

4

cond N

移除任何到 break|watch point N 的條件

5

cond N expr

按表達式設置breakpoint N觸發條件

6

break * N 

增加breakpoint N(N爲地址)

7

break id

增加breakpoint 符號id的地址 ??

8

break id N

符號id 的第N行  ??

9

break N

當前源文件的第N

10

break

當前$PC 地址設置breakpoint

11

watch * N

觀察指令,* N 爲地址

12

watch id

符號id的地址

13

info break

列出所有 break|watch point

Stack manipulation

NO.

command

Details

1

bt

打印當前線程棧調用

2

bt N

打印線程IDN的線程棧調用

3

up

往上走 1 frame ??

4

up N

往上走 N frame

5

dn

往下走1frame

6

dn N

 

7

frame N

執行直到當前函數退出

8

info local

局部變量

Directory & source file manipulation

NO.

command

Details

1

show dir

打印源文件查找目錄

2

dir pathname

增加路徑到查找目錄列表

3

dir

刪除查找目錄列表

4

symbolfile pathnamme

加載外部符號定義

5

symbolfile pathname N

同上,但是有個偏移地址N

6

list  /-/N/file:N

默認列出10行代碼,-向後列出

7

list id

列出函數id處的10行代碼

8

list * N 

列出地址N10行代碼

9

list N1,N2

列出從N1行到N2行的源碼

10

list file:N1,N2

列出文件file N1行到N2行的源碼

Displaying

NO.

command

Details

1

info display

??

2

display

 

3

display expr

 

4

display lfmt expr

按格式輸出

5

del display N,undisplay N

刪除display

Disassembly

NO.

command

Details

1

disas

反彙編

2

disas expr

指定地址出彙編代碼

3

disas expr,expr

兩個地址之間的彙編

Memory (reading, writing, typing)

NO.

command

Details

1

x expr/lfmt expr

顯示地址出的值 ,格式??

2

print expr/lfmt expr

打印表達式的值

3

set lval=expr

設置變量

4

whatis expr

打印類型的表達式

5

set!symbol_picker interactive

打印的時候由用戶決定選那個符號

6

set!symbol_picker scopedb

優先局部符號,然後纔是全局的

v fmt  可以是 letter 或 count letter ??

s   ascii string

u   utf16 string

i    指令

x   32-bit 無符號16進制整數

d   32-bit 無符號10進制整數

w   16-bit無符號16進制整數

c    可打印字符,0x20~0x70 實際是可打印的

b    8-bit 無符號16進制整數

g    GUID

 

Information on Wine internals

NO.

command

Details

1

info class

列舉所有窗口類

2

info class id

關於窗口類id的信息

3

info share

列舉所有動態庫,sodll

4

info share N

地址N的模塊信息

5

info regs

CPU寄存器信息

6

info all-regs

CPU 和浮點寄存器

7

info segment N

segment N的信息,僅i386

8

info segment

所有segment ,僅i386

9

info stack

棧信息

10

info map

debbuger 的虛擬映射

11

info map N

wpid N 的虛擬映射

12

info wnd N

打印窗口N的信息

13

info wnd

列舉從桌面開始的所有窗口層次

14

info process

列舉wine回話中所有w-processes 

15

info thread

列舉所有w-threads

16

info exception

異常信息

Debug channels

NO.

command

Details

1

set + warn

打開warn channel

2

set + channel

打開warn/fixme/err/trace

3

set - channel

關閉上述channel

4

set - fixme

關閉 fixme

 

 

三、其他Debuggers

1.GDB 模式

winedbg是一個遠程gdb 監視器,增加 --gdb 即可激活gdb模式。

gdbwinegdb的區別

winegdb 掌控一個進程的所有線程,可以處理所有線程斷點。gdb只能對單個線程進行調試。

Winegdb支持 stabsstandard Unix format) 和CCodeView,.DBG(Microsoft). gdb 支持stabs 和 Dwarf II

2.DDD

如下命令: 

winedbg --gdb --no-start  *.exe  optional param

然後把輸出: target remote localhost12345 粘貼到ddd即可運行

 

3.kdbg

其他同ddd,運行時在kdbg終端運行: kdbg -r localhost:12345 wine

 

 

四、調試技巧

1、 debuging classes

FIXME

ERR

WARN

TRACE

MESSAGE

2、 debugging channels

每個組件都會有一個channel

設置方法: 

WINE_DEFAULT_DEBUG_CHANNEL(xxx);

如果要有多個channel,則增加多個名稱不同即可。

使用的時候,需要使用類似FIXME_(xxx)(fmt,...); 此時FIXMEfmt,...;指向第一個聲明channel

 

TRACE_ON WARN_ON ERR_ON FIXME_ON 用來判斷是否打開了

3、 一些有用的函數

 

1)  debugres

LPSTR debugres(const void* id);

id: 資源id指針

返回:字符串類型,格式化字符串

2)  debugstr_[aw]n

 

處理某些NULL,控制字符或太長,或需要轉換成ascii,都可以使用這些函數處理

 

 

4、 修改調試輸出

第一種方法: 使用winedbg 命令

第二種方法: 通過taskmgr修改

第三種方法:創建pipe 和運行 WINEDEBUG

mknode  /tmp/debug_pipe p

WINEDEBUG=+relay,+snoop wine setup.exe &>/tmp/debug_pipe

cat  /tmp/debug_pipe

WINEDEBUG 格式:

WINEDEBUG=[yyy]#xxx[,[yyy1]#xxx1]*

yyy: tracedebugwarnfixmeerr等,fixme err 默認是激活的,tracewarn 默認是沒激活的

#: + 或 

xxx: channelall 表示所有channel

可以用 , 隔開添加多個

如果使用MessageBox,則

WINEDEBUG=+relay wine program_name &>relmsg

 

5、 風格上的一些注意

輸出格式: classchannelfunction  message

 

6、 一些其他技術

i386系統,棧是4字節,小端,地址向下增長,棧指針存放在esp寄存器,指向棧內存最後一次push 進去的數據的地址。可以表示爲: 

push操作: *(--esp) =p;  pop 操作:p=*(esp++);

 

額外補充:

1) 調用協議常用場合

__stdcallWindows API默認的函數調用協議。

 __cdeclC/C++默認的函數調用協議。

__fastcall:適用於對性能要求較高的場合。

2) 函數參數入棧方式

__stdcall:函數參數由右向左入棧。

__cdecl:函數參數由右向左入棧。

__fastcall:從左開始不大於4字節的參數放入CPUECXEDX寄存器,其餘參數從右向左入棧。

問題一:__fastcall在寄存器中放入不大於4字節的參數,故性能較高,適用於需要高性能的場合。

3) 棧內數據清除方式

 

__stdcall:函數調用結束後由被調用函數清除棧內數據。

__cdecl:函數調用結束後由函數調用者清除棧內數據。

__fastcall:函數調用結束後由被調用函數清除棧內數據。

問題一:不同編譯器設定的棧結構不盡相同,跨開發平臺時由函數調用者清除棧內數據不可行。

問題二:某些函數的參數是可變的,如printf函數,這樣的函數只能由函數調用者清除棧內數據。

問題三:由調用者清除棧內數據時,每次調用都包含清除棧內數據的代碼,故可執行文件較大。

4) C語言編譯器函數名稱修飾規則

 

__stdcall:編譯後,函數名被修飾爲“_functionname@number”。

__cdecl:編譯後,函數名被修飾爲“_functionname”。

__fastcall:編譯後,函數名給修飾爲“@functionname@nmuber”。

注:“functionname”爲函數名,“number”爲參數字節數。

注:函數實現和函數定義時如果使用了不同的函數調用協議,則無法實現函數調用。

5) C++語言編譯器函數名稱修飾規則

 

__stdcall:編譯後,函數名被修飾爲“?functionname@@YG******@Z”。

__cdecl:編譯後,函數名被修飾爲“?functionname@@YA******@Z”。

__fastcall:編譯後,函數名被修飾爲“?functionname@@YI******@Z”。

注:“******”爲函數返回值類型和參數類型表。

注:函數實現和函數定義時如果使用了不同的函數調用協議,則無法實現函數調用。

C語言和C++語言間如果不進行特殊處理,也無法實現函數的互相調用。

 

 

stdcall 調用: 

從右往左一次將參數push 進棧。例如: function(20,30,40,50);

push  50

push  40

push  30

push  20

//此時棧的狀況: 

other variable

50

40

30

20      <---  esp 指向這裏

call  function

//此時

other variable   <---  esp 指向這裏

但是這裏有個問題是調用函數如何知道被調用函數有多少個參數

有兩種方法: 第一,記錄棧偏移  第二,

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章