android 调试堆栈整理
1. C++代码中打印堆栈
C++也是支持异常处理的,异常处理库中,已经包含了获取backtrace的接口,Android也是利用这个接口来打印堆栈信息的。在Android的C++中,已经集成了一个工具类CallStack,在libutils.so中。使用方法:
[cpp] view plain copy- #include
- ...
- CallStack stack;
- stack.update();
- stack.dump();
使用方式比较简单。目前Andoid4.2版本已经将相关信息解析的很到位,符号表查找,demangle,偏移位置校正都做好了。
PS:此方法不适用NDK,或者是作者本人未找到在NDK下面使用CallStack的方法。
后续可下载所有的android源码,然后再NDK的工程中添加依赖
2. C代码中打印堆栈
C代码,尤其是底层C库,想要看到调用的堆栈信息,还是比较麻烦的。 CallStack肯定是不能用,一是因为其实C++写的,需要重新封装才能在C中使用,二是底层库反调上层库的函数,会造成链接器循环依赖而无法链接。不过也不是没有办法,可以通过android工具类CallStack实现中使用的unwind调用及符号解析函数来处理。
这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用,这样会比较简单。如下为相关的实现代码,只需要在要打印的文件中插入此部分代码,然后调用getCallStack()即可,无需包含太多的头文件和修改Android.mk文件:
[cpp] view plain copy- #define MAX_DEPTH 31
- #define MAX_BACKTRACE_LINE_LENGTH 800
- #define PATH "/system/lib/libcorkscrew.so"
- typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t);
- typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*);
- typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);
- static void *gHandle = NULL;
- static int getCallStack(void){
- ssize_t i = 0;
- ssize_t result = 0;
- ssize_t count;
- backtrace_frame_t mStack[MAX_DEPTH];
- backtrace_symbol_t symbols[MAX_DEPTH];
- unwindFn unwind_backtrace = NULL;
- unwindSymbFn get_backtrace_symbols = NULL;
- unwindSymbFreeFn free_backtrace_symbols = NULL;
- // open the so.
- if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW);
- // get the interface for unwind and symbol analyse
- if(gHandle != NULL) unwind_backtrace = (unwindFn)dlsym(gHandle, "unwind_backtrace");
- if(gHandle != NULL) get_backtrace_symbols = (unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols");
- if(gHandle != NULL) free_backtrace_symbols = (unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols");
- if(!gHandle ||!unwind_backtrace ||!get_backtrace_symbols || !free_backtrace_symbols ){
- ALOGE("Error! cannot get unwind info: handle:%p %p %p %p",
- gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols );
- return result;
- }
- count= unwind_backtrace(mStack, 1, MAX_DEPTH);
- get_backtrace_symbols(mStack, count, symbols);
- for (i = 0; i < count; i++) {
- char line[MAX_BACKTRACE_LINE_LENGTH];
- const char* mapName = symbols[i].map_name ? symbols[i].map_name : "
" ; - const char* symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name;
- size_t fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2;
- if (symbolName) {
- uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr;
- if (pc_offset) {
- snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s+%u)",
- i, symbols[i].relative_pc, fieldWidth, mapName,
- fieldWidth, symbolName, pc_offset);
- } else {
- snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s)",
- i, symbols[i].relative_pc, fieldWidth, mapName,
- fieldWidth, symbolName);
- }
- } else {
- snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s",
- i, symbols[i].relative_pc, fieldWidth, mapName);
- }
- ALOGD("%s", line);
- }
- free_backtrace_symbols(symbols, count);
- return result;
- }
对sched_policy.c的堆栈调用分析如下,注意具体是否要打印,在哪里打印,还可以通过pid、uid、property等来控制一下,这样就不会被淹死在trace的汪洋大海中。
PS:该方法可用,但是不是线程安全的(async-signal-safe);无法再signal的处理函数中使用。
3.glibc头文件"execinfo.h"中的backtrace、backtrace_symbols 接口。不适用于android,因为android适用的是bionic,而非glibc。
4. C函数打印调用栈
可以参考CallStack.cpp的实现,通过调用_Unwind_Backtrace完成。
PS:实现难度较大。
更多相关文章
- Android(安卓)电话的反射调用机制实现静默接听电话
- 2011.09.21——— android 动态壁纸开发
- Android事件处理分析+Android事件处理 +Android输入事件流程
- android 有关怎么自己添加系统级服务 java层 重点aidl
- android客户端程序访问服务器端webservice,几篇不错的文章!
- android:configChanges属性总结
- Phone拨号调起InCallUi流程(Phone 9.0 )(Phone调用InCallUi流程)
- Android--使用include调用布局
- android跨进程通信(IPC):使用AIDL