2011-08-31 83 views
3

我想獲得像gdb那樣的backtrace樣輸出。但我想直接通過ptrace()來做到這一點。我的平臺是Linux,x86;和更高版本的x86_64。如何僅使用ptrace(linux,x86/x86_64)獲得「backtrace」(如gdb)

現在我只想從堆棧中讀取返回地址,而不用轉換爲符號名稱。

因此,對於測試程序,通過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 

我如何才能找到當前停止測試過程的返回地址與ptrace?會有幀循環?我應該什麼時候停止這種循環?

PS:是的,這也非常喜歡backtrace(3) libc function的想法,但我想通過ptrace在外部完成此操作。

回答

5

osgx發佈的例子只能用於使用幀指針的代碼。由GCC生成的具有優化的代碼不適用於x86_64。內核vdso代碼x86至少在某些處理器上不使用幀指針。 GCC 4.6(有優化)也不使用x86模式下的幀指針。

以上所有內容相結合使「通過幀指針爬棧」非常不可靠。

您可以使用libunwind(它同時支持local(進程內)和global(通過ptrace進程外停止))。

或者您將不得不重新實施libunwind的很大一部分。

Example通過ptrace使用libunwind獲取回溯。

+0

您能否提供libunwind外部展開文檔的鏈接? – osgx

+0

這個? http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html - 是否有一些使用libunwind-ptrace獲取回溯的示例? – osgx

+0

我添加了文檔鏈接。否:libunwind-ptrace不是你想要的 - 它是libunwind的一部分,它實現了ptrace工具。您可以使用該部分來重新實現更高級別的libunwind,但應該沒有理由這樣做。 –

0

可能是,pstack(1)實用程序的來源將幫助我:(在線git debian)。不幸的是,這是僅適用於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 

32位的同時,快速測試說是不是很可靠,但有時它可以打印的東西。