嵌入式系统使用堆栈c语言,嵌入式系统C编程之堆栈回溯【转】

前言

75a20baaab3ab7482f49e602c2ecd750.png

backtrace(void **buffer, int size);

backtrace_symbols(void *const *buffer, int size);

backtrace_symbols_fd(void *const *buffer, int size, int fd);

1 #include 2 #include 3 #include 4 #include 5 6 static void StackTrace(void){ 7 void *pvTraceBuf[10]; 8 int dwTraceSize = backtrace(pvTraceBuf, 10); 9 backtrace_symbols_fd(pvTraceBuf, dwTraceSize, STDOUT_FILENO); 10 } 11 12 void FuncC(void){ StackTrace(); } 13 static void FuncB(void){ FuncC(); } 14 void FuncA(void){ FuncB(); } 15 int main(void){ 16 FuncA(); 17 return 0; 18 }

1 [wangxiaoyuan_@localhost test1]$ gcc -Wall -rdynamic -o StackTrace StackTrace.c 2 [wangxiaoyuan_@localhost test1]$ ./StackTrace 3 ./StackTrace[0x80485f9] 4 ./StackTrace(FuncC+0xb)[0x8048623] 5 ./StackTrace[0x8048630] 6 ./StackTrace(FuncA+0xb)[0x804863d] 7 ./StackTrace(main+0x16)[0x8048655] 8 /lib/libc.so.6(__libc_start_main+0xdc)[0x552e9c] 9 ./StackTrace[0x8048521]

#include

dladdr(void *addr, Dl_info *info);

1 typedef struct{ 2 const char *dli_fname; /* Filename of defining object */ 3 void *dli_fbase; /* Load address of that object */ 4 const char *dli_sname; /* Name of nearest lower symbol */ 5 void *dli_saddr; /* Exact value of nearest symbol */ 6 }Dl_info;

#include

sigaction( int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);

handler(int signo, siginfo_t *info, void *context);

1 extern void FuncTraced1(void); 2 #define FuncTraced() do{ \ 3 printf("[%s]Call FuncTraced!\n", __FILE__, __LINE__); \ 4 FuncTraced1(); \ 5 }while(0)

2.1 数据定义

1 #ifndef __i386 2 #warning "Possibly Non-x86 Platform!" 3 #endif 4 5 #if defined(REG_RIP) 6 #define REG_IP REG_RIP //指令指针(保存返回地址) 7 #define REG_BP REG_RBP //帧基指针 8 #define REG_FMT "%016lx" 9 #elif defined(REG_EIP) 10 #define REG_IP REG_EIP 11 #define REG_BP REG_EBP 12 #define REG_FMT "%08x" 13 #else 14 #warning "Neither REG_RIP nor REG_EIP is defined!" 15 #define REG_FMT "%08x" 16 #endif 17 18 #define BTR_FILE_LEN 512 //保存堆栈回溯结果的文件路径最大长度 19 #ifndef BTR_FILE //保存堆栈回溯结果的基本文件名 20 #define BTR_FILE "btr" 21 #endif 22 #ifndef BTR_FILE_PATH //保存堆栈回溯结果的文件路径(默认为当前路径) 23 #define BTR_FILE_PATH "." //"..//var//tmp" 24 #endif 25 26 #ifndef MAX_BTR_LEVEL //函数回溯的最大层数 27 #define MAX_BTR_LEVEL 20 28 #endif 29 30 //用户调用SHOW_STACK宏可触发堆栈回溯 31 #ifndef BTR_SIG //触发堆栈回溯的用户信号 32 #define BTR_SIG SIGUSR1 33 #endif 34 #define SHOW_STACK() do{raise(BTR_SIG);}while(0)

1 static FILE *gpStraceFd = NULL; //输出文件描述符(置为stderr时输出到终端,否则将输出存入文件) 2 typedef VOID (*SignalHandleFunc)(INT32S dwSignal); 3 static SignalHandleFunc gfpCustSigHandler = NULL; //用户自定义的信号处理函数指针

