6.4. Controlling a Process with GDB

6.4. Controlling a Process with GDB

GDB is designed to take control of a live process or to load a process image (a “core” file) into memory. In either case, GDB provides the ability to look at the contents of the memory for either a live process or the process image. When GDB is in control of a live process, it can also control the environment of the live process, change the memory used by the live process, or control how and when the live process is run. There are two ways to control a process and one way to get a process image into GDB:

GDB 旨在控制實時進程, 或者將進程映像 ("核心" 文件) 加載到內存中。無論是哪種情況, GDB 都提供了查看實時進程或進程映像的內存內容的能力。當 GDB 控制實時進程時, 它還可以控制實時進程的環境, 更改實時進程所使用的內存, 或者控制實時進程的運行方式和何時運行。有兩種方法可以控制進程, 還有一種方法可以讓進程映像進入 GDB:

1.

Run a program directly through the debugger. Using this method, GDB actually creates and runs a new process off the command line. 使用此方法, GDB 實際上在命令行上創建並運行一個新進程。

2.

Attach to a running process. Using this method, GDB attaches to an existing process. 使用此方法, GDB 附加到現有進程。

3.

Use a core file for post-mortem analysis. When using a core file, there is no live process, but there is a process image. A process image, or core file, contains the contents of memory for a process that was once running. 使用核心文件時, 沒有實時進程, 但存在進程映像。進程映像或核心文件包含曾經運行的進程的內存內容。

Figure 6.1. Methods to get a process into GDB.

 

 

Regardless of how GDB gains control of a process (running a program directly off the command line or attaching to a live process), the resulting state is the same. GDB will have full control over the live process.

無論 GDB 如何獲得對進程的控制 (直接從命令行運行程序或附加到實時進程), 結果狀態都是相同的。GDB 將完全控制實時進程。

All three methods of using GDB will be explained in more detail.

所有使用 GDB的三種方法將在下面詳細地解釋。

6.4.1. Running a Program Off the Command Line with GDB

You should run a program through GDB if you want to be in control of the program from the beginning of its execution. For example, you might need to set a breakpoint (explained further down) in a function that gets run immediately after the program starts up. This could be for a C/C++ program where a function is simply called soon after the start up of a program or for a C++ program where some global constructors are triggered even before the main() function is called.

如果你想從它的執行開始控制程序,你應該通過 GDB運行一個程序 。例如, 您可能需要在程序啓動後立即運行的函數中設置斷點 (後面解釋)。這可能是一個 c/c++ 程序, 其中一個函數在程序啓動後很快就被調用, 或者對於 c++ 程序, 即使在調用 main () 函數之前也會觸發一些全局構造函數。

To run a program from within GDB, simply use GDB with the program as the only argument. When you first run GDB in this way, the program isn’t actually started until you run it with the run command inside GDB. If you call run without setting a breakpoint, the program will run normally until it exits or hits a trap. Here is a quick example:

要從 gdb 內部運行程序, 只需使用 gdb 作爲唯一的參數。當您第一次以這種方式運行 GDB 時, 程序實際上不會啓動, 直到您使用 gdb 內部的 run 命令運行它。如果在不設置斷點的情況下調用 run, 程序將正常運行, 直到它退出或命中陷阱爲止。下面是一個示例:

Code View: Scroll / Show All

penguin> g++ hang.C -g -o hang

penguin> gdb hang

GNU gdb 5.2.1

Copyright 2002 Free Software Foundation, Inc.

gdb is free software, covered by the GNU General Public License, and

you are welcome  to change it and/or distribute copies of it under

certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for  gdb.  Type "show warranty" for

details.

This gdb was configured as "i586-suse-linux"...

(gdb) break main

Breakpoint 1 at 0x804843c: file hang.C, line 10.

(gdb) run user

Starting program: /home/wilding/src/Linuxbook/hang

 

Breakpoint 1, main (argc=1, argv=0xbffff104) at hang.C:10

10     getpid( ) ; // a system call to show that we've entered this code

(gdb) list

5

6

7      int main( int argc, char *argv[] )

