実行時の関数全ての in/out をトレースする

  • 44
    いいね
  • 3
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

実行時の関数全ての in/out をトレースする。
もう、

printf("%d %s \n", __LINE__, __func__);

こういう DebugPrint 1関数ずつ入れなくてOK。
素敵ポイント: 大元のソースには手を入れない。
gcc 使用。

ソース

helloworld.cpp
#include<stdio.h>

/* Proto Type */
void hello_world( void );

void
hello_world(void)
{
    printf( "hello!\n" );
}

int
main(void)
{
    hello_world();
    return 0;
}
simpletrace.cpp
#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