1. 程式人生 > >gdb系列之四 在GDB裡執行程式

gdb系列之四 在GDB裡執行程式

在你開始在GDB裡執行程式前,你需要在編譯的時候產生除錯資訊。
  你可以在你選定的環境裡帶引數(如果有的話)的啟動GDB。如果你是在本地除錯,你可以重定向輸入輸出,除錯一個已執行
的程序,或者結束一個程序。

4.1 為除錯而編譯
  為了有效的除錯程式,你需要在編譯的時候產生除錯資訊。除錯資訊儲存在目標檔案裡;除錯資訊描述了資料和函式的型別,
原始碼和可執行程式碼的對應關係。
  編譯時指定編譯器的’-g’選項可以產生除錯資訊。
  在編譯給你的客戶釋出的程式時,可以用’-O’選項指定編譯器進行優化。然而,許多編譯器不能同時處理’-g’和’-o’選項。如果用的
是這些編譯器,你得不到帶有除錯資訊的優化過的可執行程式。
  GCC,GNU C/C++編譯器,帶有或不帶’-O’選項都可以用’-g’選項,因此可以讓GDB除錯優化過的程式碼。我們推薦你在編譯程式時總
是用’-g’。也許你認為你的程式是正確的,但決不要去碰運氣。
  請記住在你除錯一個用’-g -o’編譯的程式時,優化器已經重排了你的程式碼;偵錯程式顯示的是真正編譯成的程式碼。在執行路徑和你
的原始碼不一致時,不要太驚訝!一個極端例子:如果定義了一個變數,但從來也沒用過,GDB發現不了它—-因為優化器已經把
它優化掉了。
  用’-g -o’和只用’-g’編譯的程式有時候不大一樣,特別是在有些具有指令排程的機器上。如有疑問,再用只帶’-g’編譯,如果這個版
本修正了問題,請給我們傳送一個報告(包含一個測試用例)。更多除錯優化過的程式碼,參見8.2節[變數],76頁。
  較早前的GNU C編譯器允許一個’-gg’變體選項來產生除錯資訊。GDB不再支援這個格式;如果你的GNU C編譯器有這個選項,別
再用了。
  GDB知道預編譯巨集,可以顯示巨集的展開式(參見第九章[巨集],101頁)。由於’-g’選項產生的除錯資訊過多,大多數編譯器不會產生
與編譯巨集的資訊。GCC3.1版本以及此後的可以提供巨集資訊,如果在編譯的時候指定了’-gdwarf-2’和’-g3’選項;前一個選項產生Dwarf
2格式的除錯資訊,後者產生”額外資訊”。我們希望在將來能夠找到一個精簡的方式來表示巨集資訊,這樣只要一個’-g’選項就可以了

4.2 開始程式
run
r    在GDB裡用run命令開始你的程式。你在啟動GDB時指定要除錯的程式名(VxWorks例外)(參見第二章[進入和離開GDB]),
    或者用file或者exec-file命令(參見15.1節[指定檔案的命令],155頁)。
  如果你是在一個支援多程序的環境裡執行GDB的話,run命令建立一個子程序來執行你的程式。在某系不支援多程序的環境下,
run跳到被除錯程式的開頭。其他的目標,比如’remote’,總是在執行的。如果你的到一個類似如下的錯誤資訊:
    The “remote” target does not support “run”.
    Try “help target” or “continue”.
接著用’continue’繼續執行你的程式。你可能需要先load(參見[載入],169頁)。
  程式的執行總會受某些從它的上級那裡得到的資訊的影響。GDB可以指定那些虛啊喲你在啟動程式之前就要設定的資訊(你
可以在啟動程式之後改變,但是隻有在下一次執行的時候才起效)。這些資訊可以劃分為4類:
The arguments.
    將你的程式的引數作為run命令的引數。如果在你的環境裡有shell,shell可以用來傳遞引數,那樣的話你就可以用普通的方式
