2013/10/10(木)C++の関数の呼び出し元を調べるには?

はてブ数 2013/10/10 05:19 プログラミング::C++つーさ

つーさゎ、デバッグ用のメモリアロケータを書ぃてゐて、思つた。
標準の_CrtSetDbgFlagナントカカントカはどうも小回りが効かぬ。(というか使い方がよく分からぬ)
ちうか、operator newのoverloadはともかく、置換すんのはやだな……。
C#とかJavaScriptみたいに、関数の呼び出し元アドレスがどこかわかればなー。

かくして、インラインアセンブラの扉は開かれた。ちな、今回の舞台はx86世界な。

実現方法を少し考えてみたら、要は、関数呼び出し時にスタックに積まれてるはずの
リターンアドレス(=関数呼び出しの瞬間のEIPレジスタの値)を変数に読み出して、
それを引数に本命関数を呼び出せればいいんでしょ! ということなので……

じゃあ

こんなんでどうでしょ?

最初はこれがnewとdeleteのオーバーロードの数だけ並んでいたのだけど、
なんかもうちょっとどうにかならないかと思ってマクロにしたものが

こちらになります! ってか。

関数の呼び出し元をくすねてcallee変数に入れておいてくれる
proxy関数を作ってくれる小気味よいマクロにしてみたった。
うむ、小気味よい(陶酔)

呼び出す関数の戻り値について、橋渡しするようなコードを書いてないので、
構造体を返すような関数には使えないけど、まぁ十分というか。

かくして、つーさは、プログラムを動かしつつも
未だdeleteされてゐないnewされたブロックのリストを得る魔を得た。

Releaseビルドでも.mapファイルとcalleeを照合すれば、
呼び出し元が分かるという点、時と場を超えた強みとなろう。

めでたし めでたし。

どちらかというと、C++というよりはx86の寓話であったか。

今回作ってたメモリアロケータ(のラッパ)

双方向リンクドリストをわっかにしておいて、
空になる時の例外処理を書かずに済ますことがマイブーム。
https://gist.github.com/ttsuki/98a60653f398062b15e5

まぁ、最初から、こいつのお世話にならないよう予防策を講じてプログラムを書くのがよい。
というか、普通はそうしてるはずなので、今回の話は思ってたより役に立たなそう。
酒の肴くらいにはなるかの。

Gistって変更履歴が全部見えて恥ずかしいω