如何获得“回溯” (如 gdb)仅使用 ptrace(linux、x86/x86_64)

发布于 2024-12-02 02:16:53 字数 1053 浏览 0 评论 0原文

我想像 gdb 那样获得类似 backtrace 的输出。但我想直接通过 ptrace() 来完成此操作。我的平台是Linux,x86;以及后来的 x86_64。

现在我只想从堆栈中读取返回地址,而不转换为符号名称。

因此,对于测试程序,由 gcc-4.5-O0 模式编译:

  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

How can I find return fields of current Stoped test process with ptrace?帧之间会有循环吗?我什么时候应该停止这样的循环?

PS:是的,这也很像 backtrace(3) libc function 在idea中,但我想通过ptrace在外部执行此操作。

I want to get a backtrace-like output as gdb does. But I want to do this via ptrace() directly. My platform is Linux, x86; and, later x86_64.

Now I want only to read return addresses from the stack, without conversion into symbol names.

So, for test program, compiled in -O0 mode by 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();
  }

I will start a my program and connect with ptrace to test program at very beginning. Then, I will do PTRACE_CONT and will wait for signal. When test program will do a self-kill; the signal will be delivered to my program. At this moment I want to read return addresses, they will be like (because kill function is active at the moment):

 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

How can I find return addresses of currently stopped test process with ptrace? There will be a loop over frames? When should I stop such loop?

PS: yes, this is also very like backtrace(3) libc function in idea, but I want to do this externally via ptrace.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故笙诉离歌 2024-12-09 02:16:53

osgx 发布的示例仅适用于使用帧指针的代码。 GCC 生成的经过优化的 x86_64 代码则不然。 x86 上的内核 vdso 代码至少在某些处理器上不使用帧指针。 GCC 4.6(经过优化)也不在 x86 模式下使用帧指针。

上述所有因素结合在一起,使得“通过帧指针进行堆栈抓取”极其不可靠。

您可以使用 libunwind (它支持 local< /a> (进程中)和 全局(通过 ptrace 进行进程外)展开)。

或者您必须重新实现libunwind的很大一部分。

示例 使用 libunwind 通过 ptrace 获取回溯。

The example posted by osgx will work only with code that uses frame pointers. x86_64 code produced by GCC with optimizations doesn't. The kernel vdso code on x86 doesn't use frame pointers on at least some processors. GCC 4.6 (with optimization) doesn't use frame pointers in x86 mode either.

All of the above combine to make the "stack crawl via frame pointers" exceedingly unreliable.

You can use libunwind (which supports both local (in-process) and global (out-of-process via ptrace) unwinding).

Or you'll have to re-implement very large portion of libunwind.

Example of getting backtrace via ptrace using libunwind.

滥情稳全场 2024-12-09 02:16:53

可能,pstack(1)实用程序的源代码会帮助我:(来自

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 

另外,快速测试说是不是不太靠谱,不过有时候可以打印 某物。

May be, source of pstack(1) utility will help me: (online git from debian). Unfortunately this is x86 32-bit only

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 

Also, quick test says that is it not very reliable, but sometimes it can print something.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文