(比如wildcard展開和變數替換)來描述引數了。在Unix系統裡,你可以用環境變數SHELL來控制使用那個shell。參見4.3節[程式
引數],27頁。
The environment.
    你的程式會從GDB裡繼承環境變數,而你也可以用GDB命令set environment和unset environment改變某些影響你的程式的
    環境變數。參見4.4節[程式的環境],28頁。
The working directory.
    你的程式從GDB裡繼承工作目錄。你可以用GDB命令cd來改變工作目錄。參見4.5節[程式的工作目錄],29頁。
The standard input and output.
    你的程式使用和GDB一樣的標準輸入輸出。你可以在run命令列裡重定向輸入和輸出,或者你可以用tty命令來為你的程式
    設定不同的裝置。參見4.6節[程式的輸入輸出],29頁。
    警告:輸入輸出重定向起效之後,你不能再用管道將程式的產生的輸出傳遞到另外一個程式裡去;如果你要這樣試的話,
    GDB 很有可能結束除錯這個錯誤的程式。
    在你執行run命令後,你的程式馬上就開始執行。參見第五章[停止和繼續],39頁,那裡討論瞭如何籌劃中斷你的程式。一
   旦你的程式中斷下來,你就可以在你的程式裡呼叫函式,用print或者call命令。參見第八章[檢驗資料],75頁。
    如果在最近一次GDB讀入符號表之後符號檔案的修改時間發生了改變,GDB會丟棄現有的符號表然後重新讀入。重新讀入
符號表的時候,GDB會試圖保留你當前的斷點設定。
start    不同的語言可能有不同的主函式的名稱。對於C/C++來說,主函式的名稱一直都是”main”,而有些語言例如Ada就不需
    要為他們的主函式指定一個特定的名稱。依賴於程式語言,偵錯程式可以方便的開始執行程式並且在主函式的入口點中
    斷。
    ‘start’命令的功能和在主函式入口點裡設定一個臨時斷點後執行’run’命令相當。有些程式包含一個在主程式之前執
    行的加工期,加工期會執行一些啟動程式碼。這依賴於你使用哪種語言寫程式。例如,C++,建構函式會在main之前為靜
    態和全域性變數呼叫。因此偵錯程式有可能在主函式之前就中斷程式。而臨時斷點還會保留來中斷程式的執行。
    ‘start’的引數將會傳遞給你的程式。這些引數會以字元形式給’run’命令。注意要是下次不帶引數呼叫’start’或
    ‘run’的時候,這些引數將會被重用。
    有些時候必須在加工期除錯程式。這樣的話,start命令在主函式入口點的中斷就太遲了,唯一此時已經過了加工期
    。在這種情況下,在執行情在加工期程式碼上設定斷點就可以了。

4.3 程式引數
  引數可以藉由run命令的引數來指定。引數由shell傳遞給你的程式,shell會擴充套件萬用字元和執行重定向。你的SHELL環境變數
(如果有的話)會決定GDB使用哪種shell.如果你沒有定義SHELL的話,GDB使用預設的shell(Unix下’bin/sh’)。
  在非Unix系統裡,程式通常都是由GDB直接呼叫的,GDB會用相應的

系統呼叫來模擬I/O重定向,萬用字元的寬展由程式的加
工期程式碼完成,不是由shell來做的。
  不帶引數的run命令使用前一次的run命令的引數,或者由set args命令設定的引數。
set args
    為你的下一次執行程式設定引數。如果set args不帶引數的話,run就不帶引數的執行程式。一旦你帶引數的run程式
    的話,要想下一次不帶引數的執行程式就只有用不帶引數的set args命令了。
show args
    顯示在啟動的時候傳遞給程式的引數。

4.4 程式的環境
  環境由一系列的環境變數和環境變數的值的組合組成。環境變數可以很方便地記錄一些東西,例如你的使用者名稱,
