2010年10月15日(金) [長年日記]
■ [c++] C++でバックトレースを表示する
bkブログの
で全て語られているけれど、自分で使ってみたのでメモ。環境はUbuntu 10.04。
- バックトレースはThe GNU C Libraryにあるbacktrace()とbacktrace_symbols()を使って取得できる。マニュアルはここ。
- C++の場合、backtrace_symbols()で得られる関数名がマングルされていて読みづらい。The GNU C++ Libraryにあるabi::__cxa_demangle()を使うと元の関数名を取得できる。マニュアルはここ。
サンプルプログラムと実行結果をメモ。backtrace_symbols()のマニュアルにもあるけれど、関数名を得るにはリンカオプションとして -rdynamic を指定しないとうまくいかなかった。下に示すプログラムを -rdynamic なしでビルドしたときの出力結果は
Backtrace: ???: ./a.out() [0x8048e29] ???: ./a.out() [0x8049176] ???: ./a.out() [0x8049370] ???: ./a.out() [0x804937d] ???: ./a.out() [0x804938a] __libc_start_main [error:status=-2]: /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0xb74dabd6] ???: ./a.out() [0x8048d71]
となり、-rdynamic ありでビルドしたときの出力結果は
Backtrace: get_backtrace10(): ./a.out(_Z15get_backtrace10v+0x25) [0x8049e99] f3(): ./a.out(_Z2f3v+0x14) [0x804a1e6] f2(): ./a.out(_Z2f2v+0xb) [0x804a3e0] f1(): ./a.out(_Z2f1v+0xb) [0x804a3ed] main [error:status=-2]: ./a.out(main+0xb) [0x804a3fa] __libc_start_main [error:status=-2]: /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0xb75d3bd6] ???: ./a.out() [0x8049de1]
となった。
#include <cstdlib> #include <iostream> #include <sstream> #include <string> #include <vector> // backtrace()とbacktrace_symbols()はこのヘッダ #include <execinfo.h> // __cxa_demangle() はこのヘッダ #include <cxxabi.h> using std::string; using std::vector; // バックトレース情報を文字列で取得する vector<string> get_backtrace10() { // backtrace()でバックトレース情報を取得できる const int trace_size = 10; void* trace[trace_size]; int size = backtrace(trace, trace_size); // backtrace_symbols()でバックトレース情報を文字列に変換できる char** symbols = backtrace_symbols(trace, size); vector<string> result(symbols, symbols + size); // symbolsをfreeする必要がある free(symbols); return result; } // 取得したバックトレース文字列から関数名部分を切り出す string cut_function_name_part(const string& raw_text) { // '(' ~ '+' までを切り出せばいいみたい string::size_type left = raw_text.find("("); string::size_type right = raw_text.find("+", left + 1); return (left == raw_text.npos || right == raw_text.npos) ? "" : raw_text.substr(left + 1, right - left - 1); } // 関数名をデマングルする string demangle_function_name(const string& mangled) { // __cxa_demangle()でデマングルできる int status = 0; char* demangled = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status); // demangledをfreeする必要がある string result = demangled ? demangled : mangled; free(demangled); if (status != 0) { std::ostringstream oss; oss << " [error:status=" << status << "]"; result += oss.str(); } return result; } void f3() { vector<string> backtrace_texts = get_backtrace10(); std::cout << "Backtrace:\n"; for (vector<string>::const_iterator it = backtrace_texts.begin(), end = backtrace_texts.end(); it != end; ++it) { string mangled_func_name = cut_function_name_part(*it); std::cout << ((!mangled_func_name.empty()) ? demangle_function_name(mangled_func_name) : "???") << ": " << *it << "\n"; } } void f2() { f3(); } void f1() { f2(); } int main() { f1(); }
■ [life] toto当選した!
第475回の3等が。当せん金はなんと250円。2口当たっていたので合わせて500円。買ったのは8口で800円だったから赤字だ。
5年前にtotoGOAL3に当たったことはあった。totoGOAL3は当せん金が少なすぎるので最近はtoto一本をほぼ毎週800円買っていた。今回は天皇杯でJ1vsJ2の試合が多くて予想は簡単だったんだよなあ。
今日もtoto買った。1億当たってくれー。
■ やること
- コンタクト