概要
tracef は関数コールトレーサです。システムコールトレーサのstraceやptraceと類似の機能を持ち、独自関数もトレースしてくれるものです。もともとhogetraceという名で開発されたようですが、tracefに改称されています。
開発者のページは ここ (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