私は、Unix/Linuxプラットフォームで次のことを実現できるような種類のツールを探しています。
例えば:
#include <stdio.h>
int square(int x) { return x*x; }
int main(void) {
square(2);
}
そして、私がこのプログラムを実行すると、それは印刷されます
gdb
がある程度これを実行できること、またはvalgrind
が実行できることは理解していますが、すべてが私が望むことを正確に実行しているわけではありません。そのようなツールが存在するかどうか疑問に思っていますか?ありがとう。
gcov
の使用:
$ gcc -O0 --coverage square.c
$ ./a.out
$ gcov -i square.c
$ awk -F '[,:]' '$1 == "function" && $3 > 0 {print $3, $4}' square.c.gcov
1 square
1 main
(ここで、numberは関数が呼び出された回数です(awk
部分の$3 > 0
で呼び出されたことがないものはスキップします))。
これは通常、コードカバレッジ(テストされているコードの量)に使用されます。 gprof
コードプロファイリングツール(通常、コードのさまざまな領域で費やされた時間を把握するために使用されます)を使用することもできます。
$ gcc -O0 -pg square.c
$ ./a.out
$ gprof -b -P
Call graph
granularity: each sample hit covers 2 byte(s) no time propagated
index % time self children called name
0.00 0.00 1/1 main [7]
[1] 0.0 0.00 0.00 1 square [1]
-----------------------------------------------
Index by function name
[1] square
実行可能ファイルが呼び出されたときに関数名を出力するには、GNUシステムで、gcc
の-finstrument-functions
オプションとdladdr()
を使用できます。アドレスを関数名に変換します。
次のようなinstrument.c
を作成します。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#define TRACE_FD 3
void __cyg_profile_func_enter (void *, void *)
__attribute__((no_instrument_function));
void __cyg_profile_func_enter (void *func, void *caller)
{
static FILE* trace = NULL;
Dl_info info;
if (trace == NULL) {
trace = fdopen(TRACE_FD, "w");
if (trace == NULL) abort();
setbuf(trace, NULL);
}
if (dladdr(func, &info))
fprintf (trace, "%p [%s] %s\n",
func,
info.dli_fname ? info.dli_fname : "?",
info.dli_sname ? info.dli_sname : "?");
}
次に、実行可能ファイルを次のようにコンパイルします。
$ gcc -O0 -rdynamic -finstrument-functions square.c instrument.c -ldl
$ ./a.out 3>&1
0x400a8f [./a.out] main
0x400a4f [./a.out] square
(ここでは、fd 3を使用して関数名をダンプし、stdoutおよびstderrストリームから分離します)。
関数名のみが必要な場合は、dli_sname
のみを出力するようにコードを調整できます。