打印某个进程的执行栈

来源:互联网 发布:mac os官方壁纸 编辑:程序博客网 时间:2024/05/21 22:57

现成的方法有pstack或者使用gdb -p,一般用于查找进程堵塞或者CPU占用过高时的堆栈。

 

基本原理是通过ptrace到某个进程获取其寄存器的BP值,依次推导出整个执行栈

 

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/wait.h>

extern int errno;

static inline int attachproccess(int process)
{
 if (-1 == ptrace((enum __ptrace_request)PTRACE_ATTACH, process, NULL, NULL))
     {
         printf("[%s:%d] attach process %d failed : %s /n", __FILE__, __LINE__, process, strerror(errno));
  return -1;
     }

 int status;
 if (-1 == wait(&status))
 {
  printf("[%s:%d] wait process %d failed : %s /n", __FILE__, __LINE__, process, strerror(errno));
  return -1;
 }
 if(WIFEXITED(status))
 {
  printf("[%s:%d] process %d exit", __FILE__, __LINE__, process);
  return -1;
 }

#ifdef _DDEBUG
 printf("[%s:%d] attach process success /n", __FILE__, __LINE__);
#endif

 struct user_regs_struct regs;
 if (-1 == ptrace((enum __ptrace_request)PTRACE_GETREGS, process, NULL, &regs))
 {
  printf("[%s:%d] get process %d registers failed : %s /n", __FILE__, __LINE__, process, strerror(errno));
  return -1;
 }


 printf("EIP: %04x /n", regs.eip);

 int ebp = regs.ebp;
 printf("ReturnAddress: %04x /n", ptrace((enum __ptrace_request)PTRACE_PEEKDATA, process, ebp+4, NULL));

 while (ebp < 0xbfffffff)
 {
  ebp = ptrace((enum __ptrace_request)PTRACE_PEEKDATA, process, ebp, NULL);

  if (0 != ebp)
  {
   printf("ReturnAddress: %04x /n", ptrace((enum __ptrace_request)PTRACE_PEEKDATA, process, ebp+4, NULL));
   continue;
  }
  
  break;
 }


 if (-1 == ptrace((enum __ptrace_request)PTRACE_DETACH, process, NULL, NULL))
     {
         printf("[%s:%d] detach process %d failed : %s /n", __FILE__, __LINE__, process, strerror(errno));
     }

     return 0;
}


int main(int args, char** argv)
{
 int iProcessId;

 if (2 != args)
 {
  goto ParamError;
 }
  
 iProcessId = strtol(argv[1], NULL, 0);
 if (LONG_MAX == iProcessId)
 {
  goto ParamError;
 }
 else if (LONG_MIN == iProcessId)
 {
    goto ParamError;
 }
 else
 {
  attachproccess(iProcessId);
  return 0;
 }

ParamError:

 printf("please input process id with integer!!");
 return -1;
}