0

関数を使用して、関数bfd_find_nearest_lineのソースの場所を見つけています(デバッグシンボルを含む実行可能ファイルから--compiled with -g)。当然、引数の 1 つは、検索したい関数へのポインターです。

boolean
_bfd_elf_find_nearest_line (abfd, 
                section, 
                symbols, 
                offset, 
                filename_ptr, 
                functionname_ptr, // <- HERE!
                line_ptr)

https://sourceware.org/ml/binutils/2000-08/msg00248.html

かなりの量の (純粋な C) ボイラー プレートの後、これが通常の関数 (通常の関数ポインターが にキャストされる*void) で動作するように管理しました。

たとえば、これは機能します:

int my_function(){return 5;}

int main(){
    _bfd_elf_find_nearest_line (...,
                (void*)(&my_function), 
                ...);
}

問題はbfd_find_nearest_line、クラス メンバー関数のソース コードを検索するために使用できるかどうかです。

struct A{
   int my_member_function(){return 5.;}
};

_bfd_elf_find_nearest_line (...,
                what_should_I_put_here??, 
                ...)

クラス メンバ関数 (この場合は type の場合int (A::*)()) は関数ではありません。特に、 は関数ポインタにキャストできませんvoid*。ここを参照してください: https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr

この背後にあるロジックを完全に理解していますが、メンバー関数ポインターは、BFD に関数を識別させるためにメンバー関数の情報を取得する唯一のハンドルです。このポインターで関数を呼び出したくありません。

私は多かれ少なかれ C++ がどのように機能するかを知っています。コンパイラは同等の free-C 関数を静かに生成します。

__A_my_member_function(A* this){...}

しかし、この無料関数のアドレスにアクセスする方法、またはそれが可能かどうか、ライブラリがこのポインターを介してbfd元のソースの場所を特定できるかどうかはわかりません。my_member_function(現時点では、少なくとも私は仮想関数には興味がありません。)

言い換えると、

1)bfdメンバー関数を見つけることができるかどうかを知る必要があります。

2)そして、可能な場合、型のメンバー関数ポインターを()を取ることができるint (A::*)()引数にどのようにマップできますか。bfdvoid*


ポインターが存在することは他の手段 (スタック トレース) で知ってい_ZN1A18my_member_functionEvます&(A::my_member_function)

4

2 に答える 2

0

さて、良いニュースと悪いニュースがあります。

良いニュース: それ可能です。

悪いニュース: 簡単ではありません。

c++filtユーティリティが必要です。

また、実行可能ファイルのシンボル テーブルを読み取る何らかの方法 ( readelf. [mangled] シンボルを呼び出しで列挙できればbfd_*、手順を節約できる可能性があります。

また、ここに重要な点があります。テキスト文字列でシンボルの c++ 名が必要になります。したがって、 for &(A::my_member_function)、フォームで必要になり"A::my_member_function()"ます。気にするそれらの数は限られていると思われるため、これはそれほど難しくないはずです。

からシンボルとそのア​​ドレスのリストを取得する必要がありますreadelf -s <executable>。この出力を解析する準備をしてください。バイナリ値を取得するには、文字列から 16 進アドレスをデコードする必要があります。

これらはマングルされた名前になります。シンボルごとにc++filt -n mangled_name、出力 (つまり、パイプ) を何か (例えばnice_name) にキャプチャします。デマングルされた名前が返されます (つまり、希望する適切な C++ 名)。

ここで、nice_name"A:my_member_function()" と一致する場合は、一致があり、マングルされた名前が既にありますが、さらに重要なことに、シンボルの 16 進アドレスがあります。この16進値を[適切にキャスト]して、詰め込んでいたbfdにフィードしますfunctionname_ptr


注:上記は機能しますが、繰り返し呼び出すと遅くなる可能性がありますc++filt

これを行うためのより高速な方法は、次のパイプ出力をキャプチャすることです。

readelf -s <executable> | c++filt

また、フィルタリングされた出力を解析し、一致するナイス ネームを探すだけでよいため、[おそらく] この方法の方が簡単です。

また、関心のあるシンボルが複数ある場合は、1 回の呼び出しですべてのアドレスを取得できます。

于 2016-05-05T02:38:47.467 に答える