之前已经问过这个问题,并且有特定于Windows的答案,但没有令人满意的gcc答案.我可以set_terminate()用来设置一个函数,terminate()当抛出未处理的异常时,该函数将被调用(代替).我知道如何使用backtrace库从程序中的给定点生成堆栈跟踪.但是,当我的终止替换被调用时,这将无济于事,因为此时堆栈已被解除.
然而,如果我只是允许程序abort(),它将产生一个核心转储,其中包含从抛出异常的点开始的完整堆栈信息.所以信息就在那里 - 但是有没有一种编程方式来获取它,例如它可以被记录,而不是必须检查核心文件?
c++ callstack exception-handling stack-trace unhandled-exception
我在课本中读到堆栈通过减少内存地址而增长; 也就是说,从较高地址到较低地址.这可能是一个糟糕的问题,但我没有把这个概念弄好.你可以解释吗?
今天,在我的C++多平台代码中,我对每个函数都进行了尝试.在每个catch块中,我将当前函数的名称添加到异常并再次抛出,以便在最上面的catch块(我最终打印异常的详细信息)中,我有完整的调用堆栈,这有助于我跟踪异常的原因.
这是一个好习惯,还是有更好的方法来获取异常的调用堆栈?
有没有办法在C编译时知道并输出函数所需的堆栈大小?这是我想知道的:
我们来看一些功能:
void foo(int a) {
char c[5];
char * s;
//do something
return;
}
Run Code Online (Sandbox Code Playgroud)
在编译这个函数时,我想知道它被调用时会消耗多少堆栈空间.这可能对检测隐藏大缓冲区的结构的堆栈声明很有用.
我正在寻找能打印出类似内容的东西:
file foo.c:function foo stack usage是nbytes
有没有办法不看生成的程序集知道?或者可以为编译器设置限制?
更新:我不是试图避免给定进程的运行时堆栈溢出,我正在寻找一种在运行时之前查找的方法,如果编译器确定的函数堆栈使用可用作编译过程的输出.
让我们换一种说法:是否可以知道函数本地所有对象的大小?我猜编译器优化不会成为我的朋友,因为某些变量会消失但是上限很好.
我最近使用/FAsuVisual C++编译器选项输出特别长的成员函数定义的源+汇编.在汇编输出中,在设置堆栈帧之后,只需调用一个神秘的_chkstk()函数.
MSDN页面上_chkstk()没有解释调用此函数的原因.我也看到了Stack Overflow问题在堆栈上分配更多页面大小的缓冲区会破坏内存吗?,但我不明白OP和接受的答案是在谈论什么.
_chkstk()CRT功能的目的是什么?它有什么作用?
我正在Linux上的gdb 7.1中调试C++.
我有一个a()在代码中的许多地方调用的函数.我想在其中设置一个断点,但只有从它调用它b().有什么办法吗?
有没有什么方法可以做到这一点,只有b()从c()无线电话中调用,等等?
我正在使用带有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) 在JavaScript中捕获/处理异常时,如何确定异常发生时调用堆栈的内容?(如果可能的话,行号是什么)
try
{
// etc...
}
catch (ex)
{
// At this point here I want to be able to print out a detailed exception
// message, complete with call stack, and if possible line numbers.
}
Run Code Online (Sandbox Code Playgroud) 我用C编写了一个应用程序,我试图了解-fno-stack-protector编译时命令的用途是什么.对于我的特定应用程序,如果我在防止缓冲区溢出方面使用此命令,则没有任何区别.
我在网上看到,-fstack-protector和-fno-stack-protector命令分别启用和禁用堆栈粉碎保护器,但如果我自己编译应用程序,如何预先启用保护器?命令的使用是否可能取决于运行应用程序的系统?
我试图在C++程序中的回溯中找到确切的调用行.现在我正在使用这些行(来自backtrace的手册页)来获取跟踪:
void *bt_buffer[1000];
char **bt_strings;
int bt_nptrs = backtrace(bt_buffer, 1000);
bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);
Run Code Online (Sandbox Code Playgroud)
在bt_strings中,我找到了表单的行
./prog() [0x402e42]
Run Code Online (Sandbox Code Playgroud)
现在我取地址(十六进制字符串)并将其提供给addr2line.这有时会导致明显错误的行号.互联网搜索让我看到这篇文章,其中显示了这一点
readelf -wl ./prog
Run Code Online (Sandbox Code Playgroud)
表示该行的确实位置,或者表示该符号移动到当前行的行数.
编辑:这种情况发生在我编译时-g -O0,即明确没有优化.编译器gcc 4.6.3是否有我错过的另一个编译器标志?
我的问题如下:我需要自动执行此操作.我需要我的程序来创建一个回溯(完成),提取文件(完成)和行号(失败).
我当然可以调用readelf和解析输出,但这并不合适,因为输出因符号而异,具体取决于具体发生的情况.有时符号的地址在一行中,而在下一行中有关行偏移的信息......
总结一下:
有没有一种优雅的方法可以在运行时从程序中的回溯中获取函数调用的确切行号?
编辑:示例代码:
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <execinfo.h>
#include <iostream>
#include <stdlib.h>
void show_backtrace()
{
// get current address
void* p = __builtin_return_address(0);
std::cout << std::hex << p << std::endl;
// get callee addresses
p = __builtin_return_address(1);
std::cout << std::hex …Run Code Online (Sandbox Code Playgroud) callstack ×10
c++ ×6
c ×5
64-bit ×1
backtrace ×1
binutils ×1
breakpoints ×1
buffer ×1
exception ×1
gdb ×1
javascript ×1
protection ×1
stack ×1
stack-trace ×1
try-catch ×1
visual-c++ ×1
winapi ×1
windows ×1