4

我正在开发一个应用程序,在某些时候,它必须使用不同的堆栈,它将由我开发的库管理。所以,我调用了这个库的初始化函数,并将堆栈指针($sp)设置为我想要的内存地址。

当通过 GDB 运行此代码时,在我的另一个堆栈的初始化完成并执行返回到调用者函数后,GDB 给我这个警告:

warning: GDB can't find the start of the function at 0x12.

    GDB is unable to find the start of the function at 0x12
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0x12 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.

此外,在打印 $sp 时,会显示旧值。

由于这部分代码在没有 GDB 的情况下正确执行,并且在 0x12 处没有函数,因此发生这种情况是因为 GDB 使用堆栈指针来寻址来跟踪函数的帧。

有没有办法避免这种行为并能够调试这个应用程序?

4

2 回答 2

1

这是因为 GDB 使用堆栈指针来寻址来跟踪函数的帧。

是的,显然它确实

gdb_reader_funcs 中的get_frame_id 是返回当前帧对应的gdb_frame_id。[...] 一种方法是让 CODE_ADDRESS 指向函数的第一条指令,而 STACK_ADDRESS 在进入函数时指向堆栈指针的值。

我想解决这个问题的一种方法是将你的代码分成两个不同的函数(如果你只是在它们之间跳转的话)。

于 2016-01-08T10:18:43.777 回答
1

我认为您需要的是 GDB/Python 的frame unwinding。我自己从未使用过它,但帧展开是重建进程调用堆栈的(内部)过程。

正如您所提到的,您更改$SP了值,因此 GDB 无法识别标准调用约定。自定义框架展开器应该让您教 GDB 使用什么堆栈布局。

这是他们在文档中提供的示例:

 from gdb.unwinders import Unwinder

 class FrameId(object):
     def __init__(self, sp, pc):
         self.sp = sp
         self.pc = pc


 class MyUnwinder(Unwinder):
     def __init__(....):
         super(MyUnwinder, self).__init___(<expects unwinder name argument>)

     def __call__(pending_frame):
         if not <we recognize frame>:
             return None
         # Create UnwindInfo.  Usually the frame is identified by the stack
         # pointer and the program counter.
         sp = pending_frame.read_register(<SP number>)
         pc = pending_frame.read_register(<PC number>)
         unwind_info = pending_frame.create_unwind_info(FrameId(sp, pc))

         # Find the values of the registers in the caller's frame and
         # save them in the result:
         unwind_info.add_saved_register(<register>, <value>)
         ....

         # Return the result:
         return unwind_info

根据文档,您可以使用 访问 CPU 寄存器PendingFrame.read_register (reg_name or reg_id),但显然,读取局部变量可能是个问题!

一旦你的 unwinder 构建得很好,它应该透明地集成到 GDB 中,并且所有常用的 CLI 机制都应该可用。

于 2016-01-08T07:41:20.237 回答