java打印堆棧
方法一:異常對象打印堆棧
Exception e = new Exception("this is a log");
e.printStackTrace();
方法二:Log打印獲取異常的堆棧并打印
Log.e(“dump_test”,Log.getStackTraceString(new Throwable()));
C++\C打印堆棧
方法一:linux函數
函數介紹
頭文件:java
#include
函數方法:linux
// 獲取當前的調用棧信息,結果存儲在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);
編譯選項android
-rdynamic
-g
gcc編譯時加上-rdynamic和-g編譯選項,就能夠看到被調用的函數和地址,以下web
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中如下面方式添加編譯選項svg
LOCAL_CFLAGS += -rdynamic -g
linux下使用編譯選項
非Android編譯,使用以下命令函數
gcc test.cc -rdynamic -g -o test3
示例:工具
#include
#include
#include
#include
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
#include
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");
//能夠設置第二、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中this
<1>.建立callstack.cpp
#include
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
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部分未通過實際完整測試,其中命令都零散的使用過,若參照使用,請根據實際狀況調整,總體思路應該沒錯。實測部分,后面盡可能補上