1. 程式人生 > >使用strace命令解決linux服務器依賴庫問題

使用strace命令解決linux服務器依賴庫問題

utf 問題 示例 破壞 idc oam message 讓我 usr

使用strace命令解決linux服務器依賴庫問題

簡單說明:
strace的另一個用處是解決和動態庫相關的問題。當對一個可執行文件運行ldd時,它會告訴你程序使用的動態庫和找到動態庫的位置。但是如果你正在使用一個比較老 的glibc版本(2.2或更早),你可能會有一個有bug的ldd程序,它可能會報告在一個目錄下發現一個動態庫,但是真正運行程序時動態連接程序 (/lib/ld-linux.so.2)卻可能到另外一個目錄去找動態連接庫。這通常因為/etc/ld.so.conf和 /etc/ld.so.cache文件不一致,或者/etc/ld.so.cache被破壞。在glibc 2.3.2版本上這個錯誤不會出現,可能ld-linux的這個bug已經被解決了。

盡管這樣,ldd並不能把所有程序依賴的動態庫列出 來,系統調用dlopen可以在需要的時候自動調入需要的動態庫,而這些庫可能不會被ldd列出來。作為glibc的一部分的NSS(Name Server Switch)庫就是一個典型的例子,NSS的一個作用就是告訴應用程序到哪裏去尋找系統帳號數據庫。應用程序不會直接連接到NSS庫,glibc則會通 過dlopen自動調入NSS庫。如果這樣的庫偶然丟失,你不會被告知存在庫依賴問題,但這樣的程序就無法通過用戶名解析得到用戶ID了。
讓我們看一個例子:
whoami程序會給出你自己的用戶名,這個程序在一些需要知道運行程序的真正用戶的腳本程序裏面非常有用,whoami的一個示例 輸出如下:

[root@mgr04 opt]# whoami
root

whoami程序會給出你自己的用戶名,這個程序在一些需要知道運行程序的真正用戶的腳本程序裏面非常有用,whoami的一個示例 輸出如下:

特別提示:演示系統環境如下

[root@mgr04 opt]# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 

在centos系統命令行運行 ldd /usr/bin/whoami只能查看到whoami才依賴了2個庫文件,然而實際上whoami 命令依賴系統的庫文件遠不止這些。

[root@mgr04 opt]# ldd /usr/bin/whoami
    linux-vdso.so.1 =>  (0x00007ffd1c111000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe374d4d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe375116000)

咱們可以通過 strace -e trace=open whoami 命令來查看實際中whoami 所調用的庫文件如下:

查看命令行執行whoami命令是都打開了系統哪些依賴庫文件:
[root@mgr04 opt]# strace -e trace=open whoami
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
root
+++ exited with 0 +++

故障模擬演示:
假設因為某種原因在升 級glibc的過程中負責用戶名和用戶ID轉換的庫NSS丟失,我們可以通過把nss庫改名來模擬這個環境

[root@mgr04 opt]# mv /lib64/libnss_files.so.2 /lib64/libnss_files.so.2.bak
[root@mgr04 opt]# 
[root@mgr04 opt]# whoami
whoami: cannot find name for user ID 0
[root@mgr04 opt]# 

這裏你可以看到,運行whoami時出現了錯誤,此時在命令行執行ldd程序的輸出不會提供有用的幫助:

[root@mgr04 opt]# ldd /usr/bin/whoami
    linux-vdso.so.1 =>  (0x00007ffd62bd4000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fdcf861f000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fdcf89e8000)
[root@mgr04 opt]# 

你只會看到whoami依賴Libc.so.6和ld-linux-x86-64.so.2,它沒有給出運行whoami所必須的其他庫。這裏時用strace跟蹤 whoami時的輸出:

[root@mgr04 opt]# strace -o whoami-strace.txt whoami
whoami: cannot find name for user ID 0
[root@mgr04 opt]# cat whoami-strace.txt 
.....................
.....................
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1717, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f306e2ae000
read(3, "#\n# /etc/nsswitch.conf\n#\n# An ex"..., 4096) = 1717
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f306e2ae000, 4096)            = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=28446, ...}) = 0
mmap(NULL, 28446, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f306e2a8000
close(3)                                = 0
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/tls/x86_64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib64/tls/x86_64", 0x7fff92c1f600) = -1 ENOENT (No such file or directory)
open("/lib64/tls/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib64/tls", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
open("/lib64/x86_64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib64/x86_64", 0x7fff92c1f600)   = -1 ENOENT (No such file or directory)
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib64", {st_mode=S_IFDIR|0555, st_size=32768, ...}) = 0
open("/usr/lib64/tls/x86_64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/tls/x86_64", 0x7fff92c1f600) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/tls", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
open("/usr/lib64/x86_64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/x86_64", 0x7fff92c1f600) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib64", {st_mode=S_IFDIR|0555, st_size=32768, ...}) = 0
munmap(0x7f306e2a8000, 28446)           = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=28446, ...}) = 0
mmap(NULL, 28446, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f306e2a8000
close(3)                                = 0
open("/lib64/tls/libnss_sss.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/libnss_sss.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libnss_sss.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libnss_sss.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
munmap(0x7f306e2a8000, 28446)           = 0
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2502, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f306e2ae000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2502
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f306e2ae000, 4096)            = 0
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "whoami: cannot find name for use"..., 39) = 39
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++
[root@mgr04 opt]# 

你可以發現在不同目錄下面查找libnss.so.2的嘗試,但是都失敗了。如果沒有strace這樣的工具,很難發現這個錯誤是由於缺少動態庫造成的。現 在只需要找到libnss.so.2並把它放回到正確的位置就可以了。 

如果你已經知道你要找什麽,你可以讓strace只跟蹤一些類型的系統調用。例如,你需要看看在configure腳本裏面執行的程序,你需要監視的系統調 用就是execve。讓strace只記錄execve的調用用這個命令:

strace -f -o configure-strace.txt -e execve ./configure

原文地址:
https://www.linuxidc.com/Linux/2012-12/75671p3.htm

使用strace命令解決linux服務器依賴庫問題