CentOS 7 へ 関数コールトレーサ tracef (hogetrace) をインストール

# 概要
tracef は関数コールトレーサです。システムコールトレーサのstraceやptraceと類似の機能を持ち、独自関数もトレースしてくれるものです。もともとhogetraceという名で開発されたようですが、tracefに改称されています。
開発者のページは [ここ (http://binary.nahi.to/hogetrace/)](http://binary.nahi.to/hogetrace/) にあるのですが文字化けがひどい、かつ、詰まった部分があるのでインストール手順を記載します。なお、開発者ページ原本はUTF-8でエンコーディングすれば読めます。

# インストール
開発者のページにあるインストール手順に沿ってインストールします。

### 1. 必要なパッケージをインストール
- gcc-c++
- libstdc++-devel
- binutils-devel
- elfutils-libelf-devel
- boost-devel
- libdwarf


### 2. ひとまず configure そして make
```
$ tar xvzf tracef-0.1.tar.gz
$ cd tracef-0.1
$ ./configure
$ cd src
$ make
```


### 3. エラー発生！！
上記手順の`make`で以下のようなエラーが発生します。

```
$ make
if g++ -DHAVE_CONFIG_H -I. -I. -I..     -g -O2 -MT prototype.o -MD -MP -MF ".deps/prototype.Tpo" -c -o prototype.o `test -f 'ftrace/prototype.cpp' || echo './'`ftrace/prototype.cpp; \
then mv -f ".deps/prototype.Tpo" ".deps/prototype.Po"; else rm -f ".deps/prototype.Tpo"; exit 1; fi
In file included from ./main.h:20:0,
                 from ftrace/prototype.cpp:12:
./main.h:23:28: error: ‘uintptr_t’ was not declared in this scope
 BOOST_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(unsigned long));
                            ^
./main.h:23:1: error: template argument 1 is invalid
 BOOST_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(unsigned long));
 ^
ftrace/prototype.cpp:38:35: error: ‘elf’ is not a type
   int prototype_add_elf(Elf *elf, elf& pelf);
                                   ^
ftrace/prototype.cpp:52:35: error: ‘elf’ is not a type
   int prototype_add_elf(Elf *elf, elf& pelf)
                                   ^
ftrace/prototype.cpp: In function ‘int {anonymous}::prototype_add_elf(Elf*, int&)’:
ftrace/prototype.cpp:79:38: error: invalid initialization of reference of type ‘hoge::elf&’ from expression of type ‘int’
       prototype_add_cu(dbg, die, pelf);
                                      ^
ftrace/prototype.cpp:39:7: error: in passing argument 3 of ‘int {anonymous}::prototype_add_cu(Dwarf_Debug, Dwarf_Die, hoge::elf&)’
   int prototype_add_cu(Dwarf_Debug dbg, Dwarf_Die die, 
       ^
ftrace/prototype.cpp: In function ‘int hoge::get_debug_info(pid_t, hoge::elf&)’:
ftrace/prototype.cpp:379:30: error: invalid initialization of reference of type ‘int&’ from expression of type ‘hoge::elf’
     prototype_add_elf(e, pelf);
                              ^
ftrace/prototype.cpp:52:7: error: in passing argument 2 of ‘int {anonymous}::prototype_add_elf(Elf*, int&)’
   int prototype_add_elf(Elf *elf, elf& pelf)
       ^
make: *** [prototype.o] Error 1
```

### 4. エラー解決

- まず、`uintptr_t`に関する解決法ですが、関連するファイルに `#include <stdint.h>`を追記すればOKです。
- 次に、`elf`に関するタイプエラーですが、`ftrace/prototype.cpp`の38,53行目で`elf&`を`hoge::elf&`に変更します。

### 5. 次なるエラー発生

```
$ make
if g++ -DHAVE_CONFIG_H -I. -I. -I..     -g -O2 -MT printer.o -MD -MP -MF ".deps/printer.Tpo" -c -o printer.o printer.cpp; \
then mv -f ".deps/printer.Tpo" ".deps/printer.Po"; else rm -f ".deps/printer.Tpo"; exit 1; fi
printer.cpp:17:22: fatal error: asm/user.h: No such file or directory
 #include <asm/user.h>
                      ^
compilation terminated.
make: *** [printer.o] Error 1
```

### 6. 再びエラー解決
`printer.cpp`の17行目`#include <asm/user.h>`を、`#include <sys/user.h>`へ変更します。

なお、次に`make`すると同じエラーが他のファイルでも出るので、 `#include <sys/user.h>`へ変更します。

### 7. またまたエラー発生
```
$ make
if g++ -DHAVE_CONFIG_H -I. -I. -I..     -g -O2 -MT trace.o -MD -MP -MF ".deps/trace.Tpo" -c -o trace.o trace.cpp; \
then mv -f ".deps/trace.Tpo" ".deps/trace.Po"; else rm -f ".deps/trace.Tpo"; exit 1; fi
trace.cpp: In member function ‘uintptr_t hoge::tracer::get_word(uintptr_t) const’:
trace.cpp:95:51: error: ‘CHAR_BIT’ was not declared in this scope
         ret |= (static_cast<uintptr_t>(b) << (i * CHAR_BIT));  
                                                   ^
trace.cpp: In member function ‘void hoge::tracer::set_word(uintptr_t, uintptr_t)’:
trace.cpp:119:40: error: ‘CHAR_BIT’ was not declared in this scope
         sinsn_t b = (w & mask) >> (i * CHAR_BIT);
                                        ^
make: *** [trace.o] Error 1
```

### 8. 再び再びエラー解決　＆＆　インストール完了
`printer.cpp`に`#include <climits>`を追記し、インストール完了です。

# テスト
```~/test/test.c
#include <stdio.h>

void myfunc2(){
  printf("hello world");
}

void myfunc1(){
  myfunc2();
}

int main(int argc, char** argv){
  myfunc1();
  myfunc2();
  return 0;
}
```

```
$ gcc -o ~/test/test.o ~/test/test.c
$ ./tracef --synthetic -flATu ~/test/test.o
[pid 31896] 16:58:31.883982 +++ process 31896 attached (ppid 31895) +++
[pid 31896] 16:58:31.884654 === symbols loaded: '/home/pepper/test/test.o' ===
[pid 31896] 16:58:31.884957 ==> _start() at 0x0000000000400430
[pid 31896] 16:58:31.885269    ==> __libc_start_main@plt() at 0x0000000000400410
[pid 31896] 16:58:31.885524       ==> __libc_csu_init() at 0x0000000000400570
[pid 31896] 16:58:31.885725          ==> _init() at 0x00000000004003c8
[pid 31896] 16:58:31.885866          <== _init() [rax = 0x0]
[pid 31896] 16:58:31.885959          ==> frame_dummy() at 0x00000000004004f0
[pid 31896] 16:58:31.886098          ==> register_tm_clones() at 0x0000000000400490
[pid 31896] 16:58:31.886235          <== register_tm_clones() [rax = 0x0]
[pid 31896] 16:58:31.886322       <== __libc_csu_init() [rax = 0x0]
[pid 31896] 16:58:31.886404       ==> main() at 0x0000000000400542
[pid 31896] 16:58:31.886491          ==> myfunc1() at 0x0000000000400532
[pid 31896] 16:58:31.886587             ==> myfunc2() at 0x000000000040051d
[pid 31896] 16:58:31.886714                ==> printf@plt() at 0x0000000000400400
[pid 31896] 16:58:31.886851                <== printf@plt() [rax = 0xb]
[pid 31896] 16:58:31.887001             <== myfunc2() [rax = 0xb]
[pid 31896] 16:58:31.887135          <== myfunc1() [rax = 0xb]
[pid 31896] 16:58:31.887257          ==> myfunc2() at 0x000000000040051d
[pid 31896] 16:58:31.887393             ==> printf@plt() at 0x0000000000400400
[pid 31896] 16:58:31.887539             <== printf@plt() [rax = 0xb]
[pid 31896] 16:58:31.887631          <== myfunc2() [rax = 0xb]
[pid 31896] 16:58:31.887715       <== main() [rax = 0x0]
[pid 31896] 16:58:31.887794       ==> __do_global_dtors_aux() at 0x00000000004004d0
[pid 31896] 16:58:31.887884       ==> deregister_tm_clones() at 0x0000000000400460
[pid 31896] 16:58:31.887982       <== deregister_tm_clones() [rax = 0x7]
[pid 31896] 16:58:31.888065       ==> _fini() at 0x00000000004005e4
[pid 31896] 16:58:31.888155       <== _fini() [rax = 0x4005e4]
hello worldhello world[pid 31896] 16:58:31.888314 +++ process 31896 detached (ppid 31895) +++
tracef: done
```