2012-04-05 107 views
5

背景:我用getcontext(3)/makecontext(3)/setcontext(3)ucontext.h; SUSv2,POSIX.1-2001)系列函数分配我自己的机器上下文和堆栈。GDB如何确定堆栈的底部?

当我使用gdb(版本6.1.1)来检查一个堆栈,而线程是在我分配的这些上下文中的一个上下文中时,看起来好像gdb不知道堆栈的末端(逻辑底部)在哪里是。例如,这里有来自86 FreeBSD的堆栈:

#0 0x2872d79f in poll() from /lib/libc.so.7 
#1 0x28646e23 in poll() from /lib/libthr.so.3 
#2 0x2869b267 in fdtask (task=0x28a3dc40, v=0x0) at fd.c:58 
#3 0x2869c8dc in taskstart (y=681827392, x=0) at task.c:58 
#4 0x00000000 in ??() 
#5 0x28a3dc40 in ??() 
#6 0x00000000 in ??() 
#7 0x00000000 in ??() 
… 
#65 0x00000000 in ??() 
… 

(是的,这是建立在Russ Cox' libtask library顶部)。

这方面的执行始于taskstart功能,但它似乎是GDB想不通它应该停止尝试读取堆栈,即使它在该帧中返回NULL的返回地址。

我的问题是:有什么我可以做(通过格式化以某种方式堆栈,或者设置寄存器,任何东西),以帮助GDB明白的地方堆栈的顶部?谢谢。

编辑:结论:似乎gdb 6.1.1检测堆栈的结束是通过检查存储的帧指针是否为NULL;我通过修改x86和AMD64 makecontext(2)函数初始化新的情境时,EBP或RBP归零固定我的使用情况的问题。 (在这种情况下,我不关心其他体系结构。)这个问题在gdb 7.1中消失了;据推测gdb 7.1能够通过其他方式检测堆栈的结束,例如debuginfo。

+1

这听起来像一个问题要问在gdb的开发人员邮件列表。 – 2012-04-05 15:38:30

回答

2

如果GDB是使用帧指针展开栈(预DWARF2法)它停止当它到达一个空帧指针,我相信。与DWARF2事情复杂得多,因为“帧指针”被隐含由堆栈指针与指针insruction和DWARF2帧组合确定的偏移信息用于当前指令,但本质的作用是相同的。不确定哪些FreeBSD使用这些日子。

+0

这是相当古老的FreeBSD(〜7.2,我相信)。谢谢! – 2012-04-05 17:26:02

+0

看看'taskstart'的反汇编,framepointer被保存在条目中。我添加了代码以将创建的上下文的ebp设置为零,并且gdb 6.1.1的堆栈跟踪看起来是正确的。再次感谢! – 2012-04-05 18:11:39

0

gdb文件说,一个它停止上市回溯帧的方式是返回地址main()后。

参见GDB/DOC/gdb.textinfo ftp://sourceware.org/pub/gdb/snapshots/current/gdb-7.4.50.20120405.tar.bz2@cindex backtrace beyond @code{main} function线6251

+0

当然,但是这对我的情况并不是特别有用,因为这些上下文都没有以'main'开头。 – 2012-04-05 20:54:48

+0

@ConradMeyer:如何命名它调用'taskstart'类似的功能'主()','_main()'或'__main()'? – wallyk 2012-04-05 20:58:03

+0

什么都不会调用'taskstart'。 libtask schedular将用户空间上下文切换到以'taskstart'开头的上下文中。我想'taskstart'可以重命名为'main'或'_main'或其他,但这似乎是一个巨大的混乱。初始化帧指针为0似乎足以让gdb6检测堆栈的结束,并且无论上下文中初始函数的名称如何,都可以工作。 – 2012-04-05 21:06:52