1. 程式人生 > 其它 >GDB動態庫搜尋路徑

GDB動態庫搜尋路徑

筆記:

當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) 返回失敗

  對相對路徑,搜尋順序是:

  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)
Coredump中儲存的原始路徑名為/lib/librt.so.1,為了讓GDB使用正確的庫/home/evan/gdbso/mips/lib/librt.so.1,只需要將絕對路徑字首設定為/home/evan/gdbso/mips即可,這裡設定為evan/gdbso/mips來演示效果:

(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已經正確地載入了絕對路徑。但相對路徑"./libddd.so"還沒有找到,為了使用/home/evan/gdbso/mips/libddd.so,設定庫搜尋路徑包含/home/evan/gdbso/mips即可。為了檢視效果,這裡還添加了一個不存在的搜尋路徑:
(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)
可以看到,所有的庫都找到正確的路徑了,Syms也被正確地載入。