19

ソース コードを変更せずに、関数 (次の例では func100 など) が呼び出されたときに、どの関数がどのパラメーターで呼び出されたかを追跡するにはどうすればよいでしょうか。出力を次のようにしたいと思います。

enter func100(p1001=xxx,p1002=xxx)
        enter func110(p1101=xxx,p1102=xxx)
        exit  func110(p1101=xxx,p1102=xxx)
        enter func120(p1201=xxx,p1202=xxx,p1203=xxx)
                enter func121(p1211=xxx)
                exit  func121(p1211=xxx)
        exit  func120(p1201=xxx,p1202=xxx,p1203=xxx)
exit  func100(p1001=xxx,p1002=xxx)

これは実行可能ですか?または、ソース コードの変更を最小限に抑えたソリューションは何ですか?

4

9 に答える 9

21

を使用する場合は、コンパイル フラグgccを使用できます。関数が開始/終了するたびに、との-finstrument-functions2 つの関数を呼び出すコードを追加します。__cyg_profile_func_enter__cyg_profile_func_exit

必要なことを行うには、これらの関数を実装する必要があります。フラグなしでコンパイルするか、フラグを付けてコンパイルして、__attribute__((no_instrument_function))自分自身を呼び出そうとしないようにしてください。

関数の 2 番目のパラメーターは、呼び出しサイト (つまり、呼び出し元の関数内の戻りアドレス) へのポインターになります。でそのまま印刷できますが%p、ちょっと使いづらいです。nmこのアドレスを含む実際の関数を把握するために使用できます。

この方法では関数パラメーターを取得できません。

于 2012-04-29T17:09:21.737 に答える
14

GNU C ライブラリを使用すると、backtraceモジュールを使用できます。その例を次に示します。

#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>


void handler(char *caller) {
  void *array[10];
  size_t size;
  printf("Stack Trace Start for %s\n",caller);
  size = backtrace(array, 10);
  backtrace_symbols_fd(array, size, 2);
  printf("Stack Trace End\n");
}

void car() {
    handler("car()");
    printf("Continue Execution");
}
void baz() {car(); }

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  foo(); 
}

-g -rdynamicシンボルをロードするコンパイラ オプションを指定してコンパイルする

gcc -g -rdynamic Test1.c -o Test

次のような出力が表示されます

Stack Trace Start for car()
./Test(handler+0x2d)[0x80486f1]
./Test(car+0x12)[0x804872e]
./Test(baz+0xb)[0x8048747]
./Test(bar+0xb)[0x8048754]
./Test(foo+0xb)[0x8048761]
./Test(main+0xb)[0x804876e]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x126e37]
./Test[0x8048631]
Stack Trace End
Continue Execution in car

このハンドラ関数を記述して、プログラムのどこからでもいつでも呼び出すことができます。array必要に応じてサイズを大きくすることを忘れないでください。

于 2012-04-29T17:11:05.357 に答える
5

Linux を使用している場合は、callgrindが役立つ場合があります。基本的に、探しているものの統計を収集するため、生データにアクセスする方法を提供する場合があります。

于 2012-04-29T17:01:56.960 に答える
3

デバッガーを使用して、関連付けられたアクションでブレークポイントを設定します。たとえば、gdb では、トレースする各関数の最初と最後にブレークポイントを設定できます。これらの各ブレークポイントに、次のような実行するコマンドを指定できます。

printf("Enter func100(p1001=%d, p1002=%d)", p1001, p1002)

次に、プログラムを (デバッガーで) 実行すると、各コマンドのテキストが関連するパラメーターと共に出力されます。

gdbの関連ドキュメントをご覧ください。

于 2012-04-29T17:17:57.843 に答える
0

Apache Foundation がホストするプロジェクトである log4cxx を調べることができます。java の亜種である log4j を使用すると、感度を設定でき、プログラムで実行されたすべてのことを追跡できることを私は知っています。おそらく、C++ バリアントは同じですが、いくつかの代替手段があります。アスペクト指向の C++ コンパイラがあり、すべての関数にわたってアスペクトを定義し、変数をキャッチして出力させることができます。もう 1 つの方法は、デバッガーを使用することです。

要約すると、デバッガー、log4cxx または AOP

于 2012-04-29T17:02:36.600 に答える