自己动手实现arm函数栈帧回溯

浏览:
字体:
发布时间:2013-12-13 14:31:30
来源:

自己动手实现arm函数栈帧回溯

内核版本:2.6.14

glibc版本:2.3.6

CPU平台:arm

glic中其实有这些函数,当时用的uclib版本较低,没有这些函数,但又需要,只能自己实现了(较高的版本应该有这些函数,换版本很麻烦),而且可以加深自己对这方面的理解.原理性的东西就不深入讲解了,直接上例子!

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <assert.h>#include <ucontext.h>void A(int a);void B(int b);void C(int c);void DebugBacktrace(unsigned int sn , siginfo_t  *si , void *ptr);typedef struct{	const char *dli_fname;	/* File name of defining object.  */	void *dli_fbase;		/* Load address of that object.  */	const char *dli_sname;	/* Name of nearest symbol.比如函数名*/	void *dli_saddr;		/* Exact value of nearest symbol.比如函数的起始地址*/} Dl_info;struct ucontext_ce123 {	unsigned long	  uc_flags;	struct ucontext  *uc_link;	stack_t		  uc_stack;	struct sigcontext uc_mcontext;	sigset_t	  uc_sigmask;	/* mask last for extensibility */}ucontext_ce123_;struct sigframe_ce123 {      struct sigcontext sc;//保存一组寄存器上下文      unsigned long extramask[1];      unsigned long retcode;//保存返回地址      //struct aux_sigframe aux __attribute__((aligned(8)));  }sigframe_ce123; int backtrace_ce123 (void **array, int size);char ** backtrace_symbols_ce123 (void *const *array, int size);int backtrace_ce123 (void **array, int size){	if (size <= 0)		return 0;	int *fp = 0, *next_fp = 0;	int cnt = 0;	int ret = 0;	__asm__(		"mov %0, fp/n" 		: "=r"(fp)	);	array[cnt++] = (void *)(*(fp-1));	next_fp = (int *)(*(fp-3));	while((cnt <= size) && (next_fp != 0))	{		array[cnt++] = (void *)*(next_fp - 1);		next_fp = (int *)(*(next_fp-3));	}	ret = ((cnt <= size)?cnt:size);	printf("Backstrace (%d deep)/n", ret);	return ret;}char ** backtrace_symbols_ce123 (void *const *array, int size){# define WORD_WIDTH 8	Dl_info info[size];	int status[size];	int cnt;	size_t total = 0;	char **result;	/* Fill in the information we can get from `dladdr'.  */	for (cnt = 0; cnt < size; ++cnt)	{		status[cnt] = _dl_addr (array[cnt], &info[cnt]);		if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '/0')		/* We have some info, compute the length of the string which will be		"<file-name>(<sym-name>) [+offset].  */		total += (strlen (info[cnt].dli_fname ?: "")			+ (info[cnt].dli_sname ? strlen (info[cnt].dli_sname) + 3 + WORD_WIDTH + 3 : 1)			+ WORD_WIDTH + 5);		else			total += 5 + WORD_WIDTH;	}	/* Allocate memory for the result.  */	result = (char **) malloc (size * sizeof (char *) + total);	if (result != NULL)	{		char *last = (char *) (result + size);		for (cnt = 0; cnt < size; ++cnt)		{			result[cnt] = last;			if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '/0')			{				char buf[20];				if (array[cnt] >= (void *) info[cnt].dli_saddr)					sprintf (buf, "+%#lx", /						(unsigned long)(array[cnt] - info[cnt].dli_saddr));				else					sprintf (buf, "-%#lx", /						(unsigned long)(info[cnt].dli_saddr - array[cnt]));				last += 1 + sprintf (last, "%s%s%s%s%s[%p]",					info[cnt].dli_fname ?: "",					info[cnt].dli_sname ? "(" : "",					info[cnt].dli_sname ?: "",					info[cnt].dli_sname ? buf : "",					info[cnt].dli_sname ? ") " : " ",					array[cnt]);			}			else				last += 1 + sprintf (last, "[%p]", array[cnt]);		}		assert (last <= (char *) result + size * sizeof (char *) + total);	}	return result;}void A(int a){	printf("%d: A call B/n", a);	B(2);}void B(int b){	printf("%d: B call C/n", b);	C(3);       /* 这个函数调用将导致段错误*/}void C(int c){	char *p = (char *)c;	*p = 'A';   /* 如果参数c不是一个可用的地址值,则这条语句导致段错误 */	printf("%d: function C/n", c);}/* SIGSEGV信号的处理函数,回溯栈,打印函数的调用关系*/void DebugBacktrace(unsigned int sn , siginfo_t  *si , void *ptr){	/*int *ip = 0;	__asm__(		"mov %0, ip/n" 		: "=r"(ip)	);	printf("sp = 0x%x/n", ip);	struct sigframe_ce123 * sigframe = (struct sigframe_ce123 * )ip;*/	if(NULL != ptr)	{		printf("/n/nunhandled page fault (%d) at: 0x%08x/n", si->si_signo,si->si_addr);		struct ucontext_ce123 *ucontext = (struct ucontext_ce123 *)ptr;		int pc = ucontext->uc_mcontext.arm_pc;				void *pc_array[1]; 		pc_array[0] = pc;		char **pc_name = backtrace_symbols_ce123(pc_array, 1);		printf("%d: %s/n", 0, *pc_name);#define SIZE 100		void *array[SIZE];		int size, i;		char **strings;		size = backtrace_ce123(array, SIZE);		strings = backtrace_symbols_ce123(array, size);			for(i=0;i<size;i++)			printf("%d: %s/n", i+1, strings[i]);		free(strings);	}	else		printf("error!/n");	exit(-1);}int main(int argc, char **argv){   	char a;	struct sigaction s;	s.sa_flags = SA_SIGINFO;	s.sa_sigaction = (void *)DebugBacktrace;	sigaction (SIGSEGV,&s,NULL);	A(1);	C(&a);    	return 0;}

代码的下载地址:http://download.csdn.net/detail/ce123/5063160

编译命令:arm-linux-gcc -rdynamic -o segfault segfault.c

_dl_addr链接不通过时,使用-ldl。如果没有该函数,可用dladdr函数代替。

>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2024 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();