gdb調試——簡單入門篇

    一、gdb調試器簡介     

    gdb作爲常用GUN調試器之一,可以幫助我們調試和分析二進制文件(一般就是指可執行程序)。本文和大家一起了解下Linux下如何使用gdb進行程序的簡單調試。

首先我們還是看看gdb調試器的幫助說明:

This is the GNU debugger.  Usage:

    gdb [options] [executable-file [core-file or process-id]]
    gdb [options] --args executable-file [inferior-arguments ...]

Selection of debuggee and its files:

  --args             Arguments after executable-file are passed to inferior
  --core=COREFILE    Analyze the core dump COREFILE.
  --exec=EXECFILE    Use EXECFILE as the executable.
  --pid=PID          Attach to running process PID.
  --directory=DIR    Search for source files in DIR.
  --se=FILE          Use FILE as symbol file and executable file.
  --symbols=SYMFILE  Read symbols from SYMFILE.
  --readnow          Fully read symbol files on first access.
  --write            Set writing into executable and core files.

Initial commands and command files:

  --command=FILE, -x Execute GDB commands from FILE.
  --init-command=FILE, -ix
                     Like -x but execute commands before loading inferior.
  --eval-command=COMMAND, -ex
                     Execute a single GDB command.
                     May be used multiple times and in conjunction
                     with --command.
  --init-eval-command=COMMAND, -iex
                     Like -ex but before loading inferior.
  --nh               Do not read ~/.gdbinit.
  --nx               Do not read any .gdbinit files in any directory.

Output and user interface control:

  --fullname         Output information used by emacs-GDB interface.
  --interpreter=INTERP
                     Select a specific interpreter / user interface
  --tty=TTY          Use TTY for input/output by the program being debugged.
  -w                 Use the GUI interface.
  --nw               Do not use the GUI interface.
  --tui              Use a terminal user interface.
  --dbx              DBX compatibility mode.
  -q, --quiet, --silent
                     Do not print version number on startup.

Operating modes:

  --batch            Exit after processing options.
  --batch-silent     Like --batch, but suppress all gdb stdout output.
  --return-child-result
                     GDB exit code will be the child's exit code.
  --configuration    Print details about GDB configuration and then exit.
  --help             Print this message and then exit.
  --version          Print version information and then exit.

Remote debugging options:

  -b BAUDRATE        Set serial port baud rate used for remote debugging.
  -l TIMEOUT         Set timeout in seconds for remote debugging.

Other options:

  --cd=DIR           Change current directory to DIR.
  --data-directory=DIR, -D
                     Set GDB's data-directory to DIR.

At startup, GDB reads the following init files and executes their commands:
   * user-specific init file: /Users/XXXX/.gdbinit

For more information, type "help" from within GDB, or consult the
GDB manual (available as on-line info or a printed manual).
Report bugs to "<http://www.gnu.org/software/gdb/bugs/>".

基本操作如下:

1. gdb <program> PID           # 用gdb調試一個正在運行中的進程,或者使用 gdb <program>
2. 設置斷點:br (br可使用 break或者b 代替)
   br filename:line_num        # 設置斷點到指定文件制定行
   br namespace::classname::func_name  # 設置斷點到指定函數
3. n: 單步跳過   s: 單步進入      # n(next) s(step)
4. finish                      # 執行到函數retun返回
5. list                        # 列出當前位置之後的10行代碼;
   list line_number            # 列出line_number之後的十行代碼
6. bt(backtrace)              # 列出調用棧
7. info locals                 # 列出當前函數的局部變量
8. p var                       # 打印變量值
9. info breakpoints            # 列出所有斷點
10. delete breakpoints         # 刪除所有斷點;
    delete breakpoints id      # 刪除編號爲id的斷點;
    disable/enable breakpoints id  # 禁用/啓用斷點 
11. break ... if ... 條件中斷

二、dbg調試示例

       首先,我們編寫一個簡單的程序。

// demo: malloc.c

#include <stdio.h>

