在网上搜索的Android打印调用栈,实现方式有以下三种:

  1. 使用CallStack
  2. 使用_Unwind_Backtrace函数
  3. 自己编译 libunwind

第一种方法,在我的环境中(Android 5.1),可以在 libutils.so 找到相应的函数,可是并不能在 NDK中找到 utils/CallStack.h 这个头文件,所以得自己使用 dlsym 取得函数地址再调用,但是CallStack是一个 c++ 类,要调用比较麻烦,所以放弃这种方法。

第二种方法,这个就比较好了,能找到头文件,也能够成功编译,但是编译器将 libgcc.a 中的 _Unwind_Backtrace 函数跟我的动态库链接,这个实现似乎跟 Android 水土不服,获取的调用栈数量极少。

第三种,一看就很麻烦,放弃了。

本来呢,在第二种方法中,我希望的是使用 libunwind 的_Unwind_Backtrace 函数,然而看 libunwind 时发现,它并没有导出这个函数。不过意外的发现了 unw_backtrace 函数,从源码也能看出它具有跟 _Unwind_Backtrace 相同的功能,使用它的效果也是极好的,下面源码奉上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
typedef int (*Unw_BackTrace_Func)(void**, int);
void print_backtrace() {
static Unw_BackTrace_Func unw_backtrace = NULL;
if (!unw_backtrace) {
void *hanle = dlopen("libunwind.so", RTLD_NOW);
unw_backtrace = (Unw_BackTrace_Func)dlsym(hanle, "unw_backtrace");
}

void *buffer[32] = { 0 };
int n = unw_backtrace((void**)&buffer, 32);
for(int i = 1; i < n; i++) {
const char *file = "\t\t\t\t";
const char *symbol = "\t\t\t\t";
Dl_info info;
if (dladdr(buffer[i], &info)) {
if (info.dli_sname) {
symbol = info.dli_sname;
}
if (info.dli_fname) {
file = info.dli_fname;
}
}

LOGI("#%02d: %p \t %s \t %s", i, buffer[i], symbol, file);
}
}

一些参考:

Android 平台 Native 代码的崩溃捕获机制及实现

JNI中如何打印Call Stack

Android下打印调试堆栈方法