私はgnuツールチェーンを使用しています。実行時に、関数の呼び出し元を見つけるにはどうすればよいですか?たとえば、関数B()は、関数ポインタを使用して多くの関数によって呼び出されます。ここで、Bが呼び出されるたびに、呼び出し元の名前を出力したいと思います。特定の問題をデバッグするためにこれが必要です。
GNUを使用している場合は、 backtrace 関数を使用できます。そのmanページに使用例があります。
関数の呼び出しのコードの場所は、gccによって __builtin_return_address()
組み込みで保持されます。そのためにnameを取得するには、プログラムのシンボルテーブルを解析する必要があります。 dladdr()
を介してそれを行うことは可能ですが、これには制限があります。
backtrace()
/dladdr()
を呼び出すことは、すべてのコンテキストで安全ではない可能性があります(たとえば、シグナルハンドラーから、またはマルチスレッドプログラムで同時に、またはmalloc()
。)。backtrace()
のマンページには、dladdr()
のマンページと同様に、これも記載されています。 「バグ」セクション)。多くの場合、decoupleトレースと関数名の解決に適した方法です。つまり、リターンアドレスを(16進数/バイナリとして)出力し、プログラムの実行中に取得されたシンボルテーブルに対して結果のログを後処理するだけです。
同様の質問に答えて Vasil Dimov で指摘されている別の方法は、関数呼び出しを、呼び出し元の関数名を報告または渡すラッパーマクロに置き換えることです。これは、バックトレースが機能しないインライン関数で機能します。一方、参照によって関数を呼び出すか、そうでなければそのアドレスを取得すると、機能しません。
例:これ:
int B(int x){
...
}
になる可能性があります:
int _B(int x, char *caller){
printf("caller is %s\n", caller);
...
}
#define B(x) _B((x), __func__)
B()を呼び出すたびに、呼び出し元の名前が出力されます。VasilDimovは、名前をマクロに直接出力し、関数を変更せずに、異なる方法で作成します。