android线程backtrace,c++ - Android NDK: getting the backtrace - Stack Overflow

Here is some working and complete code that implements dump_stack() by starting with Eugene Shapovalov's answer and does symbol lookups and C++ name demangling right on the device. This solution:

works with the NDK r10e (you don't need the complete Android AOSP source tree)

does NOT require any extra third-party libraries (no libunwind, libbacktrace, corkscrew, CallStack)

does NOT depend on any shared libraries being installed on the device (e.g. corkscrew, which got axed in Android 5)

does NOT force you to map addresses to symbols on your development machine; all symbol names are revealed on the Android device in your code

It uses these facilities, which are built into the NDK:

header that is in the NDK toolchain/ dirs (NOT libunwind)

dladdr()

__cxxabiv1::__cxa_demangle() from (see STLport note below)

So far, I tested this only with an arm-based Android 5.1 device and I called it only from my main program (not from a signal handler). I was using the default ndk-build which chooses gcc for the arm platform.

Please comment if you are able to make this work

on other Android OSes

from a SIGSEGV handler on crash (my goal was simply to print a stack trace on assertion failure)

using clang toolsets instead of gcc

Note the r10e NDK has code for many architectures in both gcc and clang toolsets so the support looks broad.

The C++ symbol name demangling support depends on an __cxxabiv1::__cxa_demangle() function that comes from the C++ STL that is included with the NDK. This should work as-is if you are doing your Android build with the GNU STL (APP_STL := gnustl_static or gnustl_shared in Application.mk; see this page for more info). If you are currrently using no STL at all, simply add APP_STL := gnustl_static or gnustl_shared to Application.mk. If you are using STLport, you have to enjoy a special kind of fun (more below).

IMPORTANT: for this code to work, you must not use the -fvisibility=hidden gcc compiler option (at least in your debug builds). That option is commonly used to hide symbols from prying eyes in release builds.

Many people have noted that the ndk-build script strips symbols from your NDK .so whilst copying it to the libs/ directory of your project. That is true (using nm on the two copies of the .so gives very different results) HOWEVER this particular layer of stripping amazingly does not prevent the code below from working. Somehow even after stripping there are still symbols (as long as you remembered not to compile with -fvisibility=hidden). They show up with nm -D.

Other posts on this topic have discussed other compiler options like -funwind-tables. I didn't find that I needed to set any such option. The default ndk-build options worked.

To use this code, replace _my_log() with your favorite logging or string function.

STLport users see special notes below.

#include

#include

#include

struct android_backtrace_state

{

void **current;

void **end;

};

_Unwind_Reason_Code android_unwind_callback(struct _Unwind_Context* context,

void* arg)

{

android_backtrace_state* state = (android_backtrace_state *)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;

}

void dump_stack(void)

{

_my_log("android stack dump");

const int max = 100;

void* buffer[max];

android_backtrace_state state;

state.current = buffer;

state.end = buffer + max;

_Unwind_Backtrace(android_unwind_callback, &state);

int count = (int)(state.current - buffer);

for (int idx = 0; idx < count; idx++)

{

const void* addr = buffer[idx];

const char* symbol = "";

Dl_info info;

if (dladdr(addr, &info) && info.dli_sname)

{

symbol = info.dli_sname;

}

int status = 0;

char *demangled = __cxxabiv1::__cxa_demangle(symbol, 0, 0, &status);

_my_log("%03d: 0x%p %s",

idx,

addr,

(NULL != demangled && 0 == status) ?

demangled : symbol);

if (NULL != demangled)

free(demangled);

}

_my_log("android stack dump done");

}

What if you are using STLport STL instead of GNU STL?

Sucks to be you (and me). There are two problems:

The first problem is that STLport lacks the __cxxabiv1::__cxa_demangle() call from . You will need to download two source files cp-demangle.c and cp-demangle.h from this repository and place them in a demangle/ subdirectory under your source, then do this instead of #include :

#define IN_LIBGCC2 1 // means we want to define __cxxabiv1::__cxa_demangle

namespace __cxxabiv1

{

extern "C"

{

#include "demangle/cp-demangle.c"

}

}

The second problem is more nasty. It turns out there's not one, not two, but THREE different, incompatible types of in the NDK. And you guessed it, the in STLport (actually it's in the gabi++ library that comes along for a ride when you choose STLport) is incompatible. The fact that the STLport/gabi++ includes come before the toolchain includes (see your ndk-build output's -I options) means that STLport is preventing you from using the real . I could not find any better solution than to go in and hack the filenames inside my installed NDK:

sources/cxx-stl/gabi++/include/unwind.h to sources/cxx-stl/gabi++/include/unwind.h.NOT

sources/cxx-stl/gabi++/include/unwind-arm.h to sources/cxx-stl/gabi++/include/unwind-arm.h.NOT

sources/cxx-stl/gabi++/include/unwind-itanium.h to sources/cxx-stl/gabi++/include/unwind-itanium.h.NOT

I'm sure there's some more elegant solution, however I suspect switching the order of the -I compiler options will probably create other problems, since STLs generally want to override toolchain include files.

Enjoy!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值