🦛

glibcのbacktrace_symbols_fd関数を使う

2021/08/14に公開

はじめに

glibcbacktrace_symbols_fd関数を使用してみます。

サンプル

Backtraces
以下のようなサンプルが記載されています。
ここではbacktracebacktrace_symbolsが使用されています。

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
  void *array[10];
  char **strings;
  int size, i;

  size = backtrace (array, 10);
  strings = backtrace_symbols (array, size);
  if (strings != NULL)
  {

    printf ("Obtained %d stack frames.\n", size);
    for (i = 0; i < size; i++)
      printf ("%s\n", strings[i]);
  }

  free (strings);
}

/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
  print_trace ();
}

int
main (void)
{
  dummy_function ();
  return 0;
}

backtrace_symbols_fdという関数もあるので、こちらを使用した例を書いてみました。

backtrace_symbols_fdを使用した例

以下のようなコードを書いてみました。
上記のbacktrace_symbolsを使用した例とほぼ同じです。
main関数内でbacktraceした結果を書き込むファイルをopenして、
fileno関数でファイルディスクリプタを取得しています。

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

FILE* fd;
int filedescriptor;
/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
  void *array[10];
  char **strings;
  int size, i;

  size = backtrace (array, 10);
  backtrace_symbols_fd (array, size, filedescriptor);
}

/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
  print_trace ();
}

int
main (void)
{
  // パスは環境に合わせて修正してください
  fd = fopen("/home/yutaka/temp/glibcs/log.log","w");
  filedescriptor = fileno(fd);
  dummy_function ();
  return 0;
}

コンパイルして、実行します。
トレース結果に関数名を出力するため、-rdynamicオプションを付けます。

$ gcc -o sample sample.c -rdynamic
$ ./sample

出力されたlog.logファイルを見ると、backtraceの結果が出力されました。

$ cat log.log
./sample(print_trace+0x19)[0x40115f]
./sample(dummy_function+0x9)[0x401185]
./sample(main+0x34)[0x4011bc]
/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/libc.so.6(__libc_start_main+0xed)[0x7f890247ea6d]
./sample(_start+0x2a)[0x40109a]

Discussion