home目錄,終端型別,程式執行的搜尋路徑等等。通常通過shell來設定環境變數,這些變數就可以被別的程式繼
承了。這在除錯的時候很有用,GDB就不必重新啟動來試驗一個改變了的環境。
path directory
    在PATH環境變數的前頭加上diretory(可執行程式的搜尋路徑)。GDB用的PATH將不會改變。你可以指定多個路徑名
    稱,用空格符或者系統依賴(Unix':’,MS_DOS、MS-Windows';’)的分隔符類分割如果directory已經在PATH裡了,
    這個directory會移到PATH的前面以加快搜索。
    在GDB搜尋路徑的時候,你可以用’$cwd’來代指當前工作目錄。如果你用’.’代替,它代表在你執行path命令時的目
    錄。GDB在把路徑加入PATH前用當前路徑替代’.’.
show paths
    顯示可執行程式的搜尋路徑列表(PATH環境變數)。
show environment [varname]
    列印名為varname的環境變數的值。如果你沒提供varname,列印所有的環境變數的名稱和值。你可以縮寫
    environment為env.
set environment varname [=value]
    設定環境變數varname的為value.這個值只為你的程式改變,GDB本身不改變。value可以使任意字串;環境變數
    都是字串,你的程式負責轉譯;如果被刪除了,變數的值就被設定為null值。例如,命令:
        set env USER = foo
    告訴被除錯的程式,下一次執行run的時候,它的使用者是’foo’.(‘=’附近的空格是為了清楚些;空格不是必須的)
unset environment varname
    刪除傳遞給程式的環境變數。和‘set env varname =’不同,unset environment是從環境變數裡刪除變數,而不是
    為它設定一個空值。
  警告:在Unix系統,GDB用shell執行程式,shell由SHELL決定(如果有的話,否則用’/bin/sh’)。如果SHELL環境變
量指定的shell有初始化檔案的話–例如C-shell的’.cshrc’,BASH的’.bashrc’—這些檔案裡定義的變數都將影響你的程式。
你也可以將那些只在登入時用到的變數移到別的檔案裡,例如’.login’或者’.profile’。

4.5 程式的工作目錄
  每次你用run啟動程式時,程式都從GDB的當前工作目錄繼承工作目錄。GDB從它的父程序(通常是shell)那裡繼承工作
目錄,而你可以用cd在GDB裡指定一個新的工作目錄。
  GDB的工作目錄是GDB操作檔案時的預設目錄。參加按15.1節[檔案命令],155頁。
cd directory
    指定GDB的工作目錄為directory
pwd    列印GDB的工作目錄
  通常很難找到被除錯程式的當前工作路徑(因為它可以在執行的時候改變)。如果你是在支援’/proc’檔案系統的系統下
執行GDB的,你可以用info proc命令來查詢當前被除錯程式的工作目錄。(參見18.1.3節,[SVR4程序資訊],183頁)

4.6 程式的輸入輸出
  預設情況下,GDB裡執行的程式在與GDB相同的終端上輸入輸出。GDB會在和你互動的時候切換到它自己的終端模式,
不過它會記住你的程式的終端模式然後在繼續執行程式切換到那個模式上。
info terminal
    顯示GDB記錄的你的程式使用的終端模式。
  你可以用run命令重定向程式的輸入/輸出。例如:
    run > outfile
  開始執行程式,將列印輸出到檔案’outfile’。
  另外一個指定程式輸入輸出的命令是tty命令。這個命令接受一個檔名作為引數,然後將這個檔案作為接下來的
run命令的預設值。它也可以為子程序重置控制終端。例如:
    tty /dev/ttyb
將接下來run命令執行的程序的輸入輸出定向到’/dev/ttyb’,並將此作為控制終端。
run命令將改變tty命令對於輸入輸出的裝置的設定,但不改變其控制終端。
用tty命令或者在run命令裡重定向輸入只會影響你除錯的程式。GDB的輸入仍然來自於你的終端。tty是set inferior-tty的別名。
  你可以用show inferior-tty命令來趟GDB顯示程式將要使用終端名。
