GDB 7.0 中文手册 —— 4. 在GDB中运行程序

GDB最新的手册,每天翻译一些。

虽水平有限,望造福大家

转贴请注明出处:

http://blog.csdn.net/benson_linux/archive/2009/11/14/4811577.aspx


英文原文:
http://sourceware.org/gdb/current/onlinedocs/gdb_toc.html

 


 

4. 在GDB中调试程序

 

如果想在GDB下调试一个程序,那个编译这个程序时,需要生成调试信息。根据需要,我们可以带参数或不带参数的启动GDB,如果是本地调试,你可以重定向被调试程序的输入输出,或调试一个已经运行的程序,还可以杀掉子进程。

  • Compilation:编译时加入调试信息
  • Starting:启动你的待调试程序
  • Arguments:待调试程序的参数
  • Environment:待调试程序的运行环境
  • Working Directory:待调试程序的工作目录
  • Input/Output:待调试程序的输入输出
  • Attach:调试一个正在运行的程序
  • Kill Process:杀掉子进程
  • Inferiors and Programs:Debugging multiple inferiors and programs
  • Threads:调试多线程程序
  • Forks:调试forks
  • Checkpoint/Restart:设置书签以便之後返回

 

 

4.1 编译时加入调试信息

 

为了让程序能够有效的调试,编译时我们需要加入调试信息。这些调试信息保存在目标文件中(object file);包含每个变量或函数的数据类型,和执行码与源代码之间的相应位置。

 

怎么加入调试信息呢?编译的时候加上‘-g’选项就行了。

 

那些将要发行的程序,一般都会使用‘-O’选项进行编译优化。然而,一些编译器不能同时支持'-g'和’-O’选项,使用这些编译器时,我们无法得到既能够调试,又是经过优化的执行程序。

 

GCC,GNU的C/C++编译器,就能够同时支持'-g'和'-O'选项,这样我们就可以得到支持调试的经过优化的执行文件。所以我们建议不论任何时候编译,都加上'-g‘选项。毕竟程序往往不能像我们想的那么顺利运行。更多信息,参考Optimized Code (代码优化)。

 

老版本的GNU C编译器,支持一种变形的调试信息选项'-gg'。GDB不再支持这种格式了,不要在使用了。

 

GDB知道代码中的预处理宏和对应的展开式(参考Macros )。对于大部分编译器来说,仅仅指定'-g'标志,并不会在调试信息中包含宏信息,因为它们太庞大了。3.1以后的GCC版本,如果编译时指定了'-gdwarf-2’和'-g3‘,会加入这些宏的信息。调试信息格式要求是Dwarf 2的,并且第二个选项还要求额外信息。将来,希望能够找到更合适的方法来表示宏信息,这样就能用'-g’选项来搞定一切了。

 


 

 

4.2 启动待调试程序

 

run

r

在GDB中用run命令启动被调试程序,我们首先需要通过GDB参数(参考Getting In and Out of GDB ),或者file或exec-file命令(参考Commands to Specify Files )给出被调试程序的名字(VxWorks平台除外)。

如果你在一个支持进程的环境中运行程序,run命令会创建一个子进程运行被调试程序。在某些没有进程的环境中,run命令跳到被调试程序的开始处。像'remote'一样的其他目标则总是运行。如果你收到这样的错误信息:

     The "remote" target does not support "run".
     Try "help target" or "continue".

那就用continue命令来运行被调试程序。当然你可能需要先做load(参考load )。

 

程序的运行会受父进程传入的信息的影响。GDB提供了多种方法来设置这些信息,当然你必须在启动被调试程序之前设置。(我们也可以在启动之后设置,不过这要等到重启程序时才有效。)这些信息可以分为4类:

 

The arguments

指定给被调试程序的参数可以作为 run 命令的参数。如果你的目标环境中有shell,那么shell会被用来传递参数,所以那些shell支持的常规用法(像通配符、变量替换),这里也可以用。在Unix系统中,可以通过SHELL环境变量设置使用那个shell。参考Your Program's Arguments

The environment

通常被调试程序会继承GDB的环境变量,不过我们也可以用GDB的“set environment”和“unset environment”命令来修改部分影响被调试程序运行的环境变量。参考Your Program's Environment

The working directory

被调试程序会继承GDB的工作目录。我们也可以用GDB的cd命令设置GDB的工作目录。参考Your Program's Working Directory

