2.2 GNU gdb調試工具
調試工具是代碼分析中至關重要的工具之一。在使用vim+ctags查看代碼時,經常會遇到難以理解的部分,此時,可以借助調試工具,對代碼的運行過程進行跟蹤,通過跟蹤運行過程以及關鍵數據的變化,可以從程序執行的過程中理解源代碼的功能。
調試工具有很多種,最常用的是GNU gdb工具。下面通過一個例子,介紹如何使用gdb,這些調試命令幾乎就是筆者調試程序的所有命令,簡單且實用。關于完整的gdb的使用,請參與GNU gdb文檔,或者使用man gdb進行在線查詢。
本例主要使用gdb來跟蹤GCC的運行過程,因此,需要事先編譯GCC源代碼(編譯時需要使用-g選項),生成可執行的編譯程序cc1,下面利用gdb對cc1程序的運行進行跟蹤。
首先,可以在程序入口處設置斷點(Break Point):
[GCC@localhost paag-gcc]$ gdb host-i686-pc-linux-gnu/gcc/cc1 GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6) Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/GCC/paag-gcc/host-i686-pc-linux-gnu/gcc/cc1...done. (gdb) b main ← 設置執行斷點 Breakpoint 1 at 0x80c253d: file ../.././gcc/main.c, line 35. (gdb) info break ← 查看斷點設置情況 Num Type Disp Enb Address What 1 breakpoint keep y 0x080c253d in main at ../.././gcc/main.c:35 (gdb)
執行程序,gdb執行到斷點處會自動停止,返回交互界面。
(gdb) run ← 運行程序 Starting program: /home/GCC/paag-gcc/host-i686-pc-linux-gnu/gcc/cc1 Breakpoint 1, main (argc=1, argv=0xbffff434) at ../.././gcc/main.c:35 35 return toplev_main (argc, (const char **) argv); Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.i686 gmp-4.3.1-7.el6_2.2.i686 mpfr-2.4.1-6.el6.i686
單步跟蹤程序的執行,step命令和next命令均可以進行單步跟蹤,二者的主要區別在于step在單步執行函數代碼時,會進入被調用的函數,而next則會將函數調用看作“單步”,一次執行完一個函數的調用。對于其他代碼,step和next命令的功能基本相同。
此時可以看到,使用run命令執行程序后,程序執行到前面定義的斷點處暫停執行。
如果此時需要查看toplev_main函數的執行細節,應該使用step命令進入該函數。
(gdb) step ← 單步跟蹤 toplev_main (argc=1, argv=0xbffff434) at ../.././gcc/toplev.c:2212
對于程序執行過程中,需要查看某些變量的值,可以使用print命令。
(gdb) print argc ← 打印變量值 $1 = 1 (gdb) print argv[0] ← 打印變量值 $2 = 0xbffff5b5 "/home/GCC/paag-gcc/host-i686-pc-linux-gnu/gcc/cc1"
查看變量的值可以使用print命令,如果在每一條指令后都需要查看某些變量的值,使用print顯得有些煩瑣,可以使用display命令,設置顯示的變量。
(gdb) disp argc ← 設置變量查看 1: argc = 1 (gdb) next ← 單步執行 2215 general_init (argv[0]); 1: argc = 1 (gdb) next 2219 decode_options (argc, argv); 1: argc = 1 (gdb) next 2221 init_local_tick (); 1: argc = 1
可以看出,每執行一步,變量argc的值都會輸出顯示。
當需要連續執行程序時,可以使用continue命令,程序則恢復運行,直到下一個斷點處再次暫停運行。
通常,在執行到某個斷點處時,當需要了解當前函數的調用情況時,可以使用bt命令(backtrace)。
(gdb) bt ← 顯示函數調用的堆棧 #0 toplev_main (argc=1, argv=0xbffff434) at ../.././gcc/toplev.c:2212 #1 main (argc=1, argv=0xbffff434) at ../.././gcc/main.c:35
可以看出當前執行的函數為toplev_main函數,其調用者為函數main,并且這兩個函數所在的文件及位置信息也在bt的輸出中給出。bt命令的輸出可以很詳細地展示當前函數的調用關系,對于理解程序的執行流程非常有幫助。
另外,gdb在輸入命令時,如果輸入命令的開始部分可以完全確定一個命令時,則可以簡寫該命令,例如,一般用戶經常將命令run簡寫為r, step命令簡寫為s, next命令簡寫為n, continue命令簡寫為c等,如果用戶沒有輸入命令,直接按回車鍵,則gdb默認會執行上一次輸入的命令。例如在單步跟蹤時,如果輸入了命令next,后續單步跟蹤則可以只需要按[Enter]鍵就可以了。這些規律,讀者可以在使用過程中不斷總結,提高調試效率。
另外,還有其他眾多的調試工具,這些工具大都對gdb程序進行了封裝,例如cgdb,可以提供一些方便地實現源代碼查看等其他很有特色的功能,其官網地址為http://cgdb.sourceforge.net/。可以通過以下代碼進行cgdb程序的安裝。
[root@localhost ~]# wget -c http://prdownloads.sourceforge.net/cgdb/cgdb-0.6.6.tar. gz? download [root@localhost cgdb-0.6.6]# tar xzvf cgdb-0.6.6.tar.gz [root@localhost cgdb-0.6.6]# cd cgdb [root@localhost cgdb-0.6.6]# yum install readline* [root@localhost cgdb-0.6.6]# ./configure [root@localhost cgdb-0.6.6]# make; make install
例如,可以使用cgdb對cc1進行調試。
[GCC@localhost gcc-4.4.0]$ cgdb ~/paag-gcc/host-i686-pc-linux-gnu/gcc/cc1
界面如圖2-3所示,可以看到cgdb中能夠很方便地查看源代碼。關于cgdb的使用請查閱相關文檔,不再贅述。

圖2-3 cgdb界面