set inferior-tty /dev/ttyb
    將被除錯程式的tty裝置設定為/dev/ttyb
show inferior-tty
    顯示被除錯程式目前的tty裝置名

4.7 除錯一個已經在執行的程序
attach process-id
    這個命令attach到一個從GDB外啟動的程序上。(info files顯示你當前活躍的目標)這個命令需要一個進
    程id作為引數。通常用ps工具來找到一個Unix程序的ID,或者用’jobs -l’shell命令。
    在你執行attach命令之後,按下回車鍵attach將不會再次執行。
  只有在支援程序的環境下,attach命令才有效;例如,attach在沒有作業系統的裸機上市無效的。你必須有發給
程序送訊號的許可權。
  在你執行attach命令的時候,偵錯程式首先在當前工作目錄下查詢程序的可執行程式,如果沒有找到,接著會用源
程式碼檔案搜尋路徑(參見7.5節[指定原始碼目錄],70頁)。你也可以用file命令來載入可執行檔案。參見15.1節[
指定檔案的命令],155頁。
  GDB在準備好要除錯的程序後第一件事就是中斷這個程序。可以在run啟動的程序上的使用的命令也可以用在你
attach的程序上,你可以檢查,修改這個程序。你可以插入一個斷點;你可以step和continue;你可以修改儲存器。
如果你希望程序繼續執行,你可以在attach之後用continue命令來繼續。
detach
    在完成了除錯之後,可以用detach來釋放GDB對程序的控制。detach程序後,程序繼續執行。detach命令之
    後,程序和GDB就沒有關係了,你還可以attach到另外一個程序或者用run啟動一個程式。detach執行之後
    ,按下回車鍵不會再重複。
  如果你attach過一個程序,退出GDB會detach這個程序。如果你是用run命令啟動的話,你將kill這個程序。預設
的,GDB會要求得到你的確認;你可以用set confirm命令來控制是否需要確認(參見19.7節[可選的警告和訊息],213頁)。

4.8 殺死子程序
kill    殺死在GDB裡執行的子程序
  在你希望除錯一個core dump而不是程序的時候,這個命令很有用。在程式執行期間的時候,GDB會忽略core dump

  在某系作業系統,如果你在GDB裡為這個程式設定了斷點,這個程式就不能在GDB外運行了。你可以用kill命令來<br
/>讓程式在GDB外執行。
  在你執行程式的時候,kill命令也有助於重編和重新連線程式,而有些系統是不可能做到這個的。在這種情況下
,在下次執行run命令的時候,GDB可以知道程式已經發生變化了,就會重新讀取符號表(同時也會保留你目前的
斷點設定)。

4.9 除錯多執行緒程序
  在某些作業系統裡,例如HP-UX和Solaris,一個程式可能有多個執行緒。執行緒精確概念隨著各個作業系統而不一樣
,但大體上,一個有多個執行緒的程序和多程序相似,除了多執行緒共享一個地址空間(就是說,他們可以檢查和修改
同一個變數)。另一方面,每個執行緒有它自己的暫存器和執行棧,也可能有自己私有的儲存空間。
  GDB提供了多個除錯多執行緒的工具:
新執行緒的自動通知
‘thread threadno’,切換執行緒
‘info threads’,查詢執行緒
‘thread apply [threadno] [all] args’,對執行緒列表執行命令
執行緒特定斷點
‘set print thread-events’,控制執行緒開始和結束時列印訊息
  警告:在各個支援執行緒的作業系統裡,不是所有的GDB配置都支援這些工具的。如果你的GDB不支援執行緒,這個命
