LoginSignup
62
61

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-03-02

概要

実行時の関数全ての 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

62
61
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
61