5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

gdb上で再現しないセグフォをgdbで追跡する

Last updated at Posted at 2020-01-07

ごくたまにGDB上で再現しないバグに遭遇することがある。
自分の場合は並列バグが問題で、gdb上だとタイミングが変わってしまいバグが再現しなくなった。

なので、gdbを介さずにプログラムを普通に走らせておき、セグフォが発生した時点でgdbを起動して検死できるようにしたい。
アイデアとしては、プログラム自体にシグナルハンドラを仕込んでおき、SIGSEGVが発生した時点でsleepを呼んで停止、あとは手動でgdb attachをかける。

手順

1. SIGSEGVを捕捉するシグナルハンドラをプログラムに追加

まずはシグナルハンドラを定義。後からgdbでattachできるように十分な時間sleepするようにする。

void segv_handler(int sig) {
  sleep(100000000);
}

次にsigaction()コールを使ってシグナルハンドラを登録しておく。

struct sigaction sa;
sa.sa_flags   = 0;
sa.sa_handler = segv_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, NULL);

2. セグフォが起きるまで待つ

3. gdbでattachする

セグフォが発生してsleepし始めたら適当にpidを調べ、

$ gdb attach <pid>

でattach。これでセグフォをgdbで追跡可能。

サンプルプログラム

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void segv_handler(int sig) {
  /* printf() cannot be used because it's not async-signal-safe */
  write(2, "segfault\n", 9);
  sleep(100000000);
}

int main() {
  /* register a signal handler for SIGSEGV */
  struct sigaction sa;
  sa.sa_flags   = 0;
  sa.sa_handler = segv_handler;
  sigemptyset(&sa.sa_mask);
  if (sigaction(SIGSEGV, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
  }

  /* raise SIGSEGV */
  int* a = 0;
  *a = 1;

  return 0;
}

コンパイルして実行、segfaultと表示されたらgdb attachで追えるはず

おわりに

セグフォじゃなくても他のシグナル(SIGFPEとか)を捕捉することも可能。

あとcoredumpでも同じようなことができるような気はするが、プログラムが大きくなってくるとdumpのファイルサイズが大きすぎて大変なことになったりするのでこっちの方がシンプルで良い気がする。

gistにも書いた
Debug segfaults that only happen outside of gdb

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?