令就無效。例如,不支援執行緒的系統裡’info threads’命令就不能輸出資訊,也會拒絕thread命令,如下:
(gdb) info threads
(gdb) thread 1
Thread ID 1 not known. Use the “info threads” command to
see the IDs of currently known threads.
  GDB執行緒除錯工具可以觀察程序的所有執行緒,而一旦GDB控制執行緒的話,這個執行緒就總是除錯的焦點了。這個執行緒
稱為當前執行緒。除錯命令從當前執行緒的角度來顯示程序的資訊。
一旦GDB察覺到程序的新執行緒,GDB就會用‘[New systag]’的方式顯示目標系統的標識。systag是執行緒的標識,各
個系統不一樣。例如,當GDB發現一個新執行緒的時候,在GNU/Linux你可能看到
    [New Thread 46912507313328 (LWP 25582)]。
而在SGI系統裡,systag就簡單的形如‘process 368’,沒有更多資訊。
  出於除錯的目的,GDB自己會給執行緒一個編號–總是一個整數。
info threads
    顯示當前程序裡的執行緒的總概要。GDB顯示每個執行緒(以此為序):
    1.GDB分配的執行緒號
    2.目標系統的執行緒標識(systag)
    3.執行緒當前棧的概要
    執行緒號左邊的星號’*’代表此執行緒是當前執行緒。例如:
(gdb) info threads
3 process 35 thread 27 0x34e5 in sigpause ()
2 process 35 thread 23 0x34e5 in sigpause ()
* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
at threadtest.c:68
  在HP-UX系統裡:
  出於除錯目的, GDB為程序裡每個執行緒分配一個執行緒號(以執行緒建立順序分配小整數)。
  無論何時GDB察覺到一個新執行緒,它會用‘[New systag]’的形式顯示GDB自己的執行緒號和目標系統的執行緒標誌 。
systag是執行緒標識,各個系統下可能不同。例如,GDB察覺到新執行緒,在HP-UX,你能看到
    [New thread 2 (system thread 26594)]。
info threads
    顯示所有執行緒的概要。GDB顯示每一個執行緒(以此為序):
    1.GDB分配的執行緒 號
    2.目標系統的執行緒標識(systag)
    3.執行緒當前棧的概要
    執行緒號左邊的星號’*’代表此執行緒是當前執行緒。例如:
(gdb) info threads
    * 3 system thread 26607 worker (wptr=0x7b09c318 “@”)
        at quicksort.c:137
    2 system thread 26606 0x7b0030d8 in __ksleep ()
        from /usr/lib/libc.2
    1 system thread 27905 0x7b003498 in _brk ()
        from /usr/lib/libc.2
  在Solaris系統,那你可以用一個Solaris特有的命令來顯示更多的資訊:
maint info sol-threads
    顯示Solaris使用者執行緒的資訊。
thread threadno
    將threadno指向的執行緒設定為當前執行緒。這個命令的引數threadno是GDB內部的執行緒號,就是’info threads’
    命令顯示第一列。
    GDB會顯示你選擇的執行緒的系統標識和它當前棧的概要:
    (gdb) thread 2
    [Switching to process 35 thread 23]
    0x34e5 in sigpause ()
    伴隨著'[New…]’訊息,’Switching to’之後的文字形式由你的系統執行緒標識表示方式決定。
thread apply [threadno] [all] command
    thread apply命令可以讓你在一個或多個執行緒上執行名為command命令。用引數threadno指定你希望操作的
    執行緒數目。可以是單個執行緒號,’info threads’顯示的第一列;或者可以是執行緒範圍,像2-4.要操作所有
    執行緒,敲入thread apply all command。
set print thread-events
set print thread-events on
set print thread-events off
    GDB察覺到新執行緒啟動或執行緒結束的時候,set print thread-events命令可以開啟或關閉列印資訊。預設
    下,如果目標系統支援的話,這些事件發生的時候,這些資訊會打印出來。注意,這些資訊不一定在所有目
    標系統裡都可以關閉的。