2.2 函数接口

1 /****************************************************************************** 2 * 函数名称: SpecifyStraceOutput 3 * 功能说明: 指定回溯结果输出方式 4 ******************************************************************************/ 5 static FILE *SpecifyStraceOutput(VOID) 6 { 7 #ifdef __BTR_TO_FILE 8 time_t tTime; 9 CHAR szFileName[BTR_FILE_LEN]; 10 szFileName[0] = '\0'; 11 if(time(&tTime) != -1) 12 { 13 struct tm *ptTime = localtime(&tTime); 14 snprintf(szFileName, sizeof(szFileName), "%s/[%d]%d%02d%02d_%02d%02d%02d.%s", 15 BTR_FILE_PATH, getpid(), (ptTime->tm_year+1900), (ptTime->tm_mon+1), 16 ptTime->tm_mday, ptTime->tm_hour, ptTime->tm_min, ptTime->tm_sec, BTR_FILE); 17 } 18 else 19 { 20 snprintf(szFileName, sizeof(szFileName), "%s/%s", BTR_FILE_PATH, BTR_FILE); 21 } 22 23 FILE *pFile = fopen(szFileName, "w+"); 24 if(NULL == pFile) 25 { 26 fprintf(stderr, "Cannot open File '%s'(%s)\n!", szFileName, strerror(errno)); 27 return -1; 28 } 29 return pFile; 30 #else 31 return stderr; 32 #endif 33 }

1 /****************************************************************************** 2 * 函数名称: SigHandler 3 * 功能说明: 信号处理函数 4 * 输入参数: INT32S dwSigNo :信号名 5 siginfo_t *tSigInfo :信号产生原因等信息 6 VOID *pvContext :信号传递时的进程上下文 7 * 输出参数: NA 8 * 返 回 值: VOID 9 ******************************************************************************/ 10 static VOID SigHandler(INT32S dwSigNo, siginfo_t *tSigInfo, VOID *pvContext) 11 { 12 fprintf(gpStraceFd, "\nStart of Stack Trace>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); 13 14 fprintf(gpStraceFd, "Process (%d) receive signal %d\n", getpid(), dwSigNo); 15 16 fprintf(gpStraceFd, ":\n" ); 17 fprintf(gpStraceFd, "\tSigNo: %-2d(%s)\n", tSigInfo->si_signo, OmciStrSigNo(tSigInfo->si_signo)); //strsignal(dwSigNo) 18 fprintf(gpStraceFd, "\tErrNo: %-2d(%s)\n", tSigInfo->si_errno, strerror(tSigInfo->si_errno)); 19 fprintf(gpStraceFd, "\tSigCode: %-2d\n", tSigInfo->si_code); 20 fprintf(gpStraceFd, "\tRaised at: %p[Unreliable]\n", tSigInfo->si_addr); 21 22 fprintf(gpStraceFd, ": \n\t" ); 23 INT32U dwIdx = 0; 24 ucontext_t *ptContext = (ucontext_t*)pvContext; 25 for(dwIdx = 0; dwIdx < NGREG; dwIdx++) 26 { 27 fprintf(gpStraceFd, REG_FMT" ", ptContext->uc_mcontext.gregs[dwIdx]); 28 if(0 == ((dwIdx+1)%4)) //每行输出4个寄存器值 29 fprintf(gpStraceFd, "\n\t"); 30 } 31 fprintf(gpStraceFd, "\n"); 32 33 #if defined(REG_RIP) || defined(REG_EIP) 34 dwIdx = 0; 35 VOID *pvIp = (VOID*)ptContext->uc_mcontext.gregs[REG_IP]; 36 VOID **ppvBp = (VOID**)ptContext->uc_mcontext.gregs[REG_BP]; 37 fprintf(gpStraceFd, ":\n"); 38 while(ppvBp != &pvIp) 39 { 40 Dl_info tDlInfo; 41 if(!dladdr(pvIp, &tDlInfo)) 42 break; 43 fprintf(gpStraceFd, "\t[%2d] (%s) [0x%08x] (%s)+0x%02x\n", ++dwIdx, 44 tDlInfo.dli_fname, (INT32U)pvIp, 45 (tDlInfo.dli_sname != NULL) ? tDlInfo.dli_sname : "", 46 ((INT32U)pvIp - (INT32U)tDlInfo.dli_saddr)); 47 48 if((NULL == ppvBp) || (tDlInfo.dli_sname && !strcmp(tDlInfo.dli_sname, "main"))) 49 break; 50 pvIp = ppvBp[1]; //帧基指针向高地址偏移1个单位(4字节)为返回地址 51 ppvBp = (VOID**)(*ppvBp); //帧基指针所指向的空间存放主调函数栈帧的帧基指针 52 } 53 #else 54 fprintf(gpStraceFd, ":\n"); 55 56 VOID *pvTraceBuf[MAX_BTR_LEVEL]; 57 INT32U dwTraceSize = backtrace(pvTraceBuf, MAX_BTR_LEVEL); 58 CHAR **ppTraceInfos = backtrace_symbols(pvTraceBuf, dwTraceSize); 59 if(!ppTraceInfos || !(*ppTraceInfos)) 60 exit(EXIT_FAILURE); 61 62 for(dwIdx = 0; dwIdx < dwTraceSize; dwIdx++) 63 fprintf(gpStraceFd, "\t%s\n", ppTraceInfos[dwIdx]); 64 65 free(ppTraceInfos); 66 #endif 67 68 fprintf(gpStraceFd, "End of Stack Trace<<<<<<<<<<<<<<<<<<<<<<<<<<<

1 VOID **GetEbp(INT32U dwDummy) 2 { 3 VOID **ebp = (VOID **)&dwDummy - 2; 4 return (*ebp); 5 }

1 VOID **ppvBp = getEbp(dwIdx); //或 2 VOID **ppvBp = (VOID **)&dwSigNo - 2;

1 #define NAME_MAP_ENTRY(name) {name, #name} 2 static T_NAME_PARSER gSigNameMap[] = { 3 NAME_MAP_ENTRY(SIGHUP), 4 NAME_MAP_ENTRY(SIGINT), 5 NAME_MAP_ENTRY(SIGQUIT), 6 NAME_MAP_ENTRY(SIGILL), 7 NAME_MAP_ENTRY(SIGTRAP), 8 NAME_MAP_ENTRY(SIGABRT), //SIGABRT(ANSI) = SIGIOT(4.2 BSD) 9 NAME_MAP_ENTRY(SIGBUS), 10 NAME_MAP_ENTRY(SIGFPE), 11 NAME_MAP_ENTRY(SIGKILL), 12 NAME_MAP_ENTRY(SIGUSR1), 13 NAME_MAP_ENTRY(SIGSEGV), 14 NAME_MAP_ENTRY(SIGUSR2), 15 NAME_MAP_ENTRY(SIGPIPE), 16 NAME_MAP_ENTRY(SIGALRM), 17 NAME_MAP_ENTRY(SIGTERM), 18 NAME_MAP_ENTRY(SIGSTKFLT), 19 NAME_MAP_ENTRY(SIGCHLD), //SIGCHLD(POSIX) = SIGCLD(System V) 20 NAME_MAP_ENTRY(SIGCONT), 21 NAME_MAP_ENTRY(SIGSTOP), 22 NAME_MAP_ENTRY(SIGTSTP), 23 NAME_MAP_ENTRY(SIGTTIN), 24 NAME_MAP_ENTRY(SIGTTOU), 25 NAME_MAP_ENTRY(SIGURG), 26 NAME_MAP_ENTRY(SIGXCPU), 27 NAME_MAP_ENTRY(SIGXFSZ), 28 NAME_MAP_ENTRY(SIGVTALRM), 29 NAME_MAP_ENTRY(SIGPROF), 30 NAME_MAP_ENTRY(SIGWINCH), 31 NAME_MAP_ENTRY(SIGIO), //SIGIO(4.2 BSD) = SIGPOLL(System V) 32 NAME_MAP_ENTRY(SIGPWR), 33 NAME_MAP_ENTRY(SIGSYS) 34 }; 35 //信号值字符串化 36 CHAR *OmciStrSigNo(INT32S dwSigNo) 37 { 38 return NameParser(gSigNameMap, ARRAY_SIZE(gSigNameMap), dwSigNo, "UnkownSigNo"); 39 }

《C语言表驱动法编程实践》一文,读者也可自行实现解析函数。

1 #define SIG_NAME(eSigNo) \ 2 ((eSigNo) == SIGHUP ? "SIGHUP" : \ 3 ((eSigNo) == SIGINT ? "SIGINT" : \ 4 ((eSigNo) == SIGQUIT ? "SIGQUIT" : \ 5 ((eSigNo) == SIGILL ? "SIGILL" : \ 6 ((eSigNo) == SIGTRAP ? "SIGTRAP" : \ 7 ((eSigNo) == SIGABRT ? "SIGABRT(ANSI)/SIGIOT(4.2 BSD)" : \ 8 ((eSigNo) == SIGBUS ? "SIGBUS" : \ 9 ((eSigNo) == SIGFPE ? "SIGFPE" : \ 10 ((eSigNo) == SIGKILL ? "SIGKILL" : \ 11 ((eSigNo) == SIGUSR1 ? "SIGUSR1" : \ 12 ((eSigNo) == SIGSEGV ? "SIGSEGV" : \ 13 ((eSigNo) == SIGUSR2 ? "SIGUSR2" : \ 14 ((eSigNo) == SIGPIPE ? "SIGPIPE" : \ 15 ((eSigNo) == SIGALRM ? "SIGALRM" : \ 16 ((eSigNo) == SIGTERM ? "SIGTERM" : \ 17 ((eSigNo) == SIGSTKFLT ? "SIGSTKFLT" : \ 18 ((eSigNo) == SIGCHLD ? "SIGCHLD(POSIX)/SIGCLD(System V)" : \ 19 ((eSigNo) == SIGCONT ? "SIGCONT" : \ 20 ((eSigNo) == SIGSTOP ? "SIGSTOP" : \ 21 ((eSigNo) == SIGTSTP ? "SIGTSTP" : \ 22 ((eSigNo) == SIGTTIN ? "SIGTTIN" : \ 23 ((eSigNo) == SIGTTOU ? "SIGTTOU" : \ 24 ((eSigNo) == SIGURG ? "SIGURG" : \ 25 ((eSigNo) == SIGXCPU ? "SIGXCPU" : \ 26 ((eSigNo) == SIGXFSZ ? "SIGXFSZ" : \ 27 ((eSigNo) == SIGVTALRM ? "SIGVTALRM" : \ 28 ((eSigNo) == SIGPROF ? "SIGPROF" : \ 29 ((eSigNo) == SIGWINCH ? "SIGWINCH" : \ 30 ((eSigNo) == SIGIO ? "SIGIO(4.2 BSD)/SIGPOLL(System V)" : \ 31 ((eSigNo) == SIGPWR ? "SIGPWR" : \ 32 ((eSigNo) == SIGSYS ? "SIGSYS" : \ 33 "Unknown" )))))))))))))))))))))))))))))))

1 /****************************************************************************** 2 * 函数名称: InstallFaultTrap 3 * 功能说明: 安装出错时的信号捕获函数 4 * 输入参数: SignalHandleFunc fpCustSigHandler :用户自定义的信号处理函数 5 * 输出参数: NA 6 * 返 回 值: INT32S 7 ******************************************************************************/ 8 static INT32S InstallFaultTrap(SignalHandleFunc fpCustSigHandler) 9 { 10 gfpCustSigHandler = fpCustSigHandler; 11 12 struct sigaction tSigAction; 13 memset(&tSigAction, 0, sizeof(tSigAction)); 14 tSigAction.sa_sigaction = SigHandler; 15 sigemptyset(&tSigAction.sa_mask); 16 tSigAction.sa_flags = SA_SIGINFO; 17 18 //检查可能导致进程终止的信号 19 INT32S dwRet = 0; 20 if((dwRet = sigaction(SIGSEGV, &tSigAction, NULL)) < 0) 21 fprintf(stderr, "[%s]Sigaction failed for SIGSEGV(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 22 23 if((dwRet = sigaction(SIGQUIT, &tSigAction, NULL)) < 0) 24 fprintf(stderr, "[%s]Sigaction failed for SIGQUIT(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 25 26 if((dwRet = sigaction(SIGILL, &tSigAction, NULL)) < 0) 27 fprintf(stderr, "[%s]Sigaction failed for SIGILL(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 28 29 if((dwRet = sigaction(SIGTRAP, &tSigAction, NULL)) < 0) 30 fprintf(stderr, "[%s]Sigaction failed for SIGTRAP(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 31 32 if((dwRet = sigaction(SIGABRT, &tSigAction, NULL)) < 0) 33 fprintf(stderr, "[%s]Sigaction failed for SIGABRT(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 34 35 if((dwRet = sigaction(SIGFPE, &tSigAction, NULL)) < 0) 36 fprintf(stderr, "[%s]Sigaction failed for SIGFPE(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 37 38 if((dwRet = sigaction(SIGBUS, &tSigAction, NULL)) < 0) 39 fprintf(stderr, "[%s]Sigaction failed for SIGBUS(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 40 41 if((dwRet = sigaction(SIGXFSZ, &tSigAction, NULL)) < 0) 42 fprintf(stderr, "[%s]Sigaction failed for SIGXFSZ(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 43 44 if((dwRet = sigaction(SIGXCPU, &tSigAction, NULL)) < 0) 45 fprintf(stderr, "[%s]Sigaction failed for SIGXCPU(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 46 47 if((dwRet = sigaction(SIGSYS, &tSigAction, NULL)) < 0) 48 fprintf(stderr, "[%s]Sigaction failed for SIGSYS(%d, %s)!\n", FUNC_NAME, errno, strerror(errno)); 49 50 if((dwRet = sigaction(BTR_SIG, &tSigAction, NULL)) < 0) 51 fprintf(stderr, "[%s]Sigaction failed for %s(%d, %s)!\n", FUNC_NAME, 52 OmciStrSigNo(BTR_SIG), errno, strerror(errno)); 53 54 return dwRet; 55 }

1 /****************************************************************************** 2 * 函数名称: AutoInitBacktrace 3 * 功能说明: 自动初始化堆栈回溯功能 4 * 输入参数: VOID 5 * 输出参数: NA 6 * 返 回 值: INT32S 7 * 注意事项: 该函数在main()函数之前执行,无需用户显式调用 8 ******************************************************************************/ 9 #ifdef __BTR_AUTO_INIT 10 static VOID __attribute((constructor)) AutoInitBacktrace(VOID) 11 { 12 gpStraceFd = SpecifyStraceOutput(); 13 InstallFaultTrap(NULL); 14 } 15 #endif

1 /****************************************************************************** 2 * 函数名称: MannInitBacktrace 3 * 功能说明: 手工初始化堆栈回溯功能 4 * 输入参数: SignalHandleFunc fpCustSigHandler :用户自定义的信号处理函数 5 * 输出参数: NA 6 * 返 回 值: VOID 7 * 注意事项: fpCustSigHandler符合signal()函数原型,用户可借此额外地输出 8 特定的自定义信息 9 ******************************************************************************/ 10 VOID MannInitBacktrace(SignalHandleFunc fpCustSigHandler) 11 { 12 gpStraceFd = SpecifyStraceOutput(); 13 InstallFaultTrap(fpCustSigHandler); 14 }

1 VOID Func1(VOID){ 2 SHOW_STACK(); 3 return; 4 } 5 VOID Func2(VOID){ 6 Func1(); 7 printf("%s\n", 0x123); 8 return; 9 } 10 VOID BtrTest(VOID){ 11 Func2(); 12 printf("%d\n", 5/0); 13 return; 14 }

1 Start of Stack Trace>>>>>>>>>>>>>>>>>>>>>>>>>> 2 Process (18390) receive signal 10 3 : 4 SigNo: 10(SIGUSR1) 5 ErrNo: 0 (Success) 6 SigCode: -6 7 Raised at: 0x47d6[Unreliable] 8 : 9 00000033 00000000 0000007b 0000007b 10 006c8ff4 00535ca0 bfb62228 bfb6221c 11 000047d6 0000000a 000047d6 00000000 12 00000000 00000000 00480402 00000073 13 00000202 bfb6221c 0000007b 14 : 15 ./OmciExec [0x804a770] 16 [0x480440] 17 ./OmciExec(Func1+0x12) [0x804ad4e] 18 ./OmciExec(Func2+0xb) [0x804ad5b] 19 ./OmciExec(BtrTest+0xb) [0x804ad7c] 20 ./OmciExec(main+0x16) [0x804eec0] 21 /lib/libc.so.6(__libc_start_main+0xdc) [0x552e9c] 22 ./OmciExec [0x8049f31] 23 End of Stack Trace<<<<<<<<<<<<<<<<<<<<<<<<<<<<

1 Start of Stack Trace>>>>>>>>>>>>>>>>>>>>>>>>>> 2 Process (18429) receive signal 11 3 : 4 SigNo: 11(SIGSEGV) 5 ErrNo: 0 (Success) 6 SigCode: 1 7 Raised at: 0x123[Unreliable] 8 : 9 00000033 00000000 0000007b 0000007b 10 00000123 bf9a5114 bf9a50ec bf9a4acc 11 0067eff4 00579999 00000003 00000123 12 0000000e 00000004 005ad1ab 00000073 13 00010206 bf9a4acc 0000007b 14 : 15 ./OmciExec [0x804a740] 16 [0xedc440] 17 /lib/libc.so.6(_IO_printf+0x33) [0x582e83] 18 ./OmciExec(Func2+0x1f) [0x804ad30] 19 ./OmciExec(BtrTest+0xb) [0x804ad3d] 20 ./OmciExec(main+0x16) [0x804ee80] 21 /lib/libc.so.6(__libc_start_main+0xdc) [0x552e9c] 22 ./OmciExec [0x8049f01] 23 End of Stack Trace<<<<<<<<<<<<<<<<<<<<<<<<<<<<

1 CFLAGS += -D__BTR_AUTO_INIT -rdynamic -ldl 2 CFLAGS += -D_GNU_SOURCE 3 CFLAGS += -fno-omit-frame-pointer

1 : 2 00000033 00000000 0000007b 0000007b 3 00000123 bfbe8694 bfbe866c bfbe804c 4 0067eff4 00579999 00000003 00000123 5 0000000e 00000004 005ad1ab 00000073 6 00010206 bfbe804c 0000007b 7 : 8 [ 1] (/lib/libc.so.6) [0x005ad1ab] (strlen)+0x0b 9 [ 2] (/lib/libc.so.6) [0x00582e83] (_IO_printf)+0x33 10 [ 3] (./OmciExec) [0x0804adfb] (Func2)+0x1f 11 [ 4] (./OmciExec) [0x0804ae08] (BtrTest)+0x0b 12 [ 5] (./OmciExec) [0x0804f154] (main)+0x2a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值