NDK打印调用堆栈
虽然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的调用堆栈了