概要
実行時の関数全ての in/out をトレースする。
もう、
printf("%d %s \n", __LINE__, __func__);
こういう DebugPrint 1関数ずつ入れなくてOK。
素敵ポイント: 大元のソースには手を入れない。
gcc 使用。
ソース
#include<stdio.h>
/* Proto Type */
void hello_world( void );
void
hello_world(void)
{
printf( "hello!\n" );
}
int
main(void)
{
hello_world();
return 0;
}
#define _GNU_SOURCE
#include <dlfcn.h>
#include <iostream>
extern "C" {
void __cyg_profile_func_enter(void* func_address, void* call_site);
void __cyg_profile_func_exit(void* func_address, void* call_site);
}
// dladdrを用いて関数アドレスから関数シンボルへ変換
const char* addr2name(void* address) {
Dl_info dli;
if (0 != dladdr(address, &dli)) {
return dli.dli_sname;
}
return 0;
}
void __cyg_profile_func_enter(void* func_address, void* call_site) {
const char* func_name = addr2name(func_address);
if (func_name) {
std::cout << "simple tracer: enter - " << func_name << std::endl;
}
}
void __cyg_profile_func_exit(void* func_address, void* call_site) {
const char* func_name = addr2name(func_address);
if (func_name) {
std::cout << "simple tracer: exit - " << func_name << std::endl;
}
}
ビルド
$ g++ -fPIC -shared simpletrace.cpp -o libsimpletrace.so -rdynamic -ldl
$ g++ -fPIC -finstrument-functions helloworld.cpp -o helloworld
実行
普通に実行。
$ ./helloworld
hello!
いざ、 in/out をトレースし実行。
$ LD_PRELOAD=./libsimpletrace.so ./helloworld
simple tracer: enter - main
simple tracer: enter - _Z11hello_worldv
hello!
simple tracer: exit - _Z11hello_worldv
simple tracer: exit - main
| c++filt でパイプして関数名を読めるように。
$ LD_PRELOAD=./libsimpletrace.so ./helloworld | c++filt
simple tracer: enter - main
simple tracer: enter - hello_world()
hello!
simple tracer: exit - hello_world()
simple tracer: exit - main
解説
ポイントは、 -finstrument-functions
。
関数の in/out で指定した関数を呼ぶ、というオプション。
in のときにやりたい処理を __cyg_profile_func_enter
に、
out のときにやりたい処理を __cyg_profile_func_exit
に記載する。
参考
http://d.hatena.ne.jp/torutk/20090126
2009-01-26 関数トレーサ
■[C++][Linux]GCCのコンパイルオプションで関数トレーサ
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/dlsym.3.html
Man Page of DLOPEN
詰まったところ
最初はビルドコマンドを
$ g++ -fPIC -shared simpletrace.cpp -o libsimpletrace.so
としていたが、実行時に dladdr が無いと怒られたので、 -rdynamic -ldl を追加し、
$ g++ -fPIC -shared simpletrace.cpp -o libsimpletrace.so -rdynamic -ldl
で実行できるようになった。
環境: Ubuntu 12.04