前言
本文以libunwind库对栈回溯流程进行描述。
libunwind栈回溯流程
libunwind包含两套使用接口,分别以前缀unw_和_Unwind标识,其中_Unwind前缀的接口是供C++异常处理的高级函数接口,unw前缀的则是更为底层通用的接口。根据libunwind代码中的configure.ac文件,在arm架构下是不使能C++的异常处理的,所以栈回溯使用的接口均为前缀位unw的函数接口。
AC_MSG_CHECKING([whether to enable C++ exception support])
AC_ARG_ENABLE(cxx_exceptions,
AS_HELP_STRING([--enable-cxx-exceptions],[use libunwind to handle C++ exceptions]),,
[
# C++ exception handling doesn't work too well on x86
case $target_arch in
x86*) enable_cxx_exceptions=no;;
aarch64*) enable_cxx_exceptions=no;;
arm*) enable_cxx_exceptions=no;;
mips*) enable_cxx_exceptions=no;;
tile*) enable_cxx_exceptions=no;;
*) enable_cxx_exceptions=yes;;
esac
])
栈回溯以函数unw_backtrace为起点:
int
unw_backtrace (void **buffer, int size)
{
unw_cursor_t cursor;
unw_context_t uc;
int n = size;
tdep_getcontext_trace (&uc); //保存当前寄存器的值
if (unlikely (unw_init_local (&cursor, &uc) < 0)) //初始化cursor,保存当前寄存器的值
return 0;
if (unlikely (tdep_trace (&cursor, buffer, &n) < 0)) //快速查找,在cache中查找,如果在cache中没有找到,则需要根据elf文件逐个回溯
{
unw_getcontext (&uc);
return slow_backtrace (buffer, size, &uc); //逐个函数进行回溯
}
return n;
}
libunwind_i.h
#define tdep_getcontext_trace unw_getcontext
libunwind-common.h.in
#define unw_getcontext(uc) unw_tdep_getcontext(uc)
libunwind-arm.h
#ifndef __thumb__
#define unw_tdep_getcontext(uc) (({
\
unw_tdep_context_t *unw_ctx = (uc); \
register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \
__asm__ __volatile__ ( \
"stmia %[base], {r0-r15}" \
: : [base] "r" (unw_base) : "memory"); \
}), 0)
#else /* __thumb__ */
#define unw_tdep_getcontext(uc) (({
\
unw_tdep_context_t *unw_ctx = (uc); \
register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \
__asm__ __volatile__ ( \
".align 2\nbx pc\nnop\n.code 32\n" \
"stmia %[base], {r0-r15}\n" \
"orr %[base], pc, #1\nbx %[base]\n" \
".code 16\n" \
: [base] "+r" (unw_base) : : "memory", "cc"); \
}), 0)
#endif
//将R0-R15的值依次保存到uc->reg[0] - uc->reg[15]中
int unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
return unw_init_local_common(cursor, uc, 1