Как получить «backtrace» (например, gdb), используя только ptrace (linux, x86 / x86_64) - PullRequest
4 голосов
/ 31 августа 2011

Я хочу получить backtrace -подобный вывод, как это делает GDB.Но я хочу сделать это через 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.

Ответы [ 2 ]

7 голосов
/ 31 августа 2011

Пример, опубликованный osgx, будет работать только с кодом, использующим указатели фреймов.x86_64 код, созданный GCC с оптимизацией, нет.Код ядра vdso на x86 не использует фреймовые указатели хотя бы на некоторых процессорах.GCC 4.6 (с оптимизацией) также не использует указатели фреймов в режиме x86.

Все вышеперечисленное объединяет, чтобы сделать "обход стека по указателям фреймов" чрезвычайно ненадежным.

Выможно использовать libunwind (которая поддерживает как local (в процессе), так и global (вне процесса через ptrace) для размотки).

Или вы 'Вам придется повторно реализовать очень большую часть libunwind.

Пример получения обратного следа через ptrace с использованием libunwind.

0 голосов
/ 31 августа 2011

Может быть, мне поможет источник утилиты pstack(1): (онлайн git от debian ).К сожалению, это только 32-битный x86

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 

Кроме того, быстрый тест говорит, что это не очень надежно, но иногда он может что-то напечатать.

...