1

スタックトレース出力をstderrに取得したり、ログファイルにダンプしたりする際に問題が発生します。Kubuntu10.04でgccコンパイラ(4.4.3)を使用してコードを実行しています。問題は、通常の実行モード(gdbなし)では、プログラムが「セグメンテーション違反」以外は何も出力しないことです。以下のprintステートメントのようにバックトレース出力を出力したいと思います。アプリケーションでgdbを実行すると、printf / fprintf /(関数呼び出し)ステートメントが表示され、次のステートメントでクラッシュします。

669     {
(gdb) 
670       printf("Testing for stability.\n");
(gdb) 

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffff68b1f45 in puts () from /lib/libc.so.6

奇妙なことに、同じファイル内でクラッシュする関数を呼び出すと機能し、正常に機能し、出力を適切に出力します。ただし、このファイルの外部の関数でプログラムがクラッシュした場合、出力は出力されません。したがって、printfまたはファイルダンプステートメントまたは関数呼び出しは処理されません。次のサンプルコードを使用しています。

void bt_sighandler(int sig, siginfo_t *info,
               void *secret) {

void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
ucontext_t *uc = (ucontext_t *)secret;

/* Do something useful with siginfo_t */
if (sig == SIGSEGV)
  printf("Got signal %d, faulty address is %p, "
       "from %p\n", sig, info->si_addr, 
       uc->uc_mcontext.gregs[0]);
else
  printf("Got signal %d#92; \n", sig);

trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *) uc->uc_mcontext.gregs[0];

messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:#92; \n");
for (i=1; i<trace_size; ++i)
  printf("[bt] %s#92; \n", messages[i]);

exit(0);
}


int main() {

/* Install our signal handler */
struct sigaction sa;

sa.sa_sigaction = (void *)bt_sighandler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
/* Do something */
printf("%d#92; \n", func_b());
}

助けてくれてありがとう。

4

6 に答える 6

3

残念ながら、SIGSEGVハンドラーではほとんど何も確実に実行できません。このように考えてください。プログラムに重大なエラーがあり、その状態(ヒープなどのシステムレベルの状態を含む)が一貫性のない状態になっています。

このような場合、OSがシグナルハンドラ内で任意のコードを実行できるようにするために必要なヒープやその他の内部構造を魔法のように修正することは期待できません。

SEGVが独自のコードで発生する場合、適切な解決策はコアを使用して根本的な問題を修正することです。コアが共有ライブラリなどを介して他のコードで発生する場合は、そのコードを完全に別個のバイナリに分離し、2つのバイナリ間で通信することをお勧めします。次に、ライブラリがクラッシュしても、メインプログラムはクラッシュしません。

于 2011-03-22T12:49:11.457 に答える
2

シグナル ハンドラーでは、原則として、sig_atomic_t 型の変数と揮発性データにのみアクセスする必要があります。

I/O を行うことは間違いなく問題外です。gcc については、次のページを参照してください。

http://www.gnu.org/s/libc/manual/html_node/Nonreentrancy.html#Nonreentrancy

于 2011-03-22T12:05:18.463 に答える
0

strcat() や write() などのより単純な関数を使用してみてください。

于 2011-03-22T12:13:38.093 に答える
0

私はそれを部分的に機能させることができました。実際には、アプリケーションを「sudo」モードで実行していました。ユーザーモードで実行すると、コールスタックが表示されます。ただし、ユーザー モードで実行すると、ハードウェア アクセラレーション (nvidia グラフィックス ドライバー) が無効になります。これを解決するために、「ビデオ」グループに自分自身を追加して、/dev/nvidia0 と /dev/nvidiactl にアクセスできるようにしました。ただし、アクセスを取得すると、スタックは生成されなくなります。ユーザーモードでハードウェアアクセラレーションが無効になっている場合にのみ、スタックが来ます。しかし、ハードウェア アクセラレーションなしではアプリケーションを実行できません (重要な機能の一部が無効になることを意味します)。誰かアイデアがあれば教えてください。

ありがとう。

于 2011-03-25T06:12:05.413 に答える
0

valgrind を使用できない理由はありますか?

于 2011-03-22T13:01:13.157 に答える
0

アプリケーションがクラッシュすると、Linux はクラッシュ時のアプリケーションの状態でコア ダンプを作成します。コア ファイルは、gdb を使用して調べることができます。

コア ファイルが作成されない場合は、コア ファイルのサイズを変更してみてください。

ulimit -c unlimited

同じシェルで、プログラムが開始される前に。通常、コア ファイルの名前は core.PID で、PID はプログラムの pid です。コア ファイルは通常、/tmp またはプログラムが開始されたディレクトリのどこかに配置されます。

コア ファイルの詳細については、コアのマニュアル ページを参照してください。使用する

man core

マニュアルページを読む。

于 2011-03-22T14:12:57.610 に答える