现成的方法有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, ®s))
{
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;
}