虽然android源码里有android::CallStack用来打印堆栈,但是NDK里面并没有包含它,所以不能直接调用它,所以要尝试用动态调用的方式来实现。
我测试的手机是安卓8.1.0版本,android::CallStack位于/system/lib/libutils.so库中,使用ida pro打开libutils.so,找到
android::CallStack::CallStack函数
.text:0000996C ; _DWORD __fastcall android::CallStack::CallStack(android::CallStack *__hidden this, const char *, int)
.text:0000996C EXPORT _ZN7android9CallStackC2EPKci
.text:0000996C _ZN7android9CallStackC2EPKci ; DATA XREF: LOAD:0000158C↑o
.text:0000996C ; LOAD:00001CDC↑o可以看到函数的导出符号为
_ZN7android9CallStackC2EPKci,因为它是类的构造方法,在反编译代码中第一次参数是一个隐藏的this指针,这个指针用来指向对象本身,动态调用我们需要自己malloc这个指针。
void* handle = dlopen(NULL, RTLD_NOW);
//查找函数导出符号
void* (*android_CallStack_CallStack)(void*, const char *, int) = (void *(*)(void *, const char *, int))dlsym(handle_121, "_ZN7android9CallStackC2EPKci");
//malloc出android::CallStack指针,这里也可以写死数字,8.1.0中android::CallStack大小为20
void* stack = malloc(sizeof(android::CallStack));
//将堆栈信息打印到logcat中,Log Tag为jyy
android_CallStack_CallStack(stack, "jyy", 1);如果担心这种方式会造成内存泄漏,也可以在打印完堆栈后主动调用android::CallStack的析构函数,并在最后free掉this指针
.text:00009B20 ; void __fastcall android::CallStack::~CallStack(android::CallStack *__hidden this)
.text:00009B20 EXPORT _ZN7android9CallStackD2Ev
.text:00009B20 _ZN7android9CallStackD2Ev ; CODE XREF: android::ProcessCallStack::update(void)+E0↓pvoid (*free_CallStack)(void*) = (void (*)(void*))dlsym(handle_121, "_ZN7android9CallStackD2Ev");
//主动调用析构函数
free_CallStack(stack);
//free this指针
free(stack);这样就可以主动打印NDK的调用堆栈了
