當GDB無法顯示so動态庫的資訊或者顯示資訊有誤時,通常是由于庫搜尋路徑錯誤導緻的,可使用set sysroot、set solib-absolute-prefix、set solib-search-path來指定庫搜尋路徑。
1. set sysroot 與 set solib-absolute-prefix 是同一條指令,實際上,set sysroot是set solib-absolute-prefix 的别名。
2. set solib-search-path設定動态庫的搜尋路徑,該指令可設定多個搜尋路徑,路徑之間使用“:”隔開(在Linux中為冒号,DOS和Win32中為分号)。
3. set solib-absolute-prefix 與 set solib-search-path 的差別:
總體上來說solib-absolute-prefix設定庫的絕對路徑字首,隻對絕對路徑有效;而solib-search-path設定庫的搜尋路徑,對絕對路徑和相對路徑均起作用。(編譯器自動連結的so庫多采用絕對路徑)。
詳細規則有:
set solib-search-path由于是路徑字首,是以隻能設定一個路徑,而solib-search-path可以設定多個搜尋路徑。
在載入動态庫資訊時Coredump會碰到兩種路徑:絕對路徑和相對路徑。編譯時連結的庫通常是絕對路徑,例如"/lib/libc.so.6"、"/lib/libdl.so.2"等,此時在Coredump檔案中也同樣儲存為絕對路徑;而程式用dlopen函數載入的so庫可能使用相對路徑,例如"./libddd.so",此時Coredump檔案原封不動地儲存相同的路徑。
為便于表述,用A表示set solib-absolute-prefix設定的路徑,R(A)表示A去掉根字首後的路徑(即去掉字首“/”符号),用Bn表示set solib-search-path設定的每一條路徑,用X表示Coredump中儲存的庫路徑,即待搜尋的庫檔案路徑,F(X)表示X中去掉目錄後的檔案名(路徑最後“/”符号後的字元串)。
對絕對路徑,搜尋順序是:
1) A/X // 先添加solib-absolute-prefix字首進行搜尋,成功則不再繼續,否則繼續2)
2) R(A)/X // 再把1)的根字首去掉後進行搜尋,成功則不再繼續,否則繼續3)
3) Bn/R(A)/X // 再在2)的基礎上逐一添加solib-search-path中的每條路徑進行搜尋,成功則不再繼續,否則繼續4)
4) Bn/F(X) // 再隻使用2)中的檔案名(去掉目錄段),并逐一添加solib-search-path中的每條路徑進行搜尋,成功則不再繼續,否則繼續5)
5) $PATH/R(A)/X // 在2)的基礎上使用環境變量$PATH中的每條路徑進行搜尋,成功則不再繼續,否則繼續6)
6) $LD_LIBRARY_PATH/R(A)/X // 在2)的基礎上使用環境變量$LD_LIBRARY_PATH中的每條路徑進行搜尋,成功則不再繼續,否則繼續7)
7) 傳回失敗
部落客注:在gdb中設定環境變量,如LD_LIBRARY_PATH可以通過以下gdb指令實作:
(gdb) set env LD_LIBRARY_PATH /tmp
對相對路徑,搜尋順序是:
1) X // 直接使用原始路徑進行搜尋,成功則不再繼續,否則繼續2)
2) Bn/X // 再逐一添加solib-search-path中的每條路徑進行搜尋,成功則不再繼續,否則繼續3)
3) Bn/F(X) // 再隻使用檔案名(去掉目錄段),并逐一添加solib-search-path中的每條路徑進行搜尋,成功則不再繼續,否則繼續4)
4) $PATH/X // 再使用環境變量$PATH中的每條路徑進行搜尋,成功則不再繼續,否則繼續5)
5) $LD_LIBRARY_PATH/X // 再使用環境變量$LD_LIBRARY_PATH中的每條路徑進行搜尋,成功則不再繼續,否則繼續6)
6) 傳回失敗
======================================================================
舉例說明:
set solib-absolute-prefix /root/temp
set solib-search-path /home/evan:/home/peter
$PATH is /usr/sbin:/usr/bin
$LD_LIBRARY_PATH is /opt:/usr/games
那麼對絕對路徑"/lib/libc.so.6"的搜尋順序是:
1) A/X
/root/temp/lib/libc.so.6
2) R(A)/X
root/temp/lib/libc.so.6
3) Bn/R(A)/X
/home/evan/root/temp/lib/libc.so.6
/home/peter/root/temp/lib/lic.so.6
4) Bn/F(X)
/home/evan/libc.so.6
/home/peter/libc.so.6
5) $PATH/R(A)/X
/usr/sbin/root/temp/lib/libc.so.6
/usr/bin/roo/temp/lib/lic.so.6
6) $LD_LIBRARY_PATH/R(A)/X
/opt/root/temp/lib/libc.so.6
/usr/games/root/temp/lib/libc.so.6
對相對路徑"./libddd.so"的搜尋順序是
1) X
./libddd.so
2) Bn/X
/home/evan/./libddd.so
/home/peter/./libddd.so
3) Bn/F(X)
/home/evan/libddd.so
/home/peter/libddd.so
4) $PATH/X
/usr/sbin/./libddd.so
/usr/bin/./libddd.so
5) $LD_LIBRARY_PATH/X
/opt/./libddd.so
/usr/games/./libddd.so
從上面看到,對絕對路徑和相對路徑都有一步是采用檔案名和solib-search-path拼接來查找(絕對路徑的第4步和相對路徑的第3步),是以隻要用set solib-search-path設定了每一個庫檔案所在的直接目錄,那麼就能保證每一個庫都能被找到。
4. 檢視so庫的加載路徑是否正确可使用info sharedlibrary指令,如果已找到對應的檔案則其From和To的加載位址會有值,并且右邊路徑顯示的就是加載檔案所在的位址,這個時候,如果so庫檔案含符号資訊,則syms Read的值為Yes,否則為No,如果未找到對應的檔案則From和To的位址為空,syms Read的值為No,此時右邊路徑顯示的是Coredump檔案中庫檔案路徑。
5. 如果在Coredump檔案載入過程中,或者info sharedlibrary指令時,出現" Cannot access memory at address 0x87000069 "這樣的錯誤,這通常是由于所使用的主執行檔案("file"指令或"exec-file"指令)與Coredump檔案("core"指令或"core-file"指令)兩者不比對導緻的。這個時候應檢查主執行檔案是否是生成Coredump時所用的主執行檔案,隻要差一點,就可能導緻動态庫資訊讀取錯誤。
6. 如果載入過程中有" warning: .dynamic section for "/lib/librt.so.1" is not at the expected address (wrong library or version mismatch?) "這樣的提示,這通常是庫搜尋路徑設定錯誤,GDB載入了錯誤的庫檔案導緻的。這時,應使用info sharedlibrary指令檢視相應庫的載入路徑,并使用set sysroot或set solib-search-path修改搜尋路徑來将錯誤的庫修正到正确的路徑上。
7. 在設定了搜尋路路徑後,最好先用file指令載入主執行檔案,再用core指令載入Coredump檔案,這樣才能保證正确載入庫的符号表。否則,如果先用core指令載入Coredump檔案,再用file指令載入主執行檔案,那麼會造成庫隻是被搜尋但并不載入符号(使用info sharedlibrary指令可以看到),這時再重新執行一次core指令就可以了。
8. 一個實際的搜尋例子:
目前目錄為/home
主執行檔案在/home/evan/gdbso/mips/gdbso
Core檔案在/home/evan/gdbso/mips/Coredump
所用動态庫與拷貝到主執行檔案同一目錄下
編譯主執行檔案所用的标準庫被拷貝到主執行檔案的lib目錄下/home/evan/gdbso/mips/lib/libxxx.so
進入GDB,用file指令載入主執行檔案:
evan@ubunu:/home$ mips-linux-gnu-gdb
...
(gdb) file evan/gdbso/mips/gdbso
Reading symbols from /home/evan/gdbso/mips/gdbso...done.
(gdb) info sharedlibrary
No shared libraries loaded at this time.
可以看到隻載入了主執行檔案時,是無法得到動态庫資訊的。再用core指令載入Coredump檔案:
(gdb) core evan/gdbso/mips/Coredump
...
warning: .dynamic section for "/lib/libc.so.6" is not at the expected address (wrong library or version mismatch?)
...
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x2aad98c0 0x2aadd6d8 Yes /lib/librt.so.1
0x2aaf3460 0x2ab0db98 Yes /lib/libm.so.6
0x2ab7e2e0 0x2ab89b28 Yes /lib/libpthread.so.0
0x2abba9a0 0x2acb2bd8 Yes /lib/libc.so.6
0x2ad06a40 0x2ad07988 Yes /lib/libdl.so.2
No /lib/ld.so.1
No ./libddd.so
(gdb)
在同時有了主執行檔案和Coredump檔案後,用info sharedlibrary就可以看到動态庫資訊了。但在載入過程中有庫版本不比對的提示。通過info sharedlibrary也看到GDB錯誤地載入了系統中自帶的标準庫。我們将絕對路徑設定到一個不存在的目錄來看看Coredump中儲存的原始路徑名:
(gdb) set sysroot /noexist
...
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
No /lib/librt.so.1
No /lib/libm.so.6
No /lib/libpthread.so.0
No /lib/libc.so.6
No /lib/libdl.so.2
No /lib/ld.so.1
No ./libddd.so
(gdb)
(gdb) set sysroot evan/gdbso/mips
...
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x2aad98c0 0x2aade270 Yes evan/gdbso/mips/lib/librt.so.1
0x2aaf3110 0x2ab31b70 Yes evan/gdbso/mips/lib/libm.so.6
0x2ab7e320 0x2ab8e620 Yes evan/gdbso/mips/lib/libpthread.so.0
0x2abba6a0 0x2accc3f0 Yes evan/gdbso/mips/lib/libc.so.6
0x2ad06b50 0x2ad07c70 Yes evan/gdbso/mips/lib/libdl.so.2
0x2aaa8810 0x2aac2e40 Yes evan/gdbso/mips/lib/ld.so.1
No ./libddd.so
(gdb)
(gdb) set solib-search-path /noexist:/home/evan/gdbso/mips
...
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x2aad98c0 0x2aade270 Yes evan/gdbso/mips/lib/librt.so.1
0x2aaf3110 0x2ab31b70 Yes evan/gdbso/mips/lib/libm.so.6
0x2ab7e320 0x2ab8e620 Yes evan/gdbso/mips/lib/libpthread.so.0
0x2abba6a0 0x2accc3f0 Yes evan/gdbso/mips/lib/libc.so.6
0x2ad06b50 0x2ad07c70 Yes evan/gdbso/mips/lib/libdl.so.2
0x2aaa8810 0x2aac2e40 Yes evan/gdbso/mips/lib/ld.so.1
0x2ad1a590 0x2ad1a770 Yes /home/evan/gdbso/mips/libddd.so
(gdb)