行业知识
Android framework C/C++中打印堆栈
2026-11-06 19:41:09
来源:互联网转载
有时候我们需要有这样的需求,需要在某些函数中打印函数的调用路径,经过查询主要有四种方式实现。
1. CallStack堆栈回溯
Android中提供了堆栈打印的类CallStack.cpp,此类在的路径为/system/core/libutils/CallStack.cpp,在不同的Android版本中,此类所在的so库不同,具体如下表所示。
| Android版本 | 所在so库 | 依赖方法 |
|---|---|---|
| Andorid O以上 | libutilscallstack | Android.mk: LOCAL_SHARED_LIBRARIES里包含libutilscallstack;Android.bp: shared_libs里包含libutilscallstack |
| Android O | libutils | Android.mk: LOCAL_SHARED_LIBRARIES里包含libutils; Android.bp: shared_libs里包含libutils |
| Android N 以前版本 | libutils | Android.mk: LOCAL_SHARED_LIBRARIES里包含libutils |
具体的使用步骤:
(1)包含头文件
#include "utils/CallStack.h"
(2)引用动态库
根据所在的so库进行依赖使用,如上表所示。
(3)打印堆栈
android::CallStack cs("tagName") 注意:此种打印堆栈的方法,并不通用。比如自己编写的普通APP中无法找到CallStack头文件,还有在系统源代码中有些地方无法依赖libutilscallstack.so 、libutils.so库。
2. backtrace堆栈回溯
此方法是参照CallStack.cpp堆栈打印的实现,查看CallStack.cpp的源代码可以发现,实现打印堆栈的方法是在backtrace/Backtrace.h头文件中,对应的实现文件是在/system/core/libbacktrace目录下,通过查看Android.dp文件可知,最终/system/core/libbacktrace目录下的文件会编译成libbacktrace.so文件。由此可知想要打印堆栈信息,可以借助libbacktrace.so文件。
具体的使用步骤:
(1)包含头文件
#include
(2)引用动态库
Android.mk: LOCAL_SHARED_LIBRARIES里包含libbacktraceAndroid.bp: shared_libs里包含libbacktrace
(3)打印堆栈
Vector mFrameLines;std::unique_ptr backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, -1));if (!backtrace->Unwind(0)) {ALOGW("%s: Failed to unwind callstack.", __FUNCTION__);}for (size_t i = 0; i NumFrames(); i++) {mFrameLines.push_back(backtrace->FormatFrameData(i).c_str());} 3. _Unwind_Backtrace堆栈回溯
具体的使用见下面的代码
#include #include #include #include #include #include namespace { struct BacktraceState { void** current; void** end; }; static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = static_cast(arg); uintptr_t pc = _Unwind_GetIP(context); if (pc) { if (state->current == state->end) { return _URC_END_OF_STACK; } else { *state->current++ = reinterpret_cast(pc); } } return _URC_NO_REASON; }}size_t captureBacktrace(void** buffer, size_t max){ BacktraceState state = {buffer, buffer + max}; _Unwind_Backtrace(unwindCallback, &state); //调用_Unwind_Backtrace方法,回调unwindCallback return state.current - buffer;}void dumpBacktrace(std::ostream& os, void** buffer, size_t count){ for (size_t idx = 0; idx 调用堆栈中,在函数内部实际执行的位置(地址) if(info.dli_sname) { symbol = info.dli_sname; //一个指针,指向与指定的address最接近的符号的名称。该符号要么带有相同的地址,要么是带有低位地址的最接近符号。函数名称 fname = info.dli_fname; //一个指针,指向包含address的加载模块的文件名。so文件地址 baseAddr = info.dli_fbase; //,载模块的句柄。该句柄可用作dlsym() 的第一个参数。so在内存中的地址 sAddr = info.dli_saddr; //最接近符号的实际地址。对于代码符号,它包含最接近代码符号的OPD(正式Plabel 描述符)的地址。在内存中函数的相对地址 }else { fname = info.dli_fname; baseAddr = info.dli_fbase; sAddr = info.dli_saddr; } //os os const size_t max = 100; // 调用的层数 void* buffer[max]; std::ostringstream oss; dumpBacktrace(oss, buffer, captureBacktrace(buffer, max)); __android_log_print(ANDROID_LOG_INFO, "backtrace", "%s", oss.str().c_str()); return oss.str().c_str();} lr = *(uint64_t *) (fp + sizeof(char *)); Dl_info info; if (!dladdr((void *) lr, &info)) { break; } if (!info.dli_fname) { break; } LOG("backtrace pc = %p,module = %s", lr, info.dli_fname); fp = *((uint64_t *) fp);}
上一篇:怎么连接对方MYSQL服务器?
下一篇:怎么设置软件代理服务器?