1

C関数のバックトレースは、プログラムの一連の関数呼び出しを返すだけですが、gdbの情報ローカルと同じように、プログラム内のすべてのローカル変数をリストしたい.これができるかどうか何か考えはありますか? ありがとう

4

3 に答える 3

3

一般的に、いいえ。「スタック」を事実を与えられたある種の神と考えるのはやめるべきです。コール スタックは、C の一般的な実装手法にすぎません。固有の意味や必要なセマンティクスはありません。自動変数 (あなたが言うように、「ローカル変数」) は特定の方法で動作する必要があり、それはコール スタックに書き込まれることを意味する場合もあります。ただし、ローカル変数がメモリ内でまったく実現されないことは完全に考えられます。代わりに、ローカル変数はプロセッサレジスタに格納されるか、同等のプログラムをそれらなしで定式化できる場合は完全に削除される可能性があります。

いいえ、ローカル変数を列挙するための言語固有のメカニズムはありません。あなたが言うように、デバッガーはある程度それを行うことができます(デバッグシンボルが存在し、最適化の対象となることに応じて)。おそらく、実行中のプログラム内からデバッグ シンボルを処理できるライブラリを見つけることができます。

于 2012-08-27T14:21:04.920 に答える
0

backtraceまず、は標準の C ライブラリ関数ではなく、GNU 固有の拡張機能である ことに注意してください。

一般に、コンパイルされたコードからローカル変数情報を取得することは、特にデバッグなしでコンパイルされた場合や最適化を有効にしてコンパイルされた場合、不可能にすることは困難です。デバッグがオンになっていない場合、変数の名前と型は通常、結果のマシン コードに保持されません。

たとえば、次の途方もなく単純なコードを見てみましょう。

#include <stdio.h>
#include <math.h>

int main(void)
{
  int x = 1, y = 2, z;
  z = 2 * y - x;
  printf("x = %d, y = %d, z = %d\n", x, y, z);
  return 0;
}

マシンコードの結果は次のとおりです。デバッグや最適化は行われていません。

        .file   "varinfo.c"
        .version        "01.01"
gcc2_compiled.:
                .section        .rodata
.LC0:
        .string "x = %d, y = %d, z = %d\n"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    $1, -4(%ebp)
        movl    $2, -8(%ebp)
        movl    -8(%ebp), %eax
        movl    %eax, %eax
        sall    $1, %eax
        subl    -4(%ebp), %eax
        movl    %eax, -12(%ebp)
        pushl   -12(%ebp)
        pushl   -8(%ebp)
        pushl   -4(%ebp)
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        movl    $0, %eax
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

xy、およびは、それぞれ、、およびzを通じて参照されます。算術を実行するために使用される命令以外に、それらが整数であることを示すものは何もありません。 -4(%ebp)-8(%ebp)-12(%ebp)

最適化 (-O1) をオンにするとさらに良くなります。

        .file   "varinfo.c"
        .version        "01.01"
gcc2_compiled.:
        .section        .rodata.str1.1,"ams",@progbits,1
.LC0:
        .string "x = %d, y = %d, z = %d\n"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        pushl   $3
        pushl   $2
        pushl   $1
        pushl   $.LC0
        call    printf
        movl    $0, %eax
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

この場合、コンパイラは静的な分析を行いz、コンパイル時に値を計算できました。コンパイラーはそれらの値がどうあるべきかを既に知っているので、変数のためにメモリーを確保する 必要はまったくありません。

于 2012-08-27T15:33:43.047 に答える
0

これが一時的なデバッグのためだけの場合は、デバッガーを呼び出すことができます。ただし、デバッガー自体がプログラムをフリーズさせるため、出力をキャプチャするための仲介者が必要です。たとえば、 を使用systemして出力をファイルにリダイレクトし、後でそのファイルを読み取ることができます。以下の例では、ファイルに次gdbcmds.txtの行が含まれていますinfo locals

char buf[512];
FILE *gdb;
snprintf(buf, sizeof(buf), "gdb -batch -x gdbcmds.txt -p %d > gdbout.txt",
         (int)getpid());
system(buf);
gdb = fopen("gdbout.txt", "r");
while (fgets(buf, sizeof(buf), gdb) != 0) {
    printf("%s", buf);
}
fclose(gdb);
于 2012-08-27T14:39:51.607 に答える