平常初次定位問題時,我一般是先看看 api 調用,再不濟就多看看堆棧,如用 gdb 的commands 指令在 每次斷點時自動打印堆棧。
strace 有個實驗性的功能,在打印每個系統調用的同時打印當時的堆棧,有了堆棧簡直就是手握問題的鑰匙。
strace -h
...
-k obtain stack trace between each syscall
...
but,but,but,but,but,but,but,but,but,but,but,but,
公司中開發環境的centos linux 上自帶的 strace 沒有編譯對 -k 功能 的支持。只能自己從源代碼中編譯。
[strace-4.24]# ./configure --help
...
--with-libdw use libdw to implement stack tracing support
--with-libunwind use libunwind to implement stack tracing support
--with-libiberty use libiberty to demangle symbols in stack trace
...
首次編譯時,只加了 --with-libunwind ,--with-libunwind 與 --with-libdw 功能是同樣的,選其中一個就可以了,只是我對 libunwind 多點偏好而已。
CFLAGS="-O2 -fPIC" \
./configure \
--prefix=/usr \
--mandir=/usr/man \
--with-libunwind
看看編譯後新的 strace -k 去trace mysqld 的打印:
# strace -f -y -k -p 18297
...
[pid 10719] getrusage(RUSAGE_SELF, {ru_utime={tv_sec=102, tv_usec=148630}, ru_stime={tv_sec=39, tv_usec=239462}, ...}) = 0
> /usr/lib64/libc-2.17.so(getrusage+0x7) [0xf5057]
> /usr/libexec/mysqld(_ZN16PROF_MEASUREMENTC1EP13QUERY_PROFILEPKc+0x15) [0x42e065]
> /usr/libexec/mysqld(_ZN13QUERY_PROFILE10new_statusEPKcS1_S1_j+0x46) [0x42e2c6]
> /usr/libexec/mysqld(_ZN9PROFILING20finish_current_queryEv+0x28) [0x42e598]
> /usr/libexec/mysqld(_Z16dispatch_command19enum_server_commandP3THDPcj+0x4cc) [0x37a21c]
> /usr/libexec/mysqld(_Z24do_handle_one_connectionP3THD+0x1c2) [0x42da22]
> /usr/libexec/mysqld(handle_one_connection+0x4a) [0x42daca]
> /usr/lib64/libpthread-2.17.so(start_thread+0xc5) [0x7e25]
> /usr/lib64/libc-2.17.so(clone+0x6d) [0xfebad]
...
不錯了,可以啓用 -k 功能打印出堆棧,但對於 c++ 程序中的堆棧中的名字沒有做到 demangle ,像 _ZN16PROF_MEASUREMENTC1EP13QUERY_PROFILEPKc 這樣的名字,可以用下面命令看到 demangle 後的真正函數簽名
# c++filt _ZN16PROF_MEASUREMENTC1EP13QUERY_PROFILEPKc
PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE*, char const*)
回來,再次 編譯 strace ,這次 加上 --with-libiberty
CFLAGS="-O2 -fPIC" \
./configure \
--prefix=/usr \
--mandir=/usr/man \
--with-libunwind \
--with-libiberty
.
.
.
checking whether to enable stack tracing support... yes, using libunwind
checking demangle.h usability... yes
checking demangle.h presence... yes
checking for demangle.h... yes
checking for cplus_demangle in -liberty... yes
checking libiberty/demangle.h usability... no
checking libiberty/demangle.h presence... no
checking for libiberty/demangle.h... no
configure: error: in `/tmp/strace-4.24':
configure: error: failed to find demangle.h
See `config.log' for more details
# echo $?
1
but, but, but, but, but, but, but, but, but, but, but,
源碼中的編譯配置不正確,
怎麼回事,failed to find demangle.h ???
再看上一句,真正找不到的是 checking libiberty/demangle.h presence... no
看了一下我係統中的頭文件
不對呀,這不是有 #include "libiberty.h" ,也有 cplus_demangle 等相關的 C++ demangle 函數。
再看一下源碼中的 編譯配置
好傢伙,它同時 檢查 demangle.h libiberty/demangle.h 這兩個頭文件存不存在,但上面 /usr/include/demangle.h 已經 include libiberty 相關的東西,由此看來這個 libiberty/demangle.h 是多餘的,把它刪除就可以了,而且我的centos 上安裝的 binutils 包中沒有
這麼看來 很舊以前 binutls 包可能有 libiberty/demangle.h 這個文件,但現在的新版本沒有了。
也可能由於 很多的 linux 發行版中的 strace 都不編譯支持 -k 功能,所以這個管理員只就沒有測試到 編譯-k 功能的編譯配置。
看看帶 demangle 特性的 -k 功能輸出:
# strace -f -y -k -p 18297
...
[pid 3792] getrusage(RUSAGE_SELF, {ru_utime={tv_sec=170, tv_usec=48683}, ru_stime={tv_sec=61, tv_usec=704638}, ...}) = 0
> /usr/lib64/libc-2.17.so(getrusage+0x7) [0xf5057]
> /usr/libexec/mysqld(PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE*, char const*, char const*, char const*, unsigned int)+0x28) [0x42e0a8]
> /usr/libexec/mysqld(QUERY_PROFILE::new_status(char const*, char const*, char const*, unsigned int)+0x148) [0x42e3c8]
> /usr/libexec/mysqld(set_thd_proc_info+0x2e) [0x341ece]
> /usr/libexec/mysqld(dispatch_command(enum_server_command, THD*, char*, unsigned int)+0x2c6) [0x37a016]
> /usr/libexec/mysqld(do_handle_one_connection(THD*)+0x1c2) [0x42da22]
> /usr/libexec/mysqld(handle_one_connection+0x4a) [0x42daca]
> /usr/lib64/libpthread-2.17.so(start_thread+0xc5) [0x7e25]
> /usr/lib64/libc-2.17.so(clone+0x6d) [0xfebad]
...
> /usr/libexec/mysqld(PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE*, char const*, char const*, char const*, unsigned int)+0x28) 這樣的打印,好看極了