Android打印堆栈
java打印堆栈
方法一:异常对象打印堆栈
Exception e = new Exception("this is a log");
e.printStackTrace();
方法二:Log打印获取异常的堆栈并打印
Log.e(“dump_test”,Log.getStackTraceString(new Throwable()));
C++\C打印堆栈
方法一:linux函数
函数介绍
头文件:
#include <execinfo .h>
函数方法:
// 获取当前的调用栈信息,结果存储在buffer中,返回值为栈的深度,参数size限制栈的最大深度,即最大取size步的栈信息。
int backtrace(void **buffer, int size);
// 把backtrace获取的栈信息转化为字符串,以字符指针数组的形式返回,参数size限定转换的深度,一般用backtrace调用的返回值。
char **backtrace_symbols(void *const *buffer, int size);
// 它的功能和backtrace_symbols差不多,只不过它不把转换结果返回给调用方,而是写入fd指定的文件描述符。
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
编译选项
-rdynamic
-g
gcc编译时加上-rdynamic和-g编译选项,就可以看到被调用的函数和地址,如下
stackstrace begin:
./test3(_Z16print_stacktracev+0x26) [0x4008e5]
./test3(_Z4fun1v+0x13) [0x4008a7]
./test3(_Z4fun2v+0x9) [0x4008b2]
./test3(_Z4fun3v+0x9) [0x4008bd]
./test3(main+0x9) [0x40088d]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff) [0x7fa9558c1eff]
./test3() [0x4007c9]
堆栈转换
若有一个函数有多个地方被调用,可以使用addr2line,把调用地址转换为行数
// addr2line -aCfe lib addr
$ addr2line -aCfe 0x4008a7 test3
0x00000000004008a7
fun1()
/home/wuzesheng/work/test/test.cc:20
Android使用编译选项
在Android中,编译脚本是Android源码中已经写好的,可以在Android.mk中以下面方式添加编译选项
LOCAL_CFLAGS += -rdynamic -g
linux下使用编译选项
非Android编译,使用如下命令
gcc test.cc -rdynamic -g -o test3
示例:
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
myfunc3(void)
{
int j, nptrs;
#define SIZE 100
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
/* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
would produce similar output to the following: */
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
static void /* "static" means don't export the symbol... */
myfunc2(void)
{
myfunc3();
}
void
myfunc(int ncalls)
{
if (ncalls > 1)
myfunc(ncalls - 1);
else
myfunc2();
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "%s num-calls\n", argv[0]);
exit(EXIT_FAILURE);
}
myfunc(atoi(argv[1]));
exit(EXIT_SUCCESS);
}
方法二:使用Android工具方法
示例:
C++中
<1>.test.cpp
#include <utils/Log.h>
#include <utils/CallStack.h>
void dumping_callstack(){
android::CallStack stack;
//getpid()和gettid()效果一样
//stack.update(2,getpid());
//stack.update(2,gettid());
stack.update();
//输出到printf
stack.dump(1);
//输出到logcat
stack.log("dump_test");
//可以设置第2、3个参数
//stack.log("Dumping Stack",ANDROID_LOG_ERROR ,"123 ");
}
void func1(){
dumping_callstack();
}
void func2(){
func1();
}
void func3(){
func2();
}
int main(){
ALOGE("main_test------------------>");
func3();
}
<2>.Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := test.cpp
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := test
LOCAL_SHARED_LIBRARIES += libcutils libutils
include $(BUILD_EXECUTABLE)
C中
<1>.创建callstack.cpp
#include <utils/CallStack.h>
extern "C" void dumping_callstack();
void dumping_callstack(){
android::CallStack stack;
stack.update();
stack.log(“dump_test“);
}
<2>.创建callstack.h
void dumping_callstack();
<3>.测试test.c
#include "callstack.h"
static ssize_t out_write(){
dumping_callstack();
}
<4>.Anroid.mk中添加到编译选项:callstack.cpp及库
LOCAL_SHARED_LIBRARIES := libcutils libutils
LOCAL_SRC_FILES := callstack.cpp
kernel打印堆栈
#include <asm/ptrace.h>
printk(KERN_ERR "dump_stack start: %s() %d \n",__FUNCTION__,__LINE__);
dump_stack();
.......
printk(KERN_ERR "dump_stack stop: %s() %d \n",__FUNCTION__,__LINE__);
根据dump stack的log位置加printk()。
注意
java经过实践测试。
C++\C部分未经过实际完整测试,其中命令都零散的使用过,若参照使用,请根据实际情况调整,整体思路应该没错。实测部分,后面尽量补上