1. 程式人生 > >GDB除錯系列之瞭解GDB

GDB除錯系列之瞭解GDB

想要熟練利用GDB進行程式除錯,首先要了解什麼是GDB。

1. 什麼是GDB

GDB (the GNU Project Debugger) 是一個可以執行在大多數常見的UNIX架構、Windows、Mac OSX等系統上的跨平臺偵錯程式,允許我們檢視另一個程式在執行過程中內部發生了什麼——或者另一個程式崩潰時在做什麼。

具體而言,GDB能做以下四種事情[1],以幫助我們定位執行中的Bug:

  • 讓程式開始執行,指定任何可能影響其行為的內容。
  • 讓程式在特定條件下停止執行。
  • 檢查程式停止執行時發生了什麼。
  • 在程式中改變一些變數或條件,修復當前的Bug使其正常執行,繼續檢查下一個。

根據官網介紹,GDB (9.1版本) 支援 Ada/Assembly/C/C++/D/Fortran/Go/Objective-C/OpenCL/Modula-2/Pascal/Rust 等程式語言的除錯。

2. 除錯原理

那麼 GDB 是如何除錯程式,其實現的原理是什麼呢?為什麼它可以控制程式執行、中斷、訪問記憶體甚至改變程式流程呢?

這就要從一個強大的系統呼叫 ptrace() 說起了。

2.1 系統呼叫 ptrace

簡單來說,ptrace 系統呼叫提供了一種方法,讓父程序可以觀察和控制其它程序的執行,檢查和改變其核心映像和暫存器。主要用來實現斷點除錯和系統呼叫跟蹤。

GDB 的跟蹤除錯允許設定程式斷點 break point,父程序通過 ptrace 接管子程序除了 SIGKILL 之外的所有訊號。子程序(就是我們除錯的程式)在傳送 break point 或者單步除錯時,會產生一個訊號 SIGTRAP,被父程序(這裡的GDB)捕獲到,這時使用者就可以通過 GDB 實時觀察到當前子程序的狀態。

2.2 三種除錯方式

2.2.1 gdb executable_file

執行並除錯一個新的程序。

首先通過fork()系統呼叫建立一個新程序,在新建立的子程序中呼叫 ptrace(PTRACE_TRACEME, 0, 0, 0),在子程序中通過execv()系統呼叫載入使用者指定的可執行檔案。

2.2.2 gdb executable_file corefile

如果程式發生了 core dump,出現段錯誤 (segment fault) 等,該命令可用於檢視 coredump 檔案資訊,定位coredump產生原因、觸發源。

2.2.3 gdb attach pid

除錯一個已經執行的程序,如伺服器程序等,同 gdb -p pid

首先需要確定待除錯程序的程序 id,可利用 ps 指令獲取 pid;然後執行 gdb attch pid,gdb 將對指定程序執行如下操作:ptrace (PTRACE_ATTACH, pid, 0, 0) 

3. 資訊顯示

以 MacOS Mojave 10.14.6 系統為例

3.1 終端輸入 gdb 進入偵錯程式,一般啟動時會顯示如下資訊

GNU gdb (GDB) 8.3
Copyright (C) 2019 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 "x86_64-apple-darwin18.5.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) 
顯示資訊

如果不想顯示這些資訊,可以通過 -q 引數將其關掉

cv-MacBook-Pro:~ cv$ gdb -q
(gdb) 

3.2 在除錯過程中,任何時候如果想檢視 GDB 版本資訊

(gdb) show version
GNU gdb (GDB) 8.3
Copyright (C) 2019 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 "x86_64-apple-darwin18.5.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) show version

3.3 如果想檢視 GDB 版權相關資訊

(gdb) show copying
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
--Type <RET> for more, q to quit, c to continue without paging--
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
--Type <RET> for more, q to quit, c to continue without paging--
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
......
(gdb) show copying

或者

(gdb) show warranty
  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
......
(gdb) show warranty

