Linux開發調試經驗整理(一)——Release版本死鎖定位

話說誰能生巧。以前由於經常被拉去定位疑難雜症,gdb用的還算熟練。最近年把因工作內容的調整,gdb很少用,前些日子定位問題時發現曾經很熟悉的東西都有點陌生了。因此決定把以前整理的一些小經驗、技巧再回顧一下,並分享給大家。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

debug 版本的應用程序發生死鎖,可以將pthread_mutex_t打印出來,查看其中的owner字段即可知道鎖被哪個線程持有。
release版本的程序,由於進行了優化,可能無法直接打出鎖變量。 這裏介紹一個簡單方法,可以查看release版(當然也支持debug)的鎖狀態,以便快速定位死鎖問題。

操作步驟

1) gdb attach 到死鎖的進程.
例如 gdb –p 2456
2) thread 命令切換到等待鎖(這裏主要指Mutex,暫不考慮讀寫鎖)的某個線程。 可以結合 info thr、thr apply all bt 等命令確定哪些線程在等鎖。
3) bt 查看該線程堆棧

(gdb) bt
#0 0x00110424 in __kernel_vsyscall ()
#1 0x0062d019 in __lll_lock_wait () from /lib/libpthread.so.0
#2 0x00628430 in _L_lock_677 () from /lib/libpthread.so.0
#3 0x00628301 in pthread_mutex_lock () from /lib/libpthread.so.0
……

4) frame 1 切換到 __lll_lock_wait () 幀
5) 執行 p (pthread_mutex_t)ebx 1 = {__data = {__lock = 2, _count = 0, __owner = 20644, __kind = 0, __nusers = 1, {_spins = 0, __list = {
__next = 0x0}}},
__size = “\002\000\000\000\000\000\000\000\244P\000\000\000\000\000\000\001\000\000\000\000\000\000”, __align = 2}
Owner 字段表示是哪個線程持有這把鎖,它是線程的 LWP 號,可以通過 info thr 查看。
6) 根據info thr 的信息,thr 命令切換到 owner對應的線程,結合代碼排查。 一般來說,這個線程應該也在等鎖,重複執行 4、5 步驟,可以看到它鎖等待的鎖被誰持有。 再結合代碼分析,基本上可以定位出死鎖位置。

注意事項

1)上述方法只適用於32bit系統上使用 pthread_mutex_t 造成的死鎖。
X86_64 位系統上,對應的寄存器貌似是 rdi ,也就是說命令應該改成
p *(pthread_mutex_t)$rdi
2) 讀寫鎖造成的死鎖,需要結合glibc源碼和彙編,找出pthread_rwlock_t的地址(具體是啥還有待分析 _),將其打印出來應該即可。
3)如果owner對應的線程已經退出,就無法通過gdb查看該線程的堆棧。 因此建議在日誌中打印線程的LWP號(可通過getttid打印),找到該線程的日誌信息,分析是哪個線程造成的死鎖。

#define gettid() syscall(__NR_gettid) 

4)如果提示 pthread_mutex_t 符號找不到,說明gdb沒有爲 pthreadtypes.h 加載符號表,這種情況下仍有方法查看鎖狀態

(gdb) print ((int)($ebx)) // lock 字段
$4 = 2
(gdb) print ((int)($ebx)+1) // count 字段
$5 = 0
print *((int)($ebx)+2) // owner字段*
$6 = 12275

附:pthread_mutex_t 定義

typedef union {
struct __pthread_mutex_s {
int lock;
unsigned int __count;
int __owner;
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
unsigned int __nusers;
__extension union {
int _spins;
__pthread_slist_t __list;
};
} __data;
char __size[_SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章