The standard input and output

通常被调试程序会和GDB使用同样的标准输入输出设备。我们也可以在run命令行中,重定向输入输出,或者使用tty命令设置被调试程序自己的终端设备。参考Your Program's Input and Output

 

警告:当输入输出重定向起作用时,你不能用管道将被调试程序的输出连接到另外一个程序;如果你这么做了,不管你的程序是否产生输出,GDB里的被调试程序都会马上退出,并且exit code非零。例如,命令“run | more”就会产生这样的错误(并不是你的程序真的有问题)。

一旦你执行了run命令,你的被调试程序就会立即开始运行。参考Stopping and Continuing ,了解如何停止程序。一旦你的程序停止运行,就可以通过print或者call命令,调用被调试程序中的函数。参考Examining Data

 

GDB读入符号后,如果你的符号文件的修改时间发生了变化,GDB将会丢弃已有的符号表,然后重新读入并更新。当然,GDB干这些活时,它会尽量保留你当前的断点信息。

 

start

主函数的名字随着语言的不同而不同,在C/C++中,主函数的名字一般都是main,不过在Ada等其他语言中,并不要求主函数用一个固定的名字。对于不同的语言,调试器提供了很简单的方法启动被调试程序,和在主函数的第一条指令处停止运行。

 

“start”命令等同于在主函数的开始加入一个临时断点,然后执行“run”命令。

 

某些程序包含一些初始化代码段,这些代码段早于主函数运行,当然这些都取决于你使用的编程语言。例如,在C++中,静态变量和全局对象的构造函数就在主函数之前运行,因此也就有可能使调试器在主函数之前就产生中断。无论如何临时断点都会保留以便暂停被调试程序的运行。

 

通过给‘start’命令指定参数,可以设置被调试程序的参数。这些参数将会原封不动的传递给‘start’命令背后的‘run’命令。注意,如果之后使用的'start'或者‘run'参数不带参数的话,已经设置的参数将会默认使用。

 

当需要调试程序的初始化代码段时,使用’start‘命令中断程序可能有些来不及,那么干脆就程序运行之前,在你的初始化代码段中加入断点。(貌似C++代码不能调试构造函数?)

set exec-wrapper wrapper

show exec-wrapper

unset exec-wrapper

设置了'exec-wrapper'(还是保留吧,译不好,我想叫做执行程序外壳)时,指定的外壳程序将会引导被调试程序的运行。GDB通过'exec wrapper program '的shell方式启动你的程序(这里wrapper 就是那个指定的外壳程序,program 就是你的被调试程序)。GDB会自动给program 和它的参数加上引号,但不给wrapper 加,所以shell需要的话,你得自己给wrapper 加上引号。wrapper程序会一直运行到被调试程序启动,然后GDB接手控制权。

 

我们可以使用任何最终调用execve(以传入的参数,作为execve的参数)系统函数并推出的程序作为外壳。很多标准就是例子,如env和nohup。任何以'exec "$@"'结束的Unix shell脚本也行。

 

举个例子理解一下,我们可以用env来给被调试程序传入环境变量,而不用在我们的shell中设置环境变量:

本命令适用于很多平台的本地调试,包括DJGPP,Cygwin,MS Windows,和QNX Neutrino。

set disable-randomization

set disable-randomization on