3.4 當 gdb 輸出資訊較多時會暫停輸出,並列印 “---Type <return> to continue, or q <return> to quit---” 這樣的提示資訊

如果想要讓其中間不暫停,輸出全部內容,設定

cv-MacBook-Pro:~ cv$ gdb
(gdb) set pagination off

或者

cv-MacBook-Pro:~ cv$ gdb
(gdb) set height 0

附錄A

A.i 在大多 Linux 系統如 Ubuntu16.04 中 ptrace 系統呼叫原型如下

ptrace definition
  • enum __ptrace_request request  指示ptrace要執行的命令。
  • pid_t pid  指示ptrace要跟蹤的程序。
  • void *addr  指示要監控的記憶體地址。
  • void *data  存放讀取出的或者要寫入的資料。

request 的主要選項

  • PTRACE_TRACEME 由子程序呼叫,表示本程序將被其父程序跟蹤,交付給這個程序的所有訊號,即使訊號是忽略處理的(SIGKILL 除外),都會使其停止,父程序通過 wait() 獲知這一情況
  • PTRACE_ATTACH 指attach到一個指定的程序,使其成為當前程序跟蹤的子程序,而子程序的行為等同於它進行了一次 PTRACE_TRACEME 操作。但要注意的是,雖然當前程序成為被跟蹤程序的父程序,但是子程序使用 getppid() 得到的仍是其原始父程序的 pid。當在 GDB 中使用 attach 命令來跟蹤一個指定程序/執行緒時,GDB 就自動成為該程序的父程序,而被跟蹤的程序則使用了一次 PTRACE_TRACEME,GDB 也就順理成章接管這個程序。
  • PTRACE_CONT 繼續執行之前停止的子程序。可同時向子程序交付指定的訊號。

A.ii 在 MacOS Mojave 10.14.6 系統中通過 man ptrace 顯示如下

#include <sys/types.h>
#include <sys/ptrace.h>

int
ptrace(int request, pid_t pid, caddr_t addr, int data);

其中 request 有以下幾個主要設定選項

  • PT_TRACE_ME

此請求是被跟蹤程序使用的兩個請求之一,聲明當前程序將被其父程序跟蹤。所有其它引數都會被忽略。當一個程序使用了這個請求並呼叫execve(2)或其上構建的任何例程時,它將在執行新映像的第一條指令前停止。此外在可執行檔案執行過程中,任何 setuid 或 setgid 位都會被忽略。

  • PT_ATTACH/PT_ATTACHEXC

此請求允許程序獲得對其它無關程序的控制並開始對其跟蹤。不需要被跟蹤程序的任何配合。此情況下,pid 指定將被跟蹤的程序的程序 ID,其餘兩個引數被忽略。此請求要求目標程序與跟蹤程序必須具有相同的真實UID,並且它不能執行 setuid 或 setgid 可執行檔案。跟蹤程序將感知到新跟蹤的程序的停止,然後可以像一直跟蹤一樣控制它。注意此呼叫不同於先前的呼叫(PT_ATTACH),因為來自子呼叫的訊號作為Mach異常傳遞給父呼叫。

  • PT_STEP

單步執行被跟蹤的程序。引數與傳給 PT_CONTINUE 的相同。

  • PT_CONTINUE

被跟蹤的程序繼續執行。addr指向即將被執行的程序的地址,或者為 1 表示從之前停止的地方開始繼續執行。data提供在跟蹤程序恢復執行時傳遞給跟蹤程序的訊號值,不傳送訊號則為 0。

  • PT_DETACH

該請求與 PT_CONTINUE 基本相同,除了不允許在另一個備用位置繼續執行,在它成功之後,被跟蹤的程序將不再被跟蹤,並且正常繼續執行。


參考資料

[1] GDB: The GNU Project Debugger

[2] 100個gdb小技巧之資訊顯示

[3] GDB實現原理和使用範例

[4] 比較全面的gdb除錯命令

[5] GDB使用