不用execinfo库情况下,帮助我编写嵌入式 arm linux堆栈打印代码
时间: 2023-08-31 07:36:36 浏览: 138
嵌入式系统/ARM技术中的Linux下动态共享库加载时的搜索路径详解
### 回答1:
以下是一份可以在嵌入式 ARM Linux 系统中用于打印堆栈的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <ucontext.h>
/* 打印堆栈的最大深度 */
#define STACK_DEPTH 20
/* 信号处理函数,用于获取当前上下文并打印堆栈信息 */
void signal_handler(int signo, siginfo_t *info, void *context)
{
ucontext_t *ucontext = (ucontext_t *)context;
void *stack_ptrs[STACK_DEPTH];
int stack_depth = 0;
printf("Received signal %d, backtrace:\n", signo);
while (stack_depth < STACK_DEPTH && ucontext->uc_mcontext.sp != 0) {
stack_ptrs[stack_depth++] = (void *)ucontext->uc_mcontext.sp;
ucontext = (ucontext_t *)ucontext->uc_link;
}
for (int i = 0; i < stack_depth; i++) {
printf(" [%d] %p\n", i, stack_ptrs[i]);
}
exit(1);
}
/* 注册信号处理函数 */
void register_signal_handler()
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signal_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
int main()
{
/* 注册信号处理函数 */
register_signal_handler();
/* 以下是测试代码,用于触发段错误 */
int *p = NULL;
*p = 1;
return 0;
}
```
这段代码使用了信号处理机制,在程序运行时遇到段错误、非法指令、浮点数异常或总线错误等异常信号时,会调用 `signal_handler` 函数打印堆栈信息,并退出程序。在 `signal_handler` 函数中,通过获取当前上下文的方式,将堆栈上的指针保存在数组 `stack_ptrs` 中,然后打印出来。堆栈深度由 `STACK_DEPTH` 宏定义控制,可以根据实际情况进行调整。最后,在 `main` 函数中,我们调用 `register_signal_handler` 函数将信号处理函数注册到信号处理器中。
### 回答2:
在嵌入式 ARM Linux 中,如果没有使用 execinfo 库,我们可以采用以下方法编写堆栈打印代码:
1. 引入头文件:在代码中引入 `<signal.h>` 和 `<unistd.h>` 头文件。
2. 定义信号处理函数:使用 `sigaction` 函数注册一个信号处理函数,例如 `sigsegv_handler`,用于捕获程序的崩溃信号。
```c
void sigsegv_handler(int signo) {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
// 获取函数调用堆栈
trace_size = backtrace(trace, 16);
// 将函数调用堆栈转化为字符串
messages = backtrace_symbols(trace, trace_size);
// 打印堆栈信息
for (i = 0; i < trace_size; ++i) {
printf("%s\n", messages[i]);
}
// 释放堆栈信息内存
free(messages);
// 重新发送信号,触发默认的退出处理?
signal(signo, SIG_DFL);
raise(signo);
}
```
3. 注册信号处理函数:在 `main` 函数中使用 `sigaction` 函数注册 `SIGSEGV` 信号的处理函数。
```c
int main() {
struct sigaction sa;
// 设置信号处理函数
sa.sa_handler = sigsegv_handler;
sigemptyset(&sa.sa_mask);
// 使用 SA_RESETHAND 可以在信号处理函数中重新注册信号
// 使用 SA_NODEFER 可以不阻塞该信号,继续同时处理其他信号
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
// 注册 SIGSEGV 信号的处理函数
sigaction(SIGSEGV, &sa, NULL);
// 其他代码...
return 0;
}
```
通过以上方法,我们可以在嵌入式 ARM Linux 系统中实现堆栈打印功能。当程序出现崩溃时,信号处理函数将会被调用,并在控制台输出堆栈信息。这样可以帮助我们定位程序的崩溃原因,进行故障排查和修复。
阅读全文