web-dev-qa-db-ja.com

GDBの関数を評価する方法は?

GDBで関数を評価できないのはなぜですか?私のソースファイルには、gdbでデバッグするときに、これらの例は間違った評価です。

(gdb) p pow(3,2)

$10 = 1

(gdb) p pow(3,3)

$11 = 1

(gdb) p sqrt(9)

$12 = 0
29
Tim

私の推測では、コンパイラとリンカはそれらの特定の関数でいくつかの魔法をします。パフォーマンスを向上させる可能性が最も高い。

pow()をgdbで使用可能にする必要がある場合は、独自のラッパー関数を作成できます。

double mypow(double a, double b)
{
    return pow(a,b);
}

たぶんそれを#ifdef DEBUGまたは最終バイナリを乱雑にしないもの。

ところで、あなたは他のライブラリ関数を呼び出すことができることに気付くでしょう(そしてそれらの戻り値が出力される)、例えば:

(gdb) print printf("hello world")
$4 = 11
19
Isak Savo

パラメータに適切な型を与えることに加えて、通常のレジスタではなく浮動小数点レジスタで戻り値を見つけることをgdbに伝える必要があります。

つまり:

(gdb)p((double(*)())pow)(2.、2。)

$ 1 = 4

19
anon

Gdbで関数を呼び出すための構文は次のとおりです。

call pow(3,2)

タイプ

help call

詳細については、gdbプロンプトで確認してください。

18

実際、少なくともgccのLINUX実装では、math.hおよびbits/mathcalls.h(math.h内に含まれる)によって取り込まれた派手な置換を介して、数学関数の多くが引数のタイプに固有のバリアントに置き換えられます。 )。結果として、代わりにpowやexpなどの関数が___pow_または_*__GI___exp_として呼び出されます(結果は引数のタイプと特定のバージョンによって異なる場合があります)。

私のコードにリンクされている関数が何であるかを正確に識別するために、その関数だけが呼び出される行にブレークを入れます。コードにb=exp(c);の行があります。次に、そのブレークポイントまでgdbで実行し、「step」コマンドを使用してその行から呼び出しを入力します。次に、「where」コマンドを使用して、呼び出されたルーチンの名前を識別できます。私の場合、それは_*__GI___exp_でした。

この情報を取得するための賢い方法はおそらくありますが、プリプロセッサを単独で実行する(-Eオプション)か、生成されたアセンブリコードを見る(-s)だけでは正しい名前を見つけることができませんでした。

4
Robert Indik

powは、関数ではなくマクロとして定義されます。 gdbの呼び出しは、プログラムまたは共有ライブラリの関数のみを呼び出すことができます。したがって、gdbでのpowの呼び出しは失敗するはずです。

  (gdb) p pow(3,2)
  No symbol "pow" in current context.

これは、pow(int、int)を呼び出すソースのgcc生成バイナリコードです。

  (gdb) list
  1       int main() {
  2       int a=pow(3,2);
  3       printf("hello:%d\n", a);
  4       }
  (gdb) x/16i main
     0x4004f4 <main>:     Push   %rbp
     0x4004f5 <main+1>:   mov    %rsp,%rbp
     0x4004f8 <main+4>:   sub    $0x10,%rsp
     0x4004fc <main+8>:   movl   $0x9,-0x4(%rbp)
  => 0x400503 <main+15>:  mov    -0x4(%rbp),%eax
     0x400506 <main+18>:  mov    %eax,%esi
     0x400508 <main+20>:  mov    $0x40060c,%edi
     0x40050d <main+25>:  mov    $0x0,%eax
     0x400512 <main+30>:  callq  0x4003f0 <printf@plt>
     0x400517 <main+35>:  leaveq
     0x400518 <main+36>:  retq
     0x400519:    nop
     0x40051a:    nop
     0x40051b:    nop
     0x40051c:    nop
     0x40051d:    nop

以下は、pow(float、float)を呼び出すソースのgcc生成バイナリコードです。

  (gdb) list
  1       int main() {
  2       double a=pow(0.3, 0.2);
  3       printf("hello:%f\n", a);
  4       }
  (gdb) x/16i main
     0x4004f4 <main>:     Push   %rbp
     0x4004f5 <main+1>:   mov    %rsp,%rbp
     0x4004f8 <main+4>:   sub    $0x10,%rsp
     0x4004fc <main+8>:   movabs $0x3fe926eff16629a5,%rax
     0x400506 <main+18>:  mov    %rax,-0x8(%rbp)
     0x40050a <main+22>:  movsd  -0x8(%rbp),%xmm0
     0x40050f <main+27>:  mov    $0x40060c,%edi
     0x400514 <main+32>:  mov    $0x1,%eax
     0x400519 <main+37>:  callq  0x4003f0 <printf@plt>
     0x40051e <main+42>:  leaveq
     0x40051f <main+43>:  retq
1
Houcheng
NAME
   pow, powf, powl - power functions

SYNOPSIS
   #include <math.h>

   double pow(double x, double y);

Doubleの代わりにintを渡すべきではありません

 call pow( 3. , 2. )

また、単一の引数を渡すだけでは不十分です。関数が期待するように2つの引数が必要です。

 wrong: call pow ( 3. )
0
Adrian Panasiuk