打印对应的代码位置
时间: 2023-07-10 16:11:40 浏览: 49
如果需要打印堆栈信息中对应的代码位置,可以使用`addr2line`命令来实现。`addr2line`命令可以将一个地址转换为对应的源代码文件名和行号。
```c++
#include <execinfo.h>
#include <cxxabi.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
void printStackTrace() {
void* trace[256];
int traceSize = backtrace(trace, 256);
char** messages = backtrace_symbols(trace, traceSize);
int pid = getpid();
char procSelfExe[256];
sprintf(procSelfExe, "/proc/%d/exe", pid);
char exePath[256];
int exePathSize = readlink(procSelfExe, exePath, sizeof(exePath));
exePath[exePathSize] = '\0';
int addr2lineIn = open("/tmp/addr2lineIn", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
int addr2lineOut = open("/tmp/addr2lineOut", O_RDONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
for (int i = 1; i < traceSize; ++i) {
Dl_info info;
dladdr(trace[i], &info);
char* demangled = nullptr;
int status = 0;
demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
printf("[bt]: (%d) %s (%s + 0x%lx)\n", i, messages[i], (status==0 ? demangled : info.dli_sname), (char*)trace[i] - (char*)info.dli_saddr);
uint64_t addr = (uint64_t)trace[i];
write(addr2lineIn, &addr, sizeof(addr));
}
pid_t child = fork();
if (child == 0) {
dup2(addr2lineIn, STDIN_FILENO);
dup2(addr2lineOut, STDOUT_FILENO);
execlp("addr2line", "addr2line", "-e", exePath, "-f", "-i", nullptr);
}
waitpid(child, nullptr, 0);
lseek(addr2lineOut, 0, SEEK_SET);
char buf[256];
for (int i = 1; i < traceSize; ++i) {
uint64_t addr;
read(addr2lineOut, &addr, sizeof(addr));
if (addr == 0) {
printf("[bt]: ??:0\n");
continue;
}
fgets(buf, sizeof(buf), addr2lineOut);
char* p = strchr(buf, '\n');
if (p != nullptr) {
*p = '\0';
}
printf("[bt]: %s\n", buf);
}
close(addr2lineIn);
close(addr2lineOut);
free(messages);
}
```
上述代码中,我们使用`/proc/self/exe`获取当前进程的可执行文件路径,并通过`addr2line`命令将地址转换为代码位置。具体实现过程为:
1. 将地址写入`/tmp/addr2lineIn`文件,`addr2line`命令从该文件中读取地址。
2. 使用`fork()`函数创建子进程,重定向子进程的标准输入和标准输出到`/tmp/addr2lineIn`和`/tmp/addr2lineOut`文件,使`addr2line`命令可以从标准输入中读取地址,并将结果输出到标准输出中。
3. 在子进程中使用`execlp()`函数调用`addr2line`命令,并传入可执行文件路径、`-f`和`-i`选项,表示输出完整的函数名和文件名、输出源码文件名和行号。
4. 等待子进程执行完毕,再从`/tmp/addr2lineOut`文件中读取`addr2line`命令的输出结果。