運行時調試-關於死循環

對於正在運行的程序,使用gdb attach功能進行運行時調試(啓動gdb後使用attach <PID>命令或在啓動gdb時使用-p <PID>參數)。
如下是一段故意構造的簡單死循環程序:
#include <stdio.h>
#include <unistd.h>
int main()
{
    int i;
    for (i = 0; ; ++i) {
        printf("%d\n", i);
        sleep(1);
    }
}

使用gcc -O2編譯程序後運行,並在另外一個虛擬終端裏使用gdb attach進程: linux

root@bt:~# gdb -q -p 2569
Attaching to process 2569
Reading symbols from /root/test3...(no debugging symbols found)...done.
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007fbf605ac380 in nanosleep () from /lib/libc.so.6
(gdb) bt
#0 0x00007fbf605ac380 in nanosleep () from /lib/libc.so.6
#1 0x00007fbf605ac210 in sleep () from /lib/libc.so.6
#2 0x00000000004005c8 in main ()
(gdb) finish
Run till exit from #0 0x00007fbf605ac380 in nanosleep () from /lib/libc.so.6
0x00007fbf605ac210 in sleep () from /lib/libc.so.6
(gdb) finish
Run till exit from #0 0x00007fbf605ac210 in sleep () from /lib/libc.so.6
0x00000000004005c8 in main ()
(gdb) ni
0x00000000004005a8 in main ()
(gdb)
0x00000000004005aa in main ()
(gdb)
0x00000000004005af in main ()
(gdb)
0x00000000004005b4 in main ()
(gdb)
0x00000000004005b6 in main ()
(gdb)
0x00000000004005b9 in main ()
(gdb)
0x00000000004005be in main ()
(gdb)
0x00000000004005c3 in main ()
(gdb)
0x00000000004005c8 in main ()
(gdb)
0x00000000004005a8 in main ()
(gdb)
0x00000000004005aa in main ()
...
attach會使進程掛起,現象相似於插入了一個臨時斷點。上面的操做中使用了兩次finish命令使程序運行至返回到main()函數中。

對於使用-O2選項編譯的程序,沒法簡單的進行源代碼級別的調試,next/step命令不可用。對於此類程序,能夠使用nexti/stepi命令,它們大致與next/step相同,分別表示步過與步入,不一樣之處在於前者針對單條彙編指令。上述示例中連續使用ni(nexti)命令,從指令地址(rip寄存器值)能夠比較容易的發現死循環,指令地址始終徘徊在0x00000000004005a8-0x00000000004005c8。 shell

這一招數對於後臺daemon程序至關有效。我曾經維護過一個帶有守護進程的deamon程序,對於出現問題的運行中子進程,守護進程會將其殺死重啓,但並不會記錄詳細緣由。一日,某版本頻繁重啓,領導下了死命令:必須在XXX以前解決!因而動用重量級上古神器gdb掛上守護進程,讓運行中子進程自生自滅。。。天可憐見,終於在一週後重現了問題,並使用上述方法確認了死循環問題及其位置。。。 函數

那晚我夢見了花團錦簇。。。 spa

相關文章
相關標籤/搜索