gdb默认会开启这个选项,来关闭调试程序的内存虚拟地址随机排布的特性。本选项对于同时启动多个一样的调试会话很有用,能优化被调试程序的多次启动,提高它们之间的内存空间的复用。(内存地址随机排布的内容,可以参考这篇贴子:http://blog.csdn.net/drshenlei/archive/2009/07/11/4339110.aspx,很不错)

 

这个功能只在GNU/Linux平台有效,使用下边的命令也能获得同样效果:

 

set disable-randomization off

保持启动的被调试程序的加载方式。有些bug只会在执行程序加载到特定地址的时候才会出现。如果你的bug在GDB调试环境中运行时不见了,就很有可能是因为在一些平台上,GDB默认的禁止了地址空间的随机排布。例如GNU/Linux上,系统为每个独立的进程采用内存地址随机排布的方式。试试用‘set disable-randomization off’来重现这种bug。

 

目前只有在GNU/Linux平台上实施了虚拟地址空间随机使用技术,这有助于避免进程遭到安全性攻击。这种情况下,攻击者需要知道具体执行码的准确位置。随机化分布执行执行码地址后,基本不可能轻易的插入跳转语句,执行一段恶意代码。

 

提前链接动态库提高了程序启动的速度。不过这也使特权进程在这些库中的地址变得可以预测,很简单,只要在目标系统上让非特权的进程访问这些动态库。解析这些动态库的二进制文件能够获得足够的信息,来汇编恶意代码并运行它们,就算程序启动时执行一个常规的重定向处理,就能使一个预链接的动态库重新载入一个随机地址。没有预链接的动态库总是会被加载到一个随机选择的地址。

 

位置无关可执行程序(PIE)含有位置无关代码,有点像动态库,因此启动时这些代码会被随机加载到一个地址上。就算是预链接的动态库,PIE执行程序通常也会把它们加载到一个随机的地址上。通过使用“gcc -fPIE -pie”可以编译得到这样的程序。

 

堆(malloc申请的空间),栈和程序中的mmap区域通常都是随机分配的地址(只要激活了随机化处理)

show disable-randomization

打印当前配置中,已启动程序中虚拟地址空间的随机化功能的详细禁止信息。

 


 

4.3 待调试程序的参数

 

待调试程序的参数可以通过GDB的命令行来指定。这些命令行参数会先传入一个shell中,处理通配符和I/O重定向操作,并从shell中将处理后的参数传入待调试程序。SHELL变量的值(如果有的话)用来指定gdb中使用的shell。如果你的环境中没有定义SHELL变量,gdb使用默认的shell(/bin/sh 在Unix系统中)。

 

在非Unix系统上,程序往往被gdb直接调用,并通过相应的系统调用执行I/O重定向,通过待调试程序的启动代码展开通配符,而不是shell。

 

不带参数的run命令会传入上次运行run命令时的参数,或者通过set args命令设置的参数。

set args

指定下次待调试程序运行时的参数。如果set args没有参数,那么运行待调试程序时也没有参数。一旦你通过run启动待调试程序时添加了参数,那么在下次run之前使用set args是唯一的让待调试程序不带参数启动的方法。

 

show args

打印程序启动时将传入的参数。

 


 

4.4 Your Program's Environment

 

SHELL环境由一系列环境变量名值对组成。环境变量能很方便的记录你的用户名、主目录、终端类型和命令搜索路径这样的配置信息。一般情况下,你可以在shell中设置这些环境变量,然后让shell中运行的程序继承这些变量,这对于调试程序的就很有用了,不需要重启gdb,直接修改环境变量,然后再次运行被调试程序就能生效。

path directory
    Add directory to the front of the PATH environment variable (the search path for executables) that will be passed to your program. The value of PATH used by gdb does not change. You may specify several directory names, separated by whitespace or by a system-dependent separator character (`:' on Unix, `;' on MS-DOS and MS-Windows). If directory is already in the path, it is moved to the front, so it is searched sooner.

    You can use the string `$cwd' to refer to whatever is the current working directory at the time gdb searches the path. If you use `.' instead, it refers to the directory where you executed the path command. gdb replaces `.' in the directory argument (with the current path) before adding directory to the search path.


show paths
    Display the list of search paths for executables (the PATH environment variable).


show environment [varname]
    Print the value of environment variable varname to be given to your program when it starts. If you do not supply varname, print the names and values of all environment variables to be given to your program. You can abbreviate environment as env.


set environment varname [=value]
    Set environment variable varname to value. The value changes for your program only, not for gdb itself. value may be any string; the values of environment variables are just strings, and any interpretation is supplied by your program itself. The value parameter is optional; if it is eliminated, the variable is set to a null value.

    For example, this command:

              set env USER = foo
         

    tells the debugged program, when subsequently run, that its user is named `foo'. (The spaces around `=' are used for clarity here; they are not actually required.)


unset environment varname
    Remove variable varname from the environment to be passed to your program. This is different from `set env varname ='; unset environment removes the variable from the environment, rather than assigning it an empty value.

Warning: On Unix systems, gdb runs your program using the shell indicated by your SHELL environment variable if it exists (or /bin/sh if not). If your SHELL variable names a shell that runs an initialization file—such as .cshrc for C-shell, or .bashrc for BASH—any variables you set in that file affect your program. You may wish to move setting of environment variables to files that are only run when you sign on, such as .login or .profile. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值