4

backtracegdb のように出力を取得したい。ptrace()しかし、私は直接これをやりたいです。私のプラットフォームは Linux、x86 です。そして、それ以降は x86_64 です。

ここで、シンボル名に変換せずに、スタックからリターン アドレスのみを読み取りたいと考えています。

したがって、テストプログラムの場合、次の-O0モードでコンパイルされgcc-4.5ます。

  int g() {
    kill(getpid(),SIGALRM);
  }
  int f() {
    int a;
    int b;
    a = g();
    b = a;
    return a+b;
  }
  int e() {
    int c;
    c = f();
  }
  main() {
    return e();
  }

私は自分のプログラムを開始し、ptrace最初にプログラムをテストするために接続します。次に、PTRACE_CONT を実行し、シグナルを待ちます。テスト プログラムが自己停止を行う場合。信号は私のプログラムに配信されます。この時点でリターン アドレスを読みたいと思いますが、次のようになります (kill機能が現在アクティブであるため)。

 0x00_some_address_in_g
 0x00_some_address_in_f
 0x00_some_address_in_e
 0x00_some_address_in_main
 0x00_some_address_in__libc_start_main

で現在停止しているテスト プロセスのリターン アドレスを見つけるにはどうすればよいptraceですか? フレームにループが発生しますか? そのようなループをいつ停止する必要がありますか?

PS: はい、これも考え方がbacktrace(3)libc 関数に非常に似ていますが、ptrace を介して外部でこれを実行したいと考えています。

4

2 に答える 2

7

osgx によって投稿された例は、フ​​レーム ポインターを使用するコードでのみ機能します。x86_64最適化された GCC によって生成されたコードはそうではありません。カーネルvdsoコードx86は、少なくとも一部のプロセッサでフレーム ポインタを使用しません。x86GCC 4.6 (最適化あり) もモードでフレーム ポインターを使用しません。

上記のすべてが組み合わさって、「フレームポインタを介したスタッククロール」が非常に信頼できなくなります。

使用できます(ローカル(インプロセス) とグローバル(ptrace によるアウトプロセス) のlibunwind両方の巻き戻しをサポートします)。

または、 の非常に大きな部分を再実装する必要がありますlibunwind

ptraceを使用してバックトレースを取得するlibunwind

于 2011-08-31T15:19:47.517 に答える
0

おそらく、ユーティリティのソースが役立ちます: ( debianpstack(1)からのオンライン git )。残念ながら、これは x86 32 ビットのみです。

http://anonscm.debian.org/gitweb/?p=collab-maint/pstack.git;a=blob;f=pstack.c;h=61beb8d10fa490492ab351115f261614d00adb6d;hb=HEAD#l547

 547 static int crawl(int pid)
 548 {
 549   unsigned long pc, fp, nextfp, nargs, i, arg;
 550   int error_occured = 0;
 551 
 552   errno = 0;
 553   fp = -1;
 554 
 555   pc = ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0);
 556   if (pc != -1 || !errno)
 557     fp = ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0);
 558 
 559   if ((pc != -1 && fp != -1) || !errno) {
 560     print_pc(pc);
 561     for ( ; !errno && fp; ) {
 562       nextfp = ptrace(PTRACE_PEEKDATA, pid, fp, 0);
 563       if (nextfp == (unsigned) -1 && errno) break;
 564 
 565       nargs = (nextfp - fp - 8) / 4;
 566       if (nargs > MAXARGS) nargs = MAXARGS;
 567       if (nargs > 0) {
 568         fputs(" (", stdout);
 569         for (i = 1; i <= nargs; i++) {
 570           arg = ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0);
 571           if (arg == (unsigned) -1 && errno) break;
 572           printf("%lx", arg);
 573           if (i < nargs) fputs(", ", stdout);
 574         }
 575         fputc(')', stdout);
 576         nargs = nextfp - fp - 8 - (4 * nargs);
 577         if (!errno && nargs > 0) printf(" + %lx\n", nargs);
 578         else fputc('\n', stdout);
 579       } else fputc('\n', stdout);
 580 
 581       if (errno || !nextfp) break;
 582       pc = ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0);
 583       if (pc == (unsigned) -1 && errno) break;
 584       fp = nextfp;
 585       print_pc(pc);
 586     }
 587     if (fp) error_occured = 1;
 588   } else error_occured = 1;
 589 
 590   if (error_occured) perror("crawl");
 591   else errno = 0;
 592   return errno;
 593 }
 594 

また、簡単なテストでは、信頼性が低いとのことですが、何かを印刷できる場合もあります。

于 2011-08-31T14:26:50.170 に答える