如何在 C++ 中使用回溯获取正确的代码行?
How to get the correct line of code with backtrace in C++?
我把 this code 修改成这样:
std::string Backtrace(int skip = 1)
{
void *callstack[128];
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
char buf[1024];
int nFrames = backtrace(callstack, nMaxFrames);
char **symbols = backtrace_symbols(callstack, nFrames);
string message = "";
for (int i = skip; i < nFrames; i++) {
Dl_info info;
if (dladdr(callstack[i], &info)) {
char *demangled = nullptr;
int status;
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
if(demangled != nullptr)
message += string(demangled) + ": " +
to_string((char *)callstack[i] - (char *)info.dli_saddr) + "\n";
free(demangled);
}
}
free(symbols);
if (nFrames == nMaxFrames)
message += "[truncated]\n";
return message;
}
这应该会打印我当前程序的堆栈跟踪,以确定哪里出了问题,而不必在我的程序每次崩溃时都打开 gdb。
当我 运行 此代码(处于保证触发问题的状态)时,我得到以下堆栈跟踪:
DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, unsigned int, VkDebugUtilsMessengerCallbackDataEXT const*, void*): 146
vk::DispatchLoaderStatic::vkQueueSubmit(VkQueue_T*, unsigned int, VkSubmitInfo const*, VkFence_T*) const: 50
Display::UpdateFrame(): 1088
RenderingPipeline::RenderFrame(vk::Buffer&, vk::Buffer&, Image&, unsigned int): 63
RenderHandler::RenderHandler(Window*, HardwareInterface*, Display*, Memory*): 784
我的目标是尝试打印尽可能多的相关信息。 (文件、函数、行)。现在,我认为指令:
我从原始脚本复制的 (char *)callstack[i] - (char *)info.dli_saddr)
会给我调用代码的行,但是例如定义 Display::UpdateFrame()
的文件没有;甚至没有 1000 行,所以这个数字很简单't 原文件中调用代码的编号
有没有一种方法可以像 GDB 那样通过堆栈跟踪获取此信息?
即如果函数在
的源代码中被调用
File: Display.hpp
Function: Display::UpdateFrame()
Line: 227
我可以在 运行 时使用堆栈跟踪检索该信息吗?
backtrace() returns 相对于某些 ELF 部分的开头以字节为单位的偏移量。为了获得行号和函数名,您需要使用一个库,该库可以读取程序的调试信息,然后找出给定偏移量对应的源文件/行号/函数。
这是一个如何使用 libbfd 执行此操作的示例(由我编写)(假设您使用的是 linux):
https://github.com/CarloWood/libmemleak/blob/master/src/addr2line.c
我把 this code 修改成这样:
std::string Backtrace(int skip = 1)
{
void *callstack[128];
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
char buf[1024];
int nFrames = backtrace(callstack, nMaxFrames);
char **symbols = backtrace_symbols(callstack, nFrames);
string message = "";
for (int i = skip; i < nFrames; i++) {
Dl_info info;
if (dladdr(callstack[i], &info)) {
char *demangled = nullptr;
int status;
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
if(demangled != nullptr)
message += string(demangled) + ": " +
to_string((char *)callstack[i] - (char *)info.dli_saddr) + "\n";
free(demangled);
}
}
free(symbols);
if (nFrames == nMaxFrames)
message += "[truncated]\n";
return message;
}
这应该会打印我当前程序的堆栈跟踪,以确定哪里出了问题,而不必在我的程序每次崩溃时都打开 gdb。
当我 运行 此代码(处于保证触发问题的状态)时,我得到以下堆栈跟踪:
DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, unsigned int, VkDebugUtilsMessengerCallbackDataEXT const*, void*): 146
vk::DispatchLoaderStatic::vkQueueSubmit(VkQueue_T*, unsigned int, VkSubmitInfo const*, VkFence_T*) const: 50
Display::UpdateFrame(): 1088
RenderingPipeline::RenderFrame(vk::Buffer&, vk::Buffer&, Image&, unsigned int): 63
RenderHandler::RenderHandler(Window*, HardwareInterface*, Display*, Memory*): 784
我的目标是尝试打印尽可能多的相关信息。 (文件、函数、行)。现在,我认为指令:
我从原始脚本复制的 (char *)callstack[i] - (char *)info.dli_saddr)
会给我调用代码的行,但是例如定义 Display::UpdateFrame()
的文件没有;甚至没有 1000 行,所以这个数字很简单't 原文件中调用代码的编号
有没有一种方法可以像 GDB 那样通过堆栈跟踪获取此信息?
即如果函数在
的源代码中被调用File: Display.hpp
Function: Display::UpdateFrame()
Line: 227
我可以在 运行 时使用堆栈跟踪检索该信息吗?
backtrace() returns 相对于某些 ELF 部分的开头以字节为单位的偏移量。为了获得行号和函数名,您需要使用一个库,该库可以读取程序的调试信息,然后找出给定偏移量对应的源文件/行号/函数。
这是一个如何使用 libbfd 执行此操作的示例(由我编写)(假设您使用的是 linux):
https://github.com/CarloWood/libmemleak/blob/master/src/addr2line.c