5

私はこの質問に対する答えを見つけることに成功していません。

GDB を使用すると、"call" コマンドを使用して関数のプロトタイプを取得できます。例:

(gdb) call fn
$1 = {void (int, int)} 0x8048414 <fn>

そのため、GDB は elf ファイルからのみ、fn() が void を返し、引数として 2 つの整数を取ることを把握できます。

ただし、elf ファイルから関数プロトタイプを抽出するには、他のツールを使用する必要があります。できれば、objdump / readelf を使用したいと考えています。

これが可能かどうか誰にもわかりますか?それが不可能な場合、GDB はどのようにそれを行いますか? 関数プロトタイプが保存されているのは、elf ファイルのどのセクションですか?

4

1 に答える 1

4

GDB は、DWARF debuginfo を通じて関数のシグネチャを認識します。readelf -w ELFそれを捨てるでしょう。おそらく、Michael J. Eager によるIntroduction to the DWARF Debugging Formatを読みたいと思うでしょう。pyelftoolsを使用すると、インタラクティブな Python セッションから DWARF を探索および実験できます。

関数プロトタイプを抽出するには、subprogramデバッグ情報エントリが必要です。DWARF 形式のチュートリアルの例は次のとおりです。

strndup.c

 1: #include "ansidecl.h"
 2: #include <stddef.h>
 3:
 4: extern size_t strlen (const char*);
 5: extern PTR malloc (size_t);
 6: extern PTR memcpy (PTR, const PTR, size_t);
 7:
 8: char *
 9: strndup (const char *s, size_t n)
10: {
11: char *result;
12: size_t len = strlen (s);
13:
14: if (n < len)
15: len = n;
16:
17: result = (char *) malloc (len + 1);
18: if (!result)
19: return 0;
20:
21: result[len] = '\0';
22: return (char *) memcpy (result, s, len);
23: }

strndup.c の DWARF 記述

<1>: DW_TAG_base_type
   DW_AT_name = int
   DW_AT_byte_size = 4
   DW_AT_encoding = signed
<2>: DW_TAG_typedef
   DW_AT_name = size_t
   DW_AT_type = <3>
<3>: DW_TAG_base_type
   DW_AT_name = unsigned int
   DW_AT_byte_size = 4
   DW_AT_encoding = unsigned
<4>: DW_TAG_base_type
   DW_AT_name = long int
   DW_AT_byte_size = 4
   DW_AT_encoding = signed
<5>: DW_TAG_subprogram
   DW_AT_sibling = <10>
   DW_AT_external = 1
   DW_AT_name = strndup
   DW_AT_prototyped = 1
   DW_AT_type = <10>
   DW_AT_low_pc = 0
   DW_AT_high_pc = 0x7b
<6>: DW_TAG_formal_parameter
   DW_AT_name = s
   DW_AT_type = <12>
   DW_AT_location =
   (DW_OP_fbreg: 0)
<7>: DW_TAG_formal_parameter
   DW_AT_name = n
   DW_AT_type = <2>
   DW_AT_location =
   (DW_OP_fbreg: 4)
<8>: DW_TAG_variable
   DW_AT_name = result
   DW_AT_type = <10>
   DW_AT_location =
   (DW_OP_fbreg: -28)
<9>: DW_TAG_variable
   DW_AT_name = len
   DW_AT_type = <2>
   DW_AT_location =
   (DW_OP_fbreg: -24)
<10>: DW_TAG_pointer_type
   DW_AT_byte_size = 4
   DW_AT_type = <11>
<11>: DW_TAG_base_type
   DW_AT_name = char
   DW_AT_byte_size = 1
   DW_AT_encoding =
   signed char
<12>: DW_TAG_pointer_type
   DW_AT_byte_size = 4
   DW_AT_type = <13>
<13>: DW_TAG_const_type
   DW_AT_type = <11>

より完全なサンプル実装については、Petr Machata によるこの C リフレクション ライブラリをご覧ください。次の警告を使用して、必要なことを行うコードがあります。

  • リフレクションは、GDB のようなアウトプロセスではなく、インプロセスで実行されます
  • これはelfutilsに依存していlibdwます。これらの外部ライブラリの依存関係の拡大についてどのように感じるかわかりません。libdwfl
于 2014-03-19T10:21:57.477 に答える