GDB手册7:检查源文件

第一章 一个GDB会话样例
第二章 进入和离开GDB
第三章 GDB 命令
第四章 在GDB里运行程序
第五章  中断和继续
第六章 检查栈

7 检查源文件
  由于程序里记录的调试信息告诉GDB程序是由哪些文件编译的,GDB可以打印程序各部分源文件。程序
中断时,GDB同时自动打印是在哪一行上中断的。同样,当选择一个堆栈帧时(参见6.3节[选择帧],64页),
GDB也打印那个帧上的执行是在哪一行里中断的。用显式的命令可以打印源文件别的信息。
  如果通过GNU Emacs接口来用GDB,可以优先选择Emacs工具来查看源代码;参见23章[在GNU Emacs里用GDB],
233页。

7.1 打印源代码行
  要打印源文件里的代码行,用list命令(缩写为l)。缺省的,一次打印十行。有几个方式可以指定你希望
打印文件的哪部分;完整列表,参见7.2节[指定位置],68页。
  下面是命令list最常用的形式:
list linenum
    以当前行为中心,打印当前源文件linenum行。
list function
    以函数function开头为中心打印源文件。
list    打印更多行。如果用list命令打印过源文件行,list命令将会在打印的最后一行代码下接着打印;否则
    ,如果最近打印的源代码行是单独的一行,作为显示堆栈帧的一部分的话,list命令将已这一行为中心
    开始打印文件代码。
list -    只打印最近已打印的代码行前的代码。
  缺省的,用上述形式的list命令,GDB打印十行源代码。可以用set listsize改变:
set listsize count
    设置list命令显示count行源代码(除非list命令明确指定其它的数字)。
show listsize
    显示list打印行的数量。
  用回车键省略参数的重复list命令,和只输入list相等。和列出相同的代码行相比更有用。参数是’-'的list命
令是例外;这个参数是用来重复执行的,每次执行都会在源文件里向上打印。
  总之,list命令期待用户提供0,1或者2的行定义。行定义指定源代码行;有多种方式来制定(参见7.2节[指定位置]
,68页),不过其效果都是制定某些源代码行。
  下面是list命令的完整的参数描述:
list linespec
    以linespec为中心打印源代码。
list first,last
    从first开始打印到last。两个参数都是行定义。当list命令有两个行定义时,并且第二个行定义的源文
    件省略了的话,两个行定义指的是在同一个文件里的代码。
list ,last
    打印到last行。
list first,
    从first开始打印
list +    只打印最近打印行后的代码
list -    只打印最近打印行前的代码
list    如前所述。

7.2 指定位置
  有多个GDB命令接受指定程序代码位置的参数。由于GDB是源代码级的调试器,位置通常指的是源代码里的某一
行;因此,位置通常是指行定义。
  下面是GDB所能识别的代码位置的指定方式:
linenum    指定当前源文件的行数量linenum
-offset
+offset    指定从当前行偏移offset。对于list命令,当前行是最经打印过的;对于断点命令,是当前选定的
    堆栈帧上的执行中断处(堆栈帧的描述,参见6.1节[帧],61页)。要是用做list命令的两个行定义
    的第二个参数,指定的是从第一个行定义开始的向上或向下的偏移。
filename:linenum
    指定源文件filename的行号。
