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億当たってくれー。
■ やること
- コンタクト
[ツッコミを入れる]