自己动手实现arm函数栈帧回溯
自己动手实现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函数代替。
>更多相关文章
- 07-30如何用u盘重装win10系统
- 07-30bios设置u盘启动
- 07-30技嘉主板bios如何设置u盘启动项
- 12-22开源视频平台:MediaCore(MediaDrop)
- 12-22JVMjavacore和heapdump文件生成选项
- 12-22使用飞信机器人发短信需要开放的端口
- 12-22TCP连接的三次握手--一次故障记录
- 12-22磁盘管理之一 逻辑卷管理
首页推荐
佛山市东联科技有限公司一直秉承“一切以用户价值为依归
- 01-11全球最受赞誉公司揭晓:苹果连续九年第一
- 12-09罗伯特·莫里斯:让黑客真正变黑
- 12-09谁闯入了中国网络?揭秘美国绝密黑客小组TA
- 12-09警示:iOS6 惊现“闪退”BUG
- 11-18LG新能源宣布与Bear Robotics达成合作,成为
- 11-18机构:三季度全球个人智能音频设备市场强势
- 11-18闲鱼:注册用户过6亿 AI技术已应用于闲置交
- 11-18美柚、宝宝树回应“涉黄短信骚扰”:未发现
- 11-01京东七鲜与前置仓完成融合
相关文章
24小时热门资讯
24小时回复排行
热门推荐
最新资讯
操作系统
黑客防御