有没有办法在每次调用某个函数时在C或C++中正在运行的进程中转储调用堆栈?我的想法是这样的:
void foo()
{
print_stack_trace();
// foo's body
return
}
Run Code Online (Sandbox Code Playgroud)
其中的print_stack_trace工作方式类似于callerPerl.
或类似的东西:
int main (void)
{
// will print out debug info every time foo() is called
register_stack_trace_function(foo);
// etc...
}
Run Code Online (Sandbox Code Playgroud)
在哪里register_stack_trace_function放置某种内部断点,这将导致在调用时打印堆栈跟踪foo.
在某些标准C库中是否存在这样的事情?
我正在使用GCC在Linux上工作.
我有一个测试运行,基于一些不应该影响此行为的命令行开关,行为不同.我的代码有一个伪随机数生成器,我假设它是基于这些开关被不同地调用的.我希望能够使用每组开关运行测试,并查看随机数生成器是否针对每个开关进行不同的调用.
特定于Linux backtrace()并backtrace_symbols()允许您生成程序的调用跟踪.但是,它只打印功能地址,而不是我的程序的名称.如何让它们也打印出函数名?我试着编译程序-g以及-ggdb.下面的测试用例打印出来:
BACKTRACE ------------
./a.out() [0x8048616]
./a.out() [0x8048623]
/lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
./a.out() [0x8048421]
----------------------
我希望前两个项目也显示函数名称,foo和main
码:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const …Run Code Online (Sandbox Code Playgroud) 使用这样的函数:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void print_trace() {
char pid_buf[30];
sprintf(pid_buf, "--pid=%d", getpid());
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
int child_pid = fork();
if (!child_pid) {
dup2(2,1); // redirect output to stderr
fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
abort(); /* If gdb failed to start */
} else {
waitpid(child_pid,NULL,0);
}
}
Run Code Online (Sandbox Code Playgroud)
我在输出中看到了print_trace的细节.
有什么其他方法可以做到这一点?
我目前正在寻找一种在Windows下从C代码(无C++)获取回溯信息的方法.
我正在构建一个跨平台的C库,带有引用计数内存管理.它还有一个集成的内存调试器,提供有关内存错误的信息(XEOS C Foundation Library).
发生故障时,将启动调试器,提供有关故障的信息以及所涉及的内存记录.

在Linux或Mac OS X上,我可以查找execinfo.h以便使用该backtrace功能,因此我可以显示有关内存故障的其他信息.
我在Windows上寻找同样的东西.
我已经看过如何在C中获取堆栈跟踪?在Stack Overflow上.我不想使用第三方库,所以CaptureStackBackTrace或者StackWalk函数看起来不错.
唯一的问题是我只是不知道如何使用它们,即使使用Microsoft文档.
我不习惯Windows编程,因为我通常在兼容POSIX的系统上工作.
对这些功能有什么解释,也许是一些例子?
编辑
我现在正在考虑使用这个CaptureStackBackTrace函数DbgHelp.lib,因为似乎开销有点少......
这是我到目前为止所尝试的:
unsigned int i;
void * stack[ 100 ];
unsigned short frames;
SYMBOL_INFO symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize( process, NULL, TRUE );
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
for( i = 0; i < frames; i++ )
{
SymFromAddr( process, ( DWORD64 )( …Run Code Online (Sandbox Code Playgroud) 我正在使用带有Win32的Stackdumps,将所有返回地址写入我的日志文件.我稍后会将这些与mapfile相匹配(参见我的文章[Post Mortem Debugging] [1]).
编辑::问题解决了 - 请参阅下面我自己的答案.
使用Windows x64,我找不到将返回地址写入日志文件的可靠方法.我试过几种方法:
试验1:指针算术:
CONTEXT Context;
RtlCaptureContext(&Context);
char *eNextBP = (char *)Context.Rdi;
for(ULONG Frame = 0; eNextBP ; Frame++)
{
char *pBP = eNextBP;
eNextBP = *(char **)pBP; // Next BP in Stack
fprintf(LogFile, "*** %2d called from %016LX (pBP at %016LX)\n", Frame,
(ULONG64)*(char **)(pBP + 8), (ULONG64)pBP);
}
Run Code Online (Sandbox Code Playgroud)
这在调试版本中运行良好 - 但它在发布版本中崩溃.Context.Rdi的值在那里没有可用的值.我确实检查了编译器设置的差异(visual Studio 2005).我没有发现任何可疑的东西.
试用版2:使用StackWalk64
RtlCaptureContext(&Context);
STACKFRAME64 stk;
memset(&stk, 0, sizeof(stk));
stk.AddrPC.Offset = Context.Rip;
stk.AddrPC.Mode = AddrModeFlat;
stk.AddrStack.Offset = Context.Rsp;
stk.AddrStack.Mode = AddrModeFlat;
stk.AddrFrame.Offset …Run Code Online (Sandbox Code Playgroud) 如果我理解正确,默认情况下Lua会在发生错误时调用调试库"debug.traceback".
但是,当将Lua嵌入到C代码中时,就像这里的示例中所做的那样: 简单的Lua API示例
我们只在堆栈顶部提供错误消息.
即
if (status) {
/* If something went wrong, error message is at the top of */
/* the stack */
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
/* I want to print a stacktrace here. How do I do that? */
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
初始错误后如何从C打印堆栈跟踪?
我有一个使用套接字,数据库连接等的进程.它基本上是在传感器数据和Web界面之间进行中继的服务器进程,因此确保应用程序(如果被杀死)正常终止是很重要的.
我如何处理意外的异常,例如段错误(至少用于调试)以及杀死信号,以便我可以关闭任何连接并停止任何线程运行,以便进程不会留下任何正在使用的东西?
我想在Native C++应用程序中运行时访问调用堆栈.我没有使用IDE.如何显示调用堆栈?
更新:我有一个函数,从整个应用程序的许多点调用.它在极少数情况下崩溃.我正在寻找一种方法来获取调用者的名字并记录它.
在Windows平台上,我试图从我的变量所在的应用程序中转储内存.这是功能:
void MyDump(const void *m, unsigned int n)
{
const unsigned char *p = reinterpret_cast<const unsigned char *>(m);
char buffer[16];
unsigned int mod = 0;
for (unsigned int i = 0; i < n; ++i, ++mod) {
if (mod % 16 == 0) {
mod = 0;
std::cout << " | ";
for (unsigned short j = 0; j < 16; ++j) {
switch (buffer[j]) {
case 0xa:
case 0xb:
case 0xd:
case 0xe:
case 0xf:
std::cout << " …Run Code Online (Sandbox Code Playgroud) 我对RTTI知之甚少,但我相信,由于你可以在运行时检索变量的名称.是否可以检索线程当前正在运行的函数的名称?