平常初次定位问题时,我一般是先看看 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) 这样的打印,好看极了