天天看點

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

部落客注:在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)