[GDB] 在 dlopen/dlclose 函式設定中斷點,觀察 DLL 的載入與卸載過稱

[GDB] 在 dlopen/dlclose 函式設定中斷點,觀察 DLL 的載入與卸載過稱

今天在查一個 Linux 上的 shared library 沒有釋放掉的問題,

從程式來看,應該呼叫 dlopen() 和 dlclose() 的次數是相當的,

不過因為中間牽扯到其他的 .so 檔,有點不太能肯定會不會有什麼例外,

想說有沒有方法可以確定 dlopen 和 dlclose 各被呼叫了幾次呢?

 

後來想到用 gdb 在 dlopen/dlclose 上設中斷點的方式來觀察~

像下面的例子就是在 dlopen 上設了中斷點後,繼續執行程式,

但最好是在接近要觀察的點再打開這個中斷點,不然程式一開始可是會載入非常多的 .so 的:

(gdb) b dlopen
Breakpoint 2 at 0x7fffdf376b50 (10 locations)
(gdb) c
Continuing.

 

當 dlopen 被呼叫到時,由它的參數可以得知,第一個參數就是 DLL 的名稱,

在 x64 環境下,第一個參數會用 rdi 來傳遞

因此可以秀出 rdi 指到的字串內容,就是 DLL 的名稱了 (本例中的 7z.so):

Breakpoint 2, 0x00007fffdf376b50 in dlopen@plt () from /lib/lib7zip.so.0
(gdb) x/s $rdi
0x1be7468:	"7z.so"

 

按 c 繼續程式的執行,下一次的 dlopen() 開啟的是 Rar.so:

(gdb) c
Continuing.
Breakpoint 2, 0x00007fffdf376b50 in dlopen@plt () from /lib/lib7zip.so.0
(gdb) x/s $rdi
0x1d14d48:	"/p7zip/Codecs/Rar.so"

 

不過每次停在中斷點時都得自己打 x/s $di 有點麻煩,

其實可以利用 gdb 可以在中斷點上加上命令的功能,自動執行某些指令~

用 command <中斷點號碼> 這個指令,接下來就可以打想要執行的指令,最後 end 結束~

像我先用 x/s $rdi 印出第一個參數 (DLL 名稱),

接著用 fin (finish) 執行完 dlopen() 後,再用 p/x $rax 印出函式的回傳值:

(gdb) command 2
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>x/s $rdi
>fin
>p/x $rax
>end

 

重新執行程式,當 dlopen 的中斷點彈出時,的確自動秀出 DLL 的名稱 7z.so 了,

而且 fin 指令也執行了,但卻沒有執行 p/x 指令秀出 dlopen 的回傳值…

這一點還不知道為什麼… 只好手動自己打了,傳回的 handle 是 0x1daf3a0:

Breakpoint 2, 0x00007fffdf376b50 in dlopen@plt () from /lib/lib7zip.so.0
0x1c87a78:	"7z.so"
Load7ZLibrary (name=L"7z") at OSFunctions_UnixLike.cpp:173
173	  if (pHandler)
(gdb) p/x $rax
$10 = 0x1daf3a0
(gdb) c
Continuing.

 

繼續執行,接下來 dlopen 開啟的是 Rar.so,handle 是 0x1c05ef0:

Breakpoint 2, 0x00007fffdf376b50 in dlopen@plt () from /lib/lib7zip.so.0
0x1c03e08:	"/p7zip/Codecs/Rar.so"
myselect (pDir=pDir@entry=0x1dfa3b0) at OSFunctions_UnixLike.cpp:112
112	      if (pHandler != NULL)
(gdb) p/x $rax
$11 = 0x1c05ef0
(gdb) c
Continuing.

 

同樣在 dlclose 上設定中斷點,可以看到第一個要關閉的 handle 是 0x1c05ef0,

這也就是剛剛開啟 Rar.so 得到的 handle,

而第二個關閉的就是 7z.so 的 handle 0x1daf3a0:

Breakpoint 3, __dlclose (handle=0x1c05ef0) at dlclose.c:43
43	  if (__builtin_expect (_dlfcn_hook != NULL, 0))
(gdb) c
Continuing.
Breakpoint 3, __dlclose (handle=0x1daf3a0) at dlclose.c:43
43	  if (__builtin_expect (_dlfcn_hook != NULL, 0))

 

運用上述的方法,就可以確認 dlopen/dlclose 是否有如自己預期的在運作囉~

 

參考資料:

stackoverflow: Inspect the return value of a function in gdb

stackoverflow: Do specific action when certain breakpoint hits in gdb

(本頁面已被瀏覽過 468 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料