我有以下堆栈跟踪.是否可以从中进行任何有用的调试?
Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0 0x00000002 in ?? ()
#1 0x00000001 in ?? ()
#2 0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
Run Code Online (Sandbox Code Playgroud)
当我们得到一个时,从哪里开始查看代码Segmentation fault,并且堆栈跟踪不是那么有用?
注意:如果我发布代码,那么SO专家会给我答案.我想从SO那里得到指导并自己找到答案,所以我不会在这里发布代码.道歉.
Chr*_*odd 154
那些伪造的地址(0x00000002等)实际上是PC值,而不是SP值.现在,当你得到这种SEGV时,伪造的(非常小的)PC地址,99%的时间是由于通过虚假功能指针调用.请注意,C++中的虚拟调用是通过函数指针实现的,因此虚拟调用的任何问题都可以以相同的方式显示.
间接调用指令只是在调用堆栈后将PC推送到PC,然后将PC设置为目标值(在这种情况下是假的),所以如果发生了这种情况,您可以通过手动将PC从堆栈中弹出来轻松撤消它.在32位x86代码中,您只需:
(gdb) set $pc = *(void **)$esp
(gdb) set $esp = $esp + 4
Run Code Online (Sandbox Code Playgroud)
使用64位x86代码
(gdb) set $pc = *(void **)$rsp
(gdb) set $rsp = $rsp + 8
Run Code Online (Sandbox Code Playgroud)
然后,你应该能够做一个bt并找出代码的真正位置.
另外1%的时间,错误将是由于覆盖堆栈,通常是通过溢出存储在堆栈上的数组.在这种情况下,您可以通过使用valgrind之类的工具来更清楚地了解情况
wal*_*lyk 42
如果情况相当简单,Chris Dodd的回答是最好的.它看起来像跳过一个NULL指针.
然而,程序有可能在撞击之前在脚,膝盖,颈部和眼睛中射击 - 覆盖叠加,弄乱框架指针和其他邪恶.如果是这样,那么解开散列不太可能向你展示土豆和肉.
更有效的解决方案是在调试器下运行程序,并逐步执行函数直到程序崩溃.一旦识别出崩溃功能,再次启动并进入该功能并确定它调用哪个功能导致崩溃.重复,直到找到单个有问题的代码行.75%的时间,修复将是显而易见的.
在其他25%的情况下,所谓的违规行代码是红鲱鱼.它将对之前设置许多行的(无效)条件做出反应 - 可能之前有数千行.如果是这种情况,选择的最佳课程取决于许多因素:主要是您对代码的理解和经验:
printf在关键变量上插入诊断将导致必要的A ha!祝好运!
man*_*ear 25
假设堆栈指针有效......
可能无法准确地知道SEGV从回溯中发生的位置 - 我认为前两个堆栈帧被完全覆盖.0xbffff284似乎是一个有效的地址,但接下来的两个不是.要仔细查看堆栈,可以尝试以下操作:
gdb $ x/32ga $ rsp
或变体(用另一个数字替换32).这将从巨型(g)大小的堆栈指针开始打印出一些字(32),格式为地址(a).输入"help x"以获取有关格式的更多信息.
在这种情况下,使用一些sentinel'printf'检测代码可能不是一个坏主意.
查看一些其他寄存器,看看其中一个寄存器是否有堆栈指针缓存在其中.从那里,您可以检索堆栈.此外,如果嵌入了这种情况,通常会在非常特定的地址定义堆栈.使用它,你有时也可以得到一个体面的堆栈.这一切都假设当你跳到超空间时,你的程序并没有在整个记忆中呕吐...