2

リンクの例に従ってみようとしています: https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/

しかし、私はいくつかの問題に遭遇しました。libunwind を使用してバックトレース情報を出力するようなコードがあります。

test.cpp

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>

// Call this function to get a backtrace.
void backtrace() {
  unw_cursor_t cursor;
  unw_context_t context;

  // Initialize cursor to current frame for local unwinding.
  unw_getcontext(&context);
  unw_init_local(&cursor, &context);

  // Unwind frames one by one, going up the frame stack.
  while (unw_step(&cursor) > 0) {
    unw_word_t offset, pc;
    unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (pc == 0) {
      break;
    }
    printf("0x%lx:", pc);

    char sym[256];
    if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
      printf(" (%s+0x%lx)\n", sym, offset);
    } else {
      printf(" -- error: unable to obtain symbol name for this frame\n");
    }
  }
}

void foo() {
  backtrace(); // <-------- backtrace here!
}

void bar() {
  foo();
}

int main(int argc, char **argv) {
  bar();

  return 0;
}

このコードを実行すると、次のような出力が生成されます。つまり、プログラム カウンター値: (function_name+0xoffset)

$ gcc -o libunwind_backtrace -Wall -g test.cpp -lunwind
$ LD_LIBRARY_PATH=/usr/local/lib ./libunwind_backtrace
0x56154da9c9c3: (_Z3foov+0x9)
0x56154da9c9cf: (_Z3barv+0x9)
0x56154da9c9e6: (main+0x14)
0x7facd1cc82e1: (__libc_start_main+0xf1)
0x56154da9c7da: (_start+0x2a)

上記のリンクで述べたように、関数名の左側にあるプログラム カウンターの値を addr2line に入力して、ファイル名と行番号の情報を取得できます。ただし、そうしようとするたびに(たとえば、関数 foo の場合):

$ addr2line 56154da9c9c3 -e libunwind_backtrace
??:0

objdump ファイルを調べたところ、関数 foo にデバッグ エントリがあることがわかりました。

$ objdump --dwarf=info libunwind_backtrace
...
<1><723>: Abbrev Number: 27 (DW_TAG_subprogram)
   <724>   DW_AT_external    : 1
   <724>   DW_AT_name        : foo
   <728>   DW_AT_decl_file   : 1
   <729>   DW_AT_decl_line   : 32
   <72a>   DW_AT_linkage_name: (indirect string, offset: 0x1cb): _Z3foov
   <72e>   DW_AT_low_pc      : 0x9ba
   <736>   DW_AT_high_pc     : 0xc
   <73e>   DW_AT_frame_base  : 1 byte block: 9c     (DW_OP_call_frame_cfa)
   <740>   DW_AT_GNU_all_tail_call_sites: 1
...

DW_at_low_pc の値を addrline に入力すると、正しい出力が生成されます。

addr2line 0x9c6 -e libunwind_backtrace
/root/Desktop/test.cpp:36
  1. まず、libunwind によって返される PC 値が DW_AT_low_pc の値と異なるのはなぜですか?

  2. libunwind が PC に対して正しくない値を返しているようですが、その場合、libunwind はどのようにして関数名を取得できますか?

  3. addr2line またはその他のコマンド ライン ツールを使用してファイル名とファイル番号を取得できる、libunwind からの PC 値を指定する方法はありますか?

読んでくれてありがとう、私はそのちょっと長い質問を知っています。

4

2 に答える 2