8      {

9

10     getpid( ) ; // a system call to show that we've entered this code

11

12     if ( argc < 2 )

13     {

14     printf( "hang (user|system)" ) ;

 

In this example, the program was run inside of GDB with the command run user. The command run was used to run the program, and the user argument is passed as the first and only argument to the program. From the program’s point of view, it is identical to being run from the shell as hang user (hang is the name of the program).

在此示例中, 程序在 GDB 內部運行, 並使用命令run user。命令run用於運行程序, user參數作爲程序的第一個和唯一參數傳遞。從程序的角度來看, 它與從 shell 運行hang user相同 (hang是程序的名稱)。

The command break main was used to set a breakpoint on the function main(). This is the first user-code function called in normal C programs and for C++ programs that do not have global objects to initialize. The term “user-code” is used to describe the code that would be compiled for the application and does not include the operating system functions that may be called in addition, such as the Run Time Linker functions (refer to the ELF chapter for more details on the Run Time Linker). Because the program was compiled with -g, it contains debug information that allows the debugger to identify the lines of code in the main function. Unless you’re debugging the constructors of global C++ objects, the main function is a good way to stop the debugger at the beginning of the program execution.

命令break main 用於在函數main () 上設置斷點。這是在正常 c 程序中調用的第一個用戶代碼函數, 對於沒有要初始化全局對象的 c++ 程序,main()也是第一個要調用的函數。術語 "用戶代碼" 用於描述將爲應用程序編譯的代碼, 並且不包括可能調用的操作系統內核函數, 如運行時Run Time Linker函數 (有關運行時的更多詳細信息, 請參閱 ELF 章節。鏈接器)。因爲程序是用 -g 編譯的, 所以它包含調試信息, 使調試器能夠識別main函數中的代碼。除非正在調試全局 c++ 對象的構造函數, 否則 main 函數是在程序執行開始時停止調試器的好選擇。

You can also use the args GDB variable to set the command line arguments instead of including them behind the run command. This is particularly useful if the command line arguments are long and difficult to type in. With the args variable, you can set the command line arguments once and then use run on its own from then on. Here is short example to show how this works:

您還可以使用參數 GDB 變量來設置命令行參數, 而不是將它們包括在 run 命令後面。如果命令行參數長且難於鍵入, 則這一點特別有用。使用參數變量, 您只需設置命令行參數一次, 然後後面就可以一直使用。下面是一個簡短的例子來說明這是如何工作的:

(gdb) show args

Argument list to give program being debugged when it is started is "".

(gdb) set args 6 7

(gdb) show args

Argument list to give program being debugged when it is started is "67".

(gdb) run

 

In the preceding example, the program is executed as if from a shell prompt with arguments 6 and 7 as the first and second arguments, respectively.

在前面的示例中, 程序就像從 shell 提示符中運行一樣, 其中的參數6和7分別爲第一個和第二個參數。

Environment variables are another way in which the user can affect the execution of a program. Because GDB provides a controlled environment for a program in which to run, the environment variables can be manipulated as well. The command show environment will display the current environment just as the env command would in a bash shell. To set an environment variable, use the set environment command with a variable=value pair. To unset a variable use the unset environment command. This is shown in the following example:

環境變量是用戶可能影響程序執行的另一種方式。因爲 GDB 爲運行中的程序提供了受控環境 , 環境變量也可以操作。命令show environment將顯示當前環境, 就像env命令將在 bash shell 中一樣。若要設置環境變量, 請使用set環境變量,設置variable = value對。若要取消設置變量, 請使用 unset環境變量命令。下面的示例顯示了這一點:

(gdb) set environment FOO=BAR

(gdb) show environment FOO

FOO = BAR

(gdb) unset environment FOO

(gdb) show environment FOO

Environment variable "FOO" not defined.

(gdb)

Note: When using Emacs editing mode, to save some typing, use TAB command completion. Typing “env<TAB>” will complete environment for you. GDB also accepts short forms for all commands. If you don’t know the short form, start with the first letter and work up from that:

注意: 使用 Emacs 編輯模式時, 若要保存某些類型, 請使用 TAB 鍵補全命令。鍵入 "env<TAB>" 將爲您提供完整的environment。GDB 還接受了所有命令的短格式。如果您不知道短格式, 請從第一個字母開始, 然後從以下內容中進行操作:

     (gdb) show e FOO

     Ambiguous show command "e FOO": editing, endian, environment,

     eventdebug, exec-done-display.

     (gdb) show en FOO

     Ambiguous show command "en FOO": endian, environment.

     (gdb) show env FOO

     Environment variable "FOO" not defined.

     (gdb)

6.4.2. Attaching to a Running Process

Attaching to a running process with GDB is usually done when it is difficult to get a process in the debugger at a key point in its execution. For example, there are situations where the startup procedure for an application is complex in that it forks or execs other processes, and you want to attach to one of the forked or exec’ed processes only. You might also need to attach to a process that is only started in a client-server modeled application. In other words, a remote client might start a local process you cannot start manually from a command line. Another example of when it is useful to attach to a process is when a problem has already occurred and you need to attach to the process to debug it.

使用 GDB 附加到正在運行的進程比較容易完成,但是在調試器執行過程中很難獲得一個進程的關鍵時刻。例如, 在某些情況下, 應用程序的啓動過程是複雜的, 因爲它將生成子進程或執行其它程序, 並且您只想附加到子進程或被執行的一個進程。您可能還需要附加到僅在客戶端-服務器模式的應用程序中啓動的進程。換言之, 遠程客戶端可能啓動一個本地進程, 您無法從命令行手動啓動。另一個示例是問題已經發生,需要附加到進程以調試它。

To demonstrate attaching GDB to a running process, let’s use the little hanging program, hang, again:

爲了演示如何將 GDB 附加到正在運行的過程, 讓我們使用hang程序:

penguin> hang system

 

This simply causes the hang process to hang in a system call so that we can attach to the process with GDB:

這隻會導致掛起進程掛在系統調用中, 這樣我們可以附加到 GDB 的進程中:

Code View: Scroll / Show All

penguin> gdb - 3051

GNU gdb 5.2.1

Copyright 2002 Free Software Foundation, Inc.

gdb is free software, covered by the GNU General Public License, and

you are  welcome to change  it and/or distribute copies of  it under

certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for gdb. Type "show warranty" for

details.

This gdb was configured as "i586-suse-linux"...-: No such file or

directory.

Attaching to process 3051

Reading symbols from /home/wilding/src/Linuxbook/hang...done.

Reading symbols from /usr/lib/libstdc++.so.5...done.

Loaded symbols for /usr/lib/libstdc++.so.5

Reading symbols from /lib/libm.so.6...done.

Loaded symbols for /lib/libm.so.6

Reading symbols from /lib/libgcc_s.so.1...done.

Loaded symbols for /lib/libgcc_s.so.1

Reading symbols from /lib/libc.so.6...done.

Loaded symbols for /lib/libc.so.6

Reading symbols from /lib/ld-linux.so.2...done.

Loaded symbols for /lib/ld-linux.so.2

0x4019fd01 in nanosleep () from /lib/libc.so.6

(gdb) bt

#0  0x4019fd01 in nanosleep () from /lib/libc.so.6

#1  0x4019fbd9 in sleep () from /lib/libc.so.6

#2  0x080484a7 in main (argc=2, argv=0xbffff134) at hang.C:24

#3  0x4011a4a2 in __libc_start_main () from /lib/libc.so.6

(gdb) up

#1  0x4019fbd9 in sleep () from /lib/libc.so.6

(gdb) up

#2  0x080484a7 in main (argc=2, argv=0xbffff134) at hang.C:24

24            sleep( 5000 ) ;

(gdb) list

19         {

20            while ( 1 ) ;

21         }

22         else if ( !strcmp( argv[1], "system" ) )

23         {

24            sleep( 5000 ) ;

25         }

26

27         return 0 ;

28      }

 

 

                                     

 

The process is stopped, as expected, at the point where the process was hung. There is no need to set a breakpoint because the program will simply stop where it was when GDB attached to it. In this case, of course, the process was already stopped.

進程在掛起的點上按預期停止。沒有必要設置斷點, 因爲程序在 GDB 附加到它時會停止。當然, 在這種情況下, 進程已經停止。

Notice that there is no line number displayed for nanosleep(). This is because this function is in libc.so.6, which was not compiled with -g. Running bt to get the stack trace shows the line of code in function main() is 24. The up command was used twice to walk up the stack until the debugger was looking at the stack frame where source code was available.

請注意, 沒有爲 nanosleep () 顯示行號。這是因爲此函數在 libc.so. 6中, 與-g編譯. 運行 bt 獲取堆棧跟蹤顯示函數sleep在 main () 中的行號爲24。在調試器查看源代碼可用的棧幀之前, up命令使用了兩次來遍歷棧。

6.4.3. Use a Core File

Core files are often used to debug programs and applications on Linux and Unix-based operating systems. Core files are useful for debugging because they contain the memory image of the process at the time when the core file was created. A core file contains the process heap, the stack, and any writable memory segments that were in a process’ address space. A core file can be used long after a problem occurs to debug a problem in a debugger such as GDB.

core文件通常用於在 Linux 和類 Unix 的操作系統上調試程序。core文件對於調試很有用, 因爲它們包含創建core文件時進程的內存映像。core文件包含進程堆、棧以及進程 "地址空間" 中的任何可寫內存段。當在調試器 (如 GDB) 中調試問題時, 可以長時間使用core文件。

Core files can also be useful for situations where a problem has to be debugged remotely and cannot be reproduced on any system but the original. In such a case, core files can be transferred to another system for analysis as long as the libraries’ versions used by the process are the same on the other system.

core文件對於需要遠程調試問題且不能在任何系統上覆現問題的情況也很有用。在這種情況下, 只要進程使用的庫版本與其他系統上相同, core文件就可以轉移到另一個系統進行分析。

The kernel will automatically create a core file if a process traps with a signal such as SIGSEGV and if the resource limits allow it. To demonstrate the generation of core files, let’s use a very simple program that dereferences a NULL pointer. The source code for this program is:

如果進程捕獲到信號 (如 SIGSEGV) 和資源限制允許, 內核將自動創建核心文件。爲了演示core文件的生成, 讓我們使用一個非常簡單的程序來訪問 NULL 指針。此程序的源代碼爲:

int main( void )

{

   int *trap = 0;

 

   *trap = 1;

 

   return 0;

}

 

When running this program, we get the following output:

運行此程序時, 我們得到以下輸出:

   penguin> simple_trap

   Segmentation fault

   penguin> ls -l core

   /bin/ls: core: No such file or directory

 

So why was no core file generated? The answer lies in the shell’s default resource settings. For a bash shell, we can view and manipulate these settings with the ulimit command. To see a listing of all current settings, use the -a parameter:

那麼爲什麼沒有生成core文件呢?答案在於 shell 的默認資源設置中。對於 bash shell, 我們可以使用 ulimit 命令查看和設置。要查看所有當前設置, 請使用-a 參數:

penguin> ulimit -a

core file size           (blocks, -c) 0

data seg size            (kbytes, -d) unlimited

file size                (blocks, -f) unlimited

max locked memory        (kbytes, -l) unlimited

max memory size          (kbytes, -m) unlimited

open files                       (-n) 1024

pipe size             (512 bytes, -p) 8

stack size               (kbytes, -s) unlimited

cpu time                (seconds, -t) unlimited

max user processes               (-u) 7168

virtual memory           (kbytes, -v) unlimited

Note: The command ulimit is built into the bash shell. For different shells, the command and its output may differ.

注意: 命令 ulimit 內置在 bash shell 中。對於不同的 shell, 命令及其輸出可能會有所不同。

 

According to the output, the core file size is limited to 0 blocks, meaning that no core files will be generated for traps. To generate a core file, we need to increase this limit. Bash’s ulimit output is nice because it displays the command line parameter to use for each setting in parentheses after the units of size. Setting the core file size to unlimited and rerunning our program gives us this output:

根據輸出, core文件大小限制爲0塊, 這意味着不會爲陷阱生成core文件。要生成core文件, 我們需要修改這個限制。Bash 的 ulimit 輸出做得很好, 因爲它顯示可用的命令行參數, 以顯示括號的單位顯示設置的大小。將core文件大小設置爲 "無限制" 並重新運行我們的程序將提供以下輸出:

penguin> ulimit -c unlimited

penguin> simple_trap

Segmentation fault (core dumped)

penguin> ls -l core

-rw———    1 dbehman  users         53248 2004-09-12 10:36 core

Note: If you always want core files to be generated for programs that produce traps, add the ulimit - unlimited command to your $HOME/ .profile bash startup script. This is assuming you use bash; the command and startup script will differ for other shells.

注意: 如果您希望爲產生陷阱的程序生成core文件, 請將 ulimit 無限制的命令添加到您的 $HOME/.profile bash 啓動腳本中。這是假設你使用 bash;對於其他 shell, 命令和啓動腳本將有所不同。

 

If you want to know what is in a core file, you can quickly peek into the core file by running readelf -all core. For more information about the contents of the core file, refer to the ELF chapter (Chapter 9).

如果您想知道core文件中的內容, 可以通過運行 readelf –all core 快速查看核心文件。有關core文件內容的詳細信息, 請參閱 ELF 章節 (9 章)。

When you have a core file, you just need to get it into GDB along with the application for which the core was generated. Here are the simple steps using the core file just generated:

當你有一個core文件, 你只需要把它與生成的core文件的軟件一起放到GDB中。下面是使用剛生成的core文件的簡單步驟:

penguin> gdb simple_trap core

GNU gdb 5.3.92

Copyright 2003 Free Software Foundation, Inc.

gdb is free software, covered by the GNU General Public License, and

you are welcome to change it and/or distribute copies of it under

certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for gdb. Type "show warranty" for

details.

This gdb was configured as "i586-suse-linux"...

Core was generated by 'simple_trap'.

Program terminated with signal 11, Segmentation fault.

Reading symbols from /lib/i686/libc.so.6...done.

Loaded symbols for /lib/i686/libc.so.6

Reading symbols from /lib/ld-linux.so.2...done.

Loaded symbols for /lib/ld-linux.so.2

#0 0x08048326 in main () at simple_trap.c:5

5         *trap = 1;

(gdb)

 

After GDB has fully read the core file, the process will look exactly the same as if we had run the simple_trap program inside of GDB on the command line. The core file gives us the advantage of easily seeing the trapped state of the process at any time on any machine without the need to run the program again.

在 GDB完全讀取了core文件之後, 該過程看起來就好像我們在命令行的 GDB 中運行了 simple_trap 程序一樣。core文件使我們能夠輕鬆地在任何計算機上隨時查看被捕獲的進程狀態, 而無需再次運行該程序。

Because a core file is not a running process, you can’t use any of the execution commands in GDB given the program is not actually running. There is no live process to control. The rest of the commands, including all of the ones that examine or print memory, will work as if there were a live process being controlled by GDB.

由於core文件不是正在運行的進程, 因此, 程序實際上沒有運行, 不能使用 GDB 中的任何可執行命令。沒有要控制的實時進程。其餘的命令, 包括所有檢查或打印內存的命令,,就像有一個實時進程被 GDB 控制一樣,工作得很好。

6.4.3.1. Changing Core File Name and Location

In some cases, you want to set the location where the core files on the system get saved to. One reason for doing this is to prevent core files from being scattered throughout the file system. Another reason is that more complex applications that manipulate the user permissions and directory locations internally while running may not have proper access to generate a core file in their respective default locations.

在某些情況下, 您希望設置系統上的core文件存儲的位置。這樣做的一個原因是防止核心文件分散在整個文件系統中。另一個原因是, 在運行時在內部操作用戶權限和目錄位置的更復雜的應用程序可能沒有正確的權限在各自的默認位置生成core文件。

To control the naming of core files generated, the /proc/sys/kernel/core_pattern control file is used. Note that this is a 2.6 kernel feature, though it is very likely that your distribution has back-ported it to its 2.4 based kernels. SuSE Linux Professional 9.0 and SuSE Linux Enterprise Server 8, for example, both have this control file. As an example, let’s say we want all core files to be generated in /core_files and have their names made up of the process name, the user ID running the process, and the process ID. First, as root, ensure that the /core_files directory exists and is fully writeable by any user. Then execute the following:

爲了控制生成的core文件的命名, 使用了/proc/sys/kernel/core_pattern 控制文件。請注意, 這是一個內核2.6的功能, 但很可能是您的發行版已將其移植到其2.4 內核。例如, SuSE linux 專業版9.0 和 SuSE linux 企業服務器版 8, 都有這個控制文件。例如, 假設我們希望在/core_files 中生成所有的core文件, 並使其名稱由進程名稱、運行進程的用戶 id 和進程 ID 組成。首先, 作爲 root 用戶, 確保/core_files 目錄存在, 並且由任何用戶完全可寫。然後執行以下操作:

echo "/core_files/%u.%e.%p.core" > /proc/sys/kernel/core_pattern

 

Now when rerunning our simple_trap program, we will see the following:

現在, 當重新運行我們的 simple_trap 程序時, 我們將看到以下內容:

Code View: Scroll / Show All

penguin> ls -l /core_files

total 52

-rw———       1 dbehman     users       53248 2004-09-12 11:22 500.simple_trap.12589.core

 

Refer to the proc(5) man page for a detailed explanation of what core-pattern can be set to.

請參閱prco (5) 幫助手冊, 詳細說明core模式。

6.4.3.2. Saving the State of a GDB Session

If you had attached GDB to a running process or run the program through GDB from the command line, you may have had the desire to save the current state of the debugging session to a file. Reasons for doing this would be to resume the debugging session at a later time or to transfer the debugging session to a co-worker on another system. In any case, GDB has a useful command that creates a core file from within a GDB session:

如果您已將 GDB 附加到正在運行的進程中, 或者通過 gdb 從命令行運行該程序, 則可能希望將調試會話的當前狀態保存到文件中。這樣做的原因是以後恢復調試會話, 或者將調試會話轉移到另一個系統上的同事。在任何情況下, gdb 都有一個有用的命令, 可以在 gdb 會話中創建core文件:

(gdb) help generate-core-file

Save a core file with the current state of the debugged process.

Argument is optional filename. Default filename is 'core.<process_id>'.

(gdb) generate-core-file

Saved corefile core.13112

(gdb)

 

This core file is in the same format as if the kernel produced it directly and can be loaded using the technique explained previously.

此core文件與內核直接生成它的格式相同, 可以使用前面解釋的技術進行加載。

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