多线程程序中, 经常遇到线程死锁的问题。
出现死锁的状况,很多时候像盲人摸象般的加调试信息,看程序“已经跑在哪里”了。
但同时,也需要这个死锁能经常不断的出现,才能找到问题所在。
利用调试器提供的便利,我们可以找到更好地解决办法。
下面的过程中,逐鹿使用的是一个AXD调试器,对象程序是ARM的eCos程序,
其中几个线程不见动静(已经死锁)。
于是选择其中一个线程,定位该线程死锁的位置。
1. 找到该线程的stack位置
对照程序源代码,不难发现线程的thread handle变量名,在调试器的symbol窗口中查看变量的地址。
暂停程序运行,在memory窗口中,定位到该变量地址处,这个地址处保留有一个线程控制块结构,
类型为Cyg_HardwareThread。
class Cyg_HardwareThread
{
CYG_ADDRESS stack_base; // pointer to base of stack area
cyg_uint32 stack_size; // size of stack area in bytes
CYG_ADDRESS stack_limit; // movable stack limit
CYG_ADDRESS stack_ptr; // pointer to saved state on stack
cyg_thread_entry *entry_point; // main entry point (code pointer!)
CYG_ADDRWORD entry_data; // entry point argument
....
};
从该结构看出,thread handle指向的地址, 加上偏移3 int (24 byte)的地方,
是一个 stack_ptr, 这个stack_ptr即是进程当前的栈顶指针.
2. 找到线程阻塞之前的sp, lr, pc寄存器.
在此利用AXD的查看memory窗口, 定位到stack_ptr的值指向的地址.
这个地址处, 实际上保存着 r0 - r12, sp, lr, pc 一共16个寄存器的内容.
因此sp, lr, pc 分别在 stack_prt指向的地址偏移 13 int, 14 int, 15 int处.
sp *( (int*)stack_ptr + 13 )
lr *( (int*)stack_ptr + 14 )
pc *( (int*)stack_ptr + 15 )
3. 察看线程阻塞之前的函数调用现场
有了sp, lr, pc, 接下来的事情就容易了.
查看当前寄存器窗口, 先记录下当前的 sp(r13), lr(r14) 和 pc的值,
将第2步找到的死锁线程的sp, lr, pc值填进去。
然后,打开BackTrace窗口。不出所料,线程的函数调用栈一目了然,
从哪里调进来,走到哪步不动,全部清清楚楚。
至此,我们圆满完成调试。
(如果还需要继续运行程序调试,继续之前别忘了将旧的sp,lr和pc重填回去,呵呵)
阅读(660) | 评论(0) | 转发(0) |