show print thread-events
    顯示是否在GDB察覺執行緒啟動或結束時列印資訊。
  由斷點或者訊號決定,無論何時GDB停止程式,它都會選擇斷點或訊號發生的執行緒。GDB會用‘[Switching to syst
ag]’形式標識執行緒提示執行緒上下文的切換。
  更多關於GDB在停止啟動多執行緒程式的行為的資訊,參見5.4節[停止核啟動多執行緒程式],59頁。
  更多多執行緒程式觀察點的資訊,參見5.1.2[設定觀察點],44頁。

4.10 除錯多個程式
  在多數系統下,GDB沒有為能用fork呼叫建立附加程序的程式提供特殊的支援。程式建立子程序時,GDB會繼續除錯
父程序,而子程序則不受影響。如果你此前在子程序的程式碼上設定了一個斷點,則子程序會被SIGTRAP訊號結束。
  不過,如果你想除錯子程序的話,有一個不那麼麻煩的替代方案。在fork呼叫之後的子程序程式碼裡呼叫sleep調
用。如果sleep程式碼的呼叫由某些環境變數或者某個檔案的存在與否來決定,那就很方便了:如果你不想除錯子進
程,不設定這些變數或者刪除檔案就可以了。在子程序休眠的時候,用ps程式來得到程序id.接著用GDB attach到這
個子程序上,如果你正在除錯父程序,你需要新啟動一個GDB例項,參見4.7[Attach],30頁。你就可以如同attach到別的
程序那樣開始除錯子程序了。
  在某些系統上,GDB提供除錯用fork或vfork呼叫建立子程序的程式的支援。目前,只有HP-UX(11.x和以後版本)和
GNU/Linux(2.5.60核心版本及後續)提供這個功能的支援。
  預設的,在建立子程序的時候,GDB會繼續除錯父程序,而子程序不受影響。
  如果你要除錯子程序,用命令
set follow-fork-mode.
set follow-fork-mode mode
    設定偵錯程式對於fork或vfork呼叫的反應。fork或vfork建立一個子程序。mode引數可以是:
    parent    fork之後除錯原程序。子程序不受影
響。這是預設方式。
    child    fork之後除錯新的程序。父程序不受影響。
show follow-fork-mode
    顯示當前偵錯程式對於fork/vfork呼叫的反應。
  在Linux下,如果你要除錯父程序和子程序,用命令
set detach-on-fork.
set detach-on-fork mode
     設定GDB在fork之後是否detach程序中的其中一個,或者繼續保留控制這兩個程序。
    on    子程序(或者父程序,依賴於follow-fork-mode的值)會被detach然後獨立執行。這是預設mode。
    off    兩個程序都由GDB控制。一個程序(子程序或者父程序,依賴於follow-fork-mode)被除錯,另外
        一個則被掛起。
show detach-on-fork
    顯示detach-on-fork mode
如果你選擇了設定‘detach-on-fork’為off,那麼GDB會保持控制所有被建立的子程式(包括被巢狀建立的)。你
可以用info forks命令來顯示在GDB裡建立的子程序,然後用fork命令來從一個程序切換到另一個。
info forks
    列印在GDB控制下被建立的子程序列表。這個表包括fork id, 程序id和當前程序的位置(程式計數器)。
fork fork-id
    切換到fork-id指定的程序。引數fork-id是GDB內部為fork分配的,如命令’info forks’所顯示列表的第一
    列。
process process-id
    切換到process-id指定的程序。引數process-id必須是’info forks’輸出的。
  要想結束除錯一個被建立的程序,可以用detach fork命令(允許這個程序獨立的執行),或者用刪除(也殺死)
的方法delete fork命令。
detach fork fork-id
    detach一個由GDB標識的fork-id指定的程序,然後從fork列表裡刪除。這個程序會被允許繼續獨立執行。
delete fork fork-id
    殺死一個由GDB標識的fork-id指定的程序,然後從fork列表裡刪除。
  如果你要除錯一個vfork建立接著exec的程序的話,GDB會在這個新的目標上執行到底一個斷點。如果你在原來程式