function
    指定行从函数function为开始。例如,在C里,行是开括号{。
filename:function
    指定行从文件filename里的函数function开始。要是有多个文件里有相同名字的函数的话,只需要用
    文件名加上函数名就可以避免混淆了。
*address
    指定程序地址address。对于行导向的命令,例如list和edit,这个参数指定位置为address的源代码行。
    对于break和其它断点导向的命令,这个参数可以在不带调试信息或没有源文件的程序部分里设置断点。
    这里address可以是当前工作语言(参见12章[语言],119页)的任意有效的指定代码位置的表达式。另外
    ,GDB扩展了用于位置的表达式的语义,以此包含在调试过程中经常碰到的情况。下面是address的各种
    形式:
    expression
        当前工作语言的任意有效表达式。
    funcaddr
        函数的地址或源自名字的过程的地址。在C,C++,Java,Object-C,Fortran,微指令和汇编里
        这个参数是函数名function(或者是一个有效表达式的一个特例)。在Pascal和Modula-2,是
        &function。在Ada里,是function’Address(虽然Pascal形式也可用)。
        这中形式指定函数第一个指令的位置,这个位置是在堆栈帧和参数建立前的。
    ‘filename’::funcaddr
        和上面的funcaddr类似,不过还指定了源文件名。这个形式在只指定函数名会造成歧义的时候很
        有用,例如,如果在不同的文件里有多个函数都具有相同的名字时。

7.3 编辑源文件
  要编辑源文件里的内容,用edit命令。你选择的编辑程序将被调用,并将程序里的当前行设置为激活行。另外,
有几种方式可以指定你希望打印文件的哪部分,如果你要想看程序的其它部分的话。
edit location
    编辑指定为location的源文件。编辑从location开始,例如,在指定文件的指定行赏。参见7.2节[指定位
    置],68页,所有位置参数的可能形式;下面是edit命令最常用的形式:
    edit number
        将行number作为激活行编辑文件。
    edit function
        编辑包含函数function的文件,在其定义的开头开始编辑。
7.3.1 选择编辑器
  GDB可以定制你所期望的任意编辑器(注1)。缺省的,是’/bin/ex’,但你可以在运行GDB前,设置环境变量
EDITOR来改变。例如,要配置GDB实用vi编辑器,在sh shell里用下面的命令:
    EDITOR=/usr/bin/vi
    export EDITOR
    gdb …
(注1,唯一的限制在于,你的编辑器要识别如下命令行语义:ex +number file
  可选的数值+number指定文件的行号。

  或者在csh shell里,
    setenv EDITOR /usr/bin/vi
    gdb …

7.4 搜索源文件
  有两个命令可以用正则表达式在当前文件里搜索。
forward-search regexp
search regexp
    命令’forward-search regexp’检查每一行,从最近列出的行开始,查找正则表达式regexp的匹配项。命
    令列出找到的行。也可以用同义词’search regexp’或缩写命令为fo.
reverse-search regexp
    命令’reverse-search regexp’检查每一行,从最近列出的行往后,查找正则表达式regexp的匹配项。命
    令列出找到的行。缩写为rev。

7.5 指定源文件目录
  可执行程序有时并不记录源文件编译的目录,只记录名字。即使它们记录了,目录也可能在编译和调试期间被移
动了。GDB一个目录列表来搜索源文件;这些目录称为源代码路径。每次GDB需要源文件时,它都会尝试在所有的目
录列表里搜索,以它们在列表里的顺序进行,直到GDB找到所查询的文件。
  例如,假设一个可执行文件引用了文件’/usr/src/foo-1.0/lib/foo.c’并且我们的源代码路径是’/mnt/cross’。
GDB首先会从字面上去查找;如果失败了,会在’/mnt/cross/usr/src/foo-1.0/lib/foo.c’里查找;如果还是失败
,会查找’/mnt/cross/foo.c’;如果再失败的话,会打印一个错误消息。GDB不会查找部分的路径名,例如
‘/mnt/cross/src/foo-1.0/lib/foo.c’。类似的,源代码路径的子目录也不会搜索:如果源代码路径是
‘/mnt/cross’,并且二进制文件引用了’foo.c’,GDB不会去’/mnt/cross/usr/src/foo-1.0/lib’路径下查找。
  简单文件名,带先导路径的相对文件名,包含点的文件名(点文件)等等,都如上所述查找;比如,如果源代码
路径是’/mnt/cross’,并且像’../lib/foo.c’这样记录的话,GDB会首先尝试’../lib/foo.c’,接着
‘/mnt/cross/../lib/foo.c’,最后是’/mnt/cross/foo.c’。
  注意,可执行文件搜索路径不用于定位源代码文件。
  无论何时你重新设置或组织了源代码路径,GDB会清除任何缓存的关于路径和文件行的信息。
  当你启动GDB时,它的源代码路径只包含’cdir’和’cwd’,且以此顺序排列。要增加其它目录,用directory命令。
  搜索路径用于查找程序源文件和GDB脚本文件(读用’-command’选项和’source’命令)。
  除了源文件路径,GDB提供了一些命令来管理源代码路径列表替换的规则。替换规则说明了在编译和调试期间目
录被移动的情况下,如何来重写存储于程序调试信息里的源代码目录。一个规则是由两个参数组成的,第一个参数
指定需要重写的路径,第二个参数指定这个路径如何重写。在[设置替换路径],72页里,我们将这两个部分命名为
from和to。GDB简单的用to将from的源文件名的开头目录部分替换掉,并用替换后的结果来搜索源文件。
  还用前例,假设’foo-1.0′目录树已从’/usr/src’移动到’/mnt/cross’,然后让GDB用’/mnt/cross’替换所有路径
的’/usr/src’。首先在路径’/mnt/cross/foo-1.0/lib/foo.c’查询,替代原来的路径’/usr/src/foo-1.0/lib/foo.c’。
要定义一个源代码路径替换规则,用set substitute-path命令(参见[设置替换路径],72页)。
  要避免意外的替换结果,规则只在目录名的from部分以目录分隔符结尾的情况下才应用。例如,用’/usr/source’
替换’/mnt/cross’的话,会得到’/usr/source/foo-1.0′,而不是’/usr/sourceware/foo-2.0′。并且替换规则只应
用于目录名的开头部分,这个规则不会得到’/root/usr/source/baz.c’的结果。
  在很多情况下,可以用directory命令来达到相同的效果。然而,在源文件分布于一个复杂的,带有多个子目录
的目录树时,set substitute-path会更有效率。用directory命令的话,用户需要添加项目的每一个子目录。如果
将整个目录移动且保持内部代码组织的话,那么set substitute-path允许你只用一个命令就可以将调试器导向到
所有的源文件。
  set substitute-path也不仅仅只是一个快捷命令。源代码路径只用于原目录下的文件不再存在的情况下。另一
方面,set substitute-path修改调试器行为模式来在重写的位置上搜索文件。所以,如果有任何原因导致源代码
文件相对于可执行程序的位置发生了改变,替换规则是唯一可以通知GDB新位置的方法。
directory dirname …
dir dirname …
    在源代码路径前加上目录dirname。可以将几个目录名传递给这个命令,用’:'分隔(在MS-DOS和
    MS-Windows是’;',’:'通常是一个绝对路径名的一部分),或者用空格分隔。可以指定已存在的目录;这
    会将此目录前移,GDB就能更快的搜索到它了。
    可以用字符串’$cdir’来指代编译目录(如果已记录的话),’$cwd’指代当前工作目录。’$cwd’和’.'不相
    同—前者记录在GDB调试会话期间变动的当前工作目录,后者则在你将一个目录添加进源代码路径时立即
    展开为当前目录。
directory
    将源代码路径重置为默认值(Unix系统下是’$cdir:$cwd’)。这个命令要求确认。
show directories
    打印源代码路径:显示包含那个目录。
set substitute-path from to
    定义一个源代码路径替换规则,并将其填加到当前替换规则列表的尾部。如果有相同的from规则存在的话
    ,那么旧的规则就会被删除。
    例如,如果文件’/foo/bar/baz.c’移动到’/mnt/cross/baz.c’,那么命令
        (gdb) set substitute-path /usr/src /mnt/cross
    告诉GDB用’/mnt/cross’替换’/usr/src’,这就可以让GDB查找到’baz.c’,即使它已经移走了。
    如果定义了多个替换规则,那么GDB会以规则定义的顺序一个接一个的计算它们。如果有的话,第一个匹
    配项就会进行替换。
    例如,如果我们输入了下列命令:
        (gdb) set substitute-path /usr/src/include /mnt/include
        (gdb) set substitute-path /usr/src /mnt/src
    GDB会用第一个规则将’/usr/src/include/defs.h’用’/mnt/include/defs.h’替换。不过,它会用第二个
    规则将’/usr/src/lib/foo.c’用’/mnt/src/lib/foo.c’替换。
unset substitute-path [path]
    如果指定了path的话,在当前替换规则列表里搜索要重置的规则。如果找到的话就删除之。如果没有找到
    的话,调试器会输出一个警告信息。
    如果没有指定path的话,那么所有的替换规则都将被删除。
show substitute-path [path]
    如果指定了path,那么打印打印源代码路径替换规则,如果有的话。
    如果没有指定path,那么打印所有的替换规则。
  如果源代码路径混杂着一些不再有用的目录的话,GDB可能在某些情况下造成错误的代码版本的混淆。可以用下
列命令来纠正这种错误:
1.用不带参数的directory命令来重置源代码路径为默认值。
2.用带正确参数的directory来添加你需要的目录。可以用一个命令将所有的路径添加。

7.6 源代码和机器代码
  可以用命令info line将源代码映射到程序地址上(反过来一样),命令disassemble可以显示一定范围的机器指
令。在GNU Emacs模式下运行时,info line命令会引起箭头指向指定的行。而且,info line打印符号形式的地址
,也打印16进制的地址。
info line linespec
    打印指定的源代码行的编译代码,从开始到结尾的地址。可以指定源代码行,7.2节[指定位置],68页里
    讨论的任意形式。
  例如,我们可以用info line来查找函数m4_chagequote的第一行的目标代码:
    (gdb) info line m4_changequote
    Line 895 of “builtin.c” starts at pc 0×634c and ends at 0×6350.
我们也可以查询(用*addr作为linespec的形式)哪一行源代码对应一个特定的地址:
    (gdb) info line *0×63ff
    Line 926 of “builtin.c” starts at pc 0×63e4 and ends at 0×6404.
  在info line后,x命令的缺省地址就变为这行的开头地址,所以’x/i’足以开始检查机器代码(参见8.5节[检查
内存],79页)。而且,这个地址也存储与变量$_里(参见8.9节[便利的变量],89页)。
disassemble
    这个命令将一段内存作为机器指令转储。缺省的内存范围是选定堆栈帧的程序计数器所代表的函数。单个
    参数的话是程序计数器的值;GDB转储值个值附近的函数。两个参数指定要转储的地址范围(第一个是开
    始,第二个是结束)。
  下面的例子显示了反汇编一个HP PA-RISC 2.0上的一段代码:
    (gdb) disas 0×32c4 0×32e4
    Dump of assembler code from 0×32c4 to 0×32e4:
    0×32c4 <main+204>: addil 0,dp
    0×32c8 <main+208>: ldw 0×22c(sr0,r1),r26
    0×32cc <main+212>: ldil 0×3000,r31
    0×32d0 <main+216>: ble 0×3f8(sr4,r31)
    0×32d4 <main+220>: ldo 0(r31),rp
    0×32d8 <main+224>: addil -0×800,dp
    0×32dc <main+228>: ldo 0×588(r1),r26
    0×32e0 <main+232>: ldil 0×3000,r31
    End of assembler dump.
  某些架构有多个通用的指令助记符或者同义词。
  对于动态链接的和使用共享库的程序,调用函数或位于共享库的分支位置的指令可能显示伪地址–这个地址是重
定位表的位置。在某些架构里,GDB可以将这些伪地址映射到函数名上。
set disassembly-flavor instruction-set
    用disassemble或x/i命令反汇编程序时,选择指令集。
    目前这个命令只在Intel x86族平台上定义。可以设置指令集为intel或att。默认是att,基于x86系统的
    Unix汇编器默认使用AT&T风格。
show disassembly-flavor
    显示当前反汇编风格的设置。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值