11

私の C++ コードで発生するエラーのほとんどは、アプリを単純に終了させ、LogCat の出力はまったくなく、デバイスにメッセージも表示されません。Null ポインターと JNI の不適切な使用により、多くの場合、この結果が生成されます。言うまでもなく、デバッグは非常に困難になります。

現在、ndk-gdb で 'bt' コマンドを使用してスタック トレースを取得できますが、ndk-gdb がプロセスを開始し、開始後にプロセスにアタッチするため、起動の最初の 2 秒以内にクラッシュが発生した場合は取得できません。さらに、ndk-gdb は信頼性が低く、たとえば、シンボルが見つからない、または致命的ではない「SIGILL」エラーについて不平を言うことがよくあります。

アプリがクラッシュしたときに、エラーをトラップしてスタック トレースやその他の情報を出力する方法はありますか? たとえば、SIGSEGV があった場合、アプリがアクセスしようとしたアドレスを知りたいです。

4

4 に答える 4

4

trace.txtファイル何かを与える?彼の居場所が :/data/anr/trace.txtまたは/data/data/{pkg}/trace.txt

于 2012-06-25T18:50:11.350 に答える
1

segv を取得したときにコードを実行するには、SIGSEGV をトラップすることから始める必要があります。これは posix コードなので、似たようなものが Android でも動作するはずです:

void abortHandler( int signum, siginfo_t* si, void* unused )
{
   const char* name = NULL;
   switch( signum )
   {
   case SIGABRT: name = "SIGABRT";  break;
   case SIGSEGV: name = "SIGSEGV";  break;
   case SIGBUS:  name = "SIGBUS";   break;
   case SIGILL:  name = "SIGILL";   break;
   case SIGFPE:  name = "SIGFPE";   break;
   case SIGPIPE: name = "SIGPIPE";  break;
   }

   if ( name )
      printf( stderr, "Caught signal %d (%s)\n", signum, name );
   else 
      printf( stderr, "Caught signal %d\n", signum );

   printStackTrace( stderr );

   exit( signum );
}

void handleCrashes()
{
   struct sigaction sa;
   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = abortHandler;
   sigemptyset( &sa.sa_mask );

   sigaction( SIGABRT, &sa, NULL );
   sigaction( SIGSEGV, &sa, NULL );
   sigaction( SIGBUS,  &sa, NULL );
   sigaction( SIGILL,  &sa, NULL );
   sigaction( SIGFPE,  &sa, NULL );
   sigaction( SIGPIPE, &sa, NULL );
}

次に、その関数を呼び出してシグナル ハンドラを登録します。main で最初に実行できますが、main になるまでスタック トレースを取得できません。以前にそれらが必要な場合は、グローバル オブジェクトのコンストラクターからこの関数を呼び出すことができます。ただし、それが最初に呼び出されるコンストラクターになるという保証はありません。確実に早期に呼び出されるようにする方法があります。たとえば、デバッグ ビルドでは new 演算子をオーバーロードして、最初の割り当てで最初にスタック トレースを初期化し、次に実際の演算子 new を呼び出します。これにより、最初の割り当てから始まるスタック トレースが得られます。

スタック トレースを出力するには:

void printStackTrace( unsigned int max_frames = 63 )
{
   void* addrlist[max_frames+1];

   // retrieve current stack addresses
   u32 addrlen = backtrace( addrlist, sizeof( addrlist ) / sizeof( void* ));

   if ( addrlen == 0 ) 
   {
      printf( stderr, "  <empty, possibly corrupt>\n" );
      return;
   }

   char** symbollist = backtrace_symbols( addrlist, addrlen );

   for ( u32 i = 3; i < addrlen; i++ )
      printf( stderr, "%s\n", symbollist[i] ):
}

シンボルを解読できるようにするには、さらに多くの作業を行う必要があります。abi::__cxa_demangle を試してください。もちろん -g でビルドし、-rdynamic でリンクします。

于 2012-06-25T19:10:56.770 に答える