int main(int argc,char** argv){
	int* a;
	*a = 5;

	return 0;
}

 

然後,我們使用gcc編譯器編譯malloc.c 。爲了調試程序,有時我們需要使用-g選項,它的作用就是將調試信息加入到最後的二進制可執行文件中。-g 同-o一樣,是分級別的。當不指定級別的時候,其level爲2。如果需要調試宏定義,我們可以使用更高的級別-g3。這裏我們使用默認即可。

root$ gcc -g2 malloc.c 
root$ ls
a.out		a.out.dSYM		malloc.c	

看代碼可知,如果直接運行上 a.out程序,會報段錯誤。那麼程序是在哪兒出錯呢(假裝不知道😄),這就需要調試了。我們也是先從簡單的開始,後面和大家一起分享複雜的程序如何進行gdb調試。

下面,我們開始使用gdb調試器去調試生成的a.out 可執行文件。

root$ gdb -q ./a.out       # 啓動gdb調試
Reading symbols from ./a.out...Reading symbols from /Desktop/a.out.dSYM/Contents/Resources/DWARF/a.out...done.
done.
(gdb) break main           # 在main函數添加斷點
Breakpoint 1 at 0x100000fa4: file malloc.c, line 5.
(gdb) break malloc.c:5     # 在文件第五行添加斷點
Note: breakpoint 1 also set at pc 0x100000fa4.
Breakpoint 2 at 0x100000fa4: file malloc.c, line 5.
(gdb) break malloc.c:6     # 在文件第6行添加斷點
Breakpoint 3 at 0x100000fae: file malloc.c, line 6.
(gdb) info break           # 查看所有斷點
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000100000fa4 in main at malloc.c:5
2       breakpoint     keep y   0x0000000100000fa4 in main at malloc.c:5
3       breakpoint     keep y   0x0000000100000fae in main at malloc.c:6
(gdb) run                  # 開始運行
Starting program: /Users/Desktop/a.out 
[New Thread 0x1903 of process 26422]
warning: unhandled dyld version (15)

Thread 2 hit Breakpoint 1, main (argc=1, argv=0x7ffeefbff770) at malloc.c:5
5		*a = 5;  # 在第五行第一個斷點處停下來,實際並沒有執行
(gdb) n          # 逐步

Thread 2 received signal SIGSEGV, Segmentation fault.
0x0000000100000fa8 in main (argc=1, argv=0x7ffeefbff770) at malloc.c:5
5		*a = 5;  # 因爲設置斷點重複,實際仍停留在當前斷點處
(gdb) p a        # 查看指針變量a的值,因爲沒有分配內存或者指向內存空間,默認初始化爲 0x00
$1 = (int *) 0x0
(gdb) p *a       # 查看*p 的值,顯然無法進入查看到
Cannot access memory at address 0x0
(gdb) info locals # 查看當前函數的所有局部變量的值
a = 0x0
(gdb) bt         # 調用堆棧查看
#0  0x0000000100000fa8 in main (argc=1, argv=0x7ffeefbff770) at malloc.c:5
(gdb) n          # 繼續逐步執行,執行完*a = 5,程序異常,報段錯誤

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) list      
1	#include <stdio.h>
2	
3	int main(int argc,char** argv){
4		int* a /*= (int *)malloc(sizeof(int))*/ ;
5		*a = 5;
6	
7		
8		return 0;
9	}
(gdb) finish
The program is not being run.
(gdb) q         # 退出gdb調試
   

通過上面執行gdb調試,我們可以定位到錯誤產生的位置。那麼修改完bug,重新編譯執行看看。

// demo: malloc.c

#include <stdio.h>

int main(int argc,char** argv){
	int* a = (int *)malloc(sizeof(int)) ;
	*a = 5;

    free(a);
    a = NULL;

	return 0;
}

     程序正常運行。至此,一個簡單程序的dbg調試完成。下篇,我們一起來試着調試下包含多文件、宏定義以及多線程的可執行程序。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章