的主函式上設定了一個斷點,子程序上的主函式上也有一個同樣的斷點。
  如果子程序正在執行vfork呼叫,你不能除錯子程序或者父程序。
  如果你在exec呼叫執行之後執行GDB的run命令,新目標會重新啟動。要重啟父程序,執行file命令,父程序可執行程式
名作引數。
  你可以用catch命令來在fork,vfork或者exec呼叫的時候讓GDB中斷。

4.11 為跳轉設定書籤
  在某些作業系統(目前只在GNU/Linux上),GDB可以儲存一個程式狀態的快照,稱為檢查點,以後可以跳回。
  跳回到檢查點會撤銷所有在檢查點之後的變化。這些變化包括記憶體,暫存器,甚至系統狀態(有些限制)。這樣可以
有效的及時回到在檢查點設定的狀態。
  因此,如果你單步除錯到你認為你接近到快要發生錯誤的地方,你就可以儲存一個檢查點。接著,如果你不經意的走的
太遠錯過了關鍵的狀態,你可以回到檢查點後再從那裡開始,而不需要從頭啟動程式。
  檢查點對於需要很長時間或者單步除錯裡bug發生地方很遠的情況下很有幫助。
  用checkpoint/restart方法除錯:
checkpoint
    儲存被除錯程式當前執行狀態的快照。checkpoint命令不需要引數,但每個檢查點都分配一個小整數標識,如同
    breakpoint標識一樣。
info checkpoints
    列出在當前被除錯會話的檢查點。對於每個檢查點,資訊顯示如下:
    Checkpoint ID
    Process ID
    Code Address
    Source line, or label
restart checkpoint-id
    在檢查點號的狀態上重新啟動。所有程式變數,暫存器,棧幀等等都恢復到檢查點上儲存的狀態。本質上將,gdb會
    把時鐘回撥到檢查點所記錄的時間。
    注意,斷點,GDB變數,命令歷史等不受檢查點重置的影響。通常,檢查點只重置被除錯程式內部的狀態,不影響偵錯程式
    本省的狀態。
delete checkpoint checkpoint-id
    刪除以前儲存的檢查點
  回到以前儲存的檢查點,會重置程式的使用者狀態,加上相當數量的系統狀態,包括檔案指標。重置不會撤銷已寫入檔案的資料,但
是會把檔案指標指向以前的文職,因此以前寫入的資料就可以被覆蓋。對於以只讀模式開啟的檔案,指標也會回到以前的位置,因此
可以重新讀取資料。
  當然,送到印表機(或者其它外設)的字元不能收回,而從別的裝置(比如串列埠裝置)裡讀取的資料可以從內部程式緩衝裡撤銷,
但是不能被塞回到序列管道里去,然後再讀取他們。相似的是檔案的內如如果被改變了,也不能被重置。
  然而,在這些約束條件下,你可以重新回到以前儲存的程式狀態去,重新除錯–然後你可以改變事件的過程來執行一個不同的路徑
除錯。
  最後,在你回到檢查點的時候,有些內部程式狀態會不一樣—程式的程序id。每個檢查點會有一個獨立的程序id(pid),每個都和原
來的pid不一樣。如果你的程式儲存了一個程序id的本地副本,這會有一個潛在的問題。

4.11.1 使用檢查點的隱含好處
  在某些系統裡(例如GNU/Linux),出於安全考慮,每個新程序的地址空間都要隨機確定。這就很難或者說不可能在一個絕對地址上
設定一個斷點或者觀察點,因為一個符號的絕對位置每次執行都不一樣。
  然而,一個檢查點是一個程序的相同的副本。因此如果你在主函式的入口點建立了一個檢查點,你可以避開地址空間的隨機化的影
響,而且符號也會呆在相同的位置。

如有版權問題,請聯絡QQ   858668791