gdb review data

来源:互联网 发布:淘宝买眼镜靠谱吗 编辑:程序博客网 时间:2024/06/05 17:11

http://zhiwei.li/text/2010/01/gdb%E6%89%8B%E5%86%8C8%E6%9F%A5%E7%9C%8B%E6%95%B0%E6%8D%AE/

 

在程序里查看数据的常用方式是用print命令(缩写为p),或者用它的同义命令inspect。print命令会计算和打印用程序语言写的表达
式的值(参见12章[不同语言下使用GDB],127页)。
print expr
print /f expr
    expr是表达式(用程序语言写的)。缺省情况下,expr的值会以它的数据类型相近的格式打印;也可以用’/f’选择不同的格式,f是
    格式描述符;参见8.5节[输出形式],85页。
print
print /f
    如果省略了expr,GDB将显示最后一次的值(从值的历史记录里;参见8.9节[值历史记录],96页)。这个命令允许用户方便的换
    一种格式查看相同值。
  用x命令可以在更低层次上查看数据。x命令检验一个指定位置上的数据,并且以指定格式打印出来。参见8.6节[查看内存],87页。
  如果对数据类型感兴趣的话,或者想知道一个结构体或类里的一个域是如何声明的话,用ptype expr命令取代print命令就可以做到了。
参见13章[查看符号表],151页。

8.1 表达式
 print 很许多其他GDB命令一样接受一个表达式作为参数并且计算它的值。在GDB里,程序里定义的任意类型的常量,变量或者操作符都是有效的表达式。包括条件表 达式,函数调用,类型转换和字符串常量。也包括预定义宏,如果在编译程序时包含了的话;参见4.1节[编译],25页。
  GDB支持用户输入的表达式里包含数组常量。语法是{element,element…}。例如,可以用命令print {1,2,3}来在内存里建立一个数组,
而这个数组是目标系统里在自由堆里分配的。
  由于C应用的如此广泛,因此本手册里的大多数例子里的表达式都是用C写的。关于在其它语言里如何使用表达式的信息,参见12章[不同语言下使用GDB],119页。
  在这节里,讨论可用于GDB表达式的与编程语言无关的操作符。
  GDB支持下列操作符,另外还有其它编程语言可以通用的操作符:

@    ‘@’是二进制操作符,将一块内存作为数组。更多信息,参见8.3节[伪数组],77页。
::    ‘::’可以指定一个文件或函数里定义的变量。参见8.2节[程序变量],76页。
{type} addr
    引用存储于addr位置上的type类型的对象。addr可能是一个表达式,其值是一个整型或是指针(但需要圆括号来进行类型转换)。
    无论在addr地址上存储的数据是何种类型,这个用法都是允许的。

8.2 程序变量
 在程序里,最常用的表达式类型是使用变量的名字。
  表达式里的变量应理解为存储与一个特定的堆栈帧里(参见6.3节[选择一个帧],64页);变量可以是下列两种:
·全局变量(或是文件里的静态变量file-static)
·根据编程语言的变量生存规则,在当前执行的堆栈帧上是可见的变量
这意味着在函数
    foo (a)
        int a;
    {
        bar (a);
        {
            int b = test ();
            bar (b);
        }
    }
程序在函数foo里执行时,用户可以检查和使用变量a,但只能在程序执行于b声明的块内(函数bar)使用或检查变量b。
  有一个例外:可以引用生存期是单个文件的变量或函数,即使当前执行点不在这个文件上。不过,很有可能有多个变量
或函数有相同的名字(在不同的源文件)。如果那样的话,引用重名的变量可能会有预想不到的效果。如果需要,可以
指定一个特定函数或文件的静态变量,用双冒号(::)标记:
    file::variable
    function::variable
这里的file或function是这个静态变量的上下文的名字。对于文件名,可以用两个单引号将文件名包起以让GDB将其作为
一单个词分析–例如,要打印’f2.c’文件里定义的全局变量x:
    (gdb) p ’f2.c’::x
  与在C++相同符号的用法相比,C的’::’ 的用法很少有冲突。GDB也支持C++生存期操作符。
    警告:偶尔的,一个本地变量可能在函数的某些点上显示错误的值–在进入一个新的生存期后和在离开前。
  在用机器指令单步跟踪程序的时候,可能碰到这个问题。这是因为,在大多数机器里,需要多于一个的指令才能建立一个
堆栈帧(包括本定变量定义);如果你是用机器指令来单步跟踪的话,变量就可能显示错误的值,直到堆栈帧完全建立为止。
在退出时,通常也需要多个机器指令才能销毁堆栈帧;在你开始单步执行通过这组指令的过程中,本地变量的定义可能已经
消失了。
  这个问题也可能在编译器做了显著优化的时候碰到。要确保总是得到精确的值的话,在编译时关闭优化选项。
  编译器优化结果所带来的另一个潜在影响是将没有用到的变量优化掉了,或者叫爱那个变量存储于寄存器(而不是内存地址
上)。由于依赖于编译器提供的调试信息格式对于此类问题的支持,GDB可能不能显示这些本地变量的值。如果真的这样,GDB
会打印类似如下的消息:
    No symbol “foo” in current context.
  要解决这些问题,要么不带优化选项重新编译,要么使用一个不同的调试信息格式,如果编译器支持多种格式的话。例如,
GCC,GNU C/C++编译器,通常支持’-gstabs+’选项。’-gstabs+’产生优于普通调格式(如COFF)的调试信息。可以用DWARF 2
(’-gdwarf-2′),这也是一个有效的调试信息格式。参见节”调试程序或GCC的选项”。参见12.4.1节[C和C++],123页,更多关于
最佳C++程序调试信息格式的信息。
  如果需要打印一个GDB未知其内容的对象,例如,由于调试信息没有完全说明它的数据类型,GDB会打印’<incomplete type>’。
更多信息,参见13章[符号],143页。
  字符串是定义为无符号的char数组。signed char或unsigned char会以1字节宽度的整形数组打印。由于GDB定义字符串类型type
‘char’为无符号类型,-fsigned-char或-funsigned-charGCC选项不会起效。对于程序代码
    char var0[] = “A”;
    signed char var1[] = “A”;
  可以在调试时得到下列信息
    (gdb) print var0
    $1 = “A”
    (gdb) print var1
    $2 = {65 ’A’, 0 ’\0’}

8.3 伪数组
  打印几个在内存里连续的相同类型的对象,常常是很有用的;数组的一节,或一个动态决定大小的数组,在程序里只有一个指针存在。
  用二进制操作符’@'将一个连续的内存区域作为伪数组,可以达到这个目的。’@'的左操作数应该是目标数组的第一个元素,并且是一个
单独的对象。右操作数应该是目标数组的长度。结果是整个数组的值,其元素都是左操作数的类型。第一个元素是左操作数;第二个元素
在内存中数紧邻着第一个元素,依此类推。下面是一个例子。如果程序
    int *array = (int *) malloc (len * sizeof (int));
可以用下面命令打印数组的内容
    p *array@len
  ‘@’的左操作数必须存在于内存中。用’@'打印的数组值和用其它下标索引得到的值一样,并且会在表达式里强制转换为指针。伪数组
常常通过值历史在表达式里出现(参见8.8节[值历史],88页),在打印过后。
  另一种创建伪数组的方法是使用强制转化。转化会将一个值作为一个数组对待。这个值不一定在内存里:
    (gdb) p/x (short[2])0×12345678
    $1 = {0×1234, 0×5678}
  为方便起见,如果不指定数组长度(如’type[]value’),GDB会计算这个伪数组合适的长度(如’sizeof(value)/sizeof(type)’):
    (gdb) p/x (short[])0×12345678
    $2 = {0×1234, 0×5678}
  有时伪数组机制还不够;在相当复杂的数据结构里,结构体里的元素可能不是真的相邻–例如,如果你需要的元素在结构体里声明为指
针。一个有用的变通方法(参见8.9节[惯用变量],89页)是在表达式里使用惯用变量作为计数器,记录第一个值,然后通过回车键重复执行表达式。例如,假设有一个结构体数组名为dtab,其结构体定义了一个指针fv。下面是一个使用dtab的例子:
    set $i = 0
    p dtab[$i++]->fv
    <RET>
    <RET>
    …

8.4 输出格式
  缺省的,GDB根据数据类型打印数据值。不过,有时这种方式可能不是你想要的。例如,你可能要以16进制打印一个数值,或者以10进
制打印一个指针。或者你想要查看内存中某个地址上的数据,作为字符串或者一个指令。要做到这些,在打印值的时候指定输出格式就可
以了。
  最简单的输出格式的用法是指定如何打印一个已计算过的值。要达到这个目的,在命令print后加上反斜杠’/'和一个格式符号就可以。
格式符号如下:
x    将数值作为整型数据,并以16进制打印。
d    打印带符号整型数据
u    打印以无符号整型数据
o    以8进制打印整形数据
t    以2进制打印整形。’t'代表’two’(注一).
注一:’b'不能用,因为这个格式在x命令里也用到了,x命令里’b'代表’byte’;参见8.5节[查看内存],79页。
a    打印地址,打印16进制的绝对地址和最近符号的偏移量。可以用这个格式找出一个未知地址的位于何处(在哪个函数里):
        (gdb) p/a 0×54320
        $3 = 0×54320 <_initialize_vx+396>
    命令info symbol 0×54320也能得到相似的结果。参见13章[符号]143页。
c    将一个整型以字符常量打印。会打印一个数值和它表示的字符。超出7位的ASCII的数值(大于127)的字符用8进制的数字替代打
    印。
    不用这个格式的话,GDB将char,unsigned char和signed char数据作为字符常量打印。单字节的向量成员以整型数据打印。
f    将数据以浮点类型打印。
s    如果可能的话,以字符串形式打印。用这个格式,指向单字节数据的指针将以nll结尾的字符串打印,单字节数据的数组则会
    以定长字符串打印。其它的值以它们原本类型打印。
    不用这个格式的话,GDB将指向char,unsigned char和signed char作为字符串打印,这些类型的数组也同样处理。单字节向量
    的成员以整型数组打印。
  例如,要以16进制打印程序计数器(参见8.10节[寄存器],90页),输入
    p/x $pc
注意,在反斜杠前不需要空格;这是由于GDB里的命令名不能包含一个反斜杠。
  要用其它格式打印最近值历史里的值,可以用print命令带一个格式就可以了,不用指定表达式。例如,’p/x’会以16进制打印最近的
值。

8.5 查看内存
  可以用命令x(表示”examine”)以多种格式查看内存,而和程序数据类型无关。
x/nfu addr
x addr
x    用x命令查看内存。
  n,f和u都是可选的参数,指定打印多长的内存数据和以何种格式打印之;addr是需要打印的内存的地址表达式。如果用默认的nfu,不
需要输入反斜杠’/'。有几个命令可以方便的设置addr的默认值。
n,重复次数
    10进制整数;默认是1。指定显示多长的内存(需要和单元长度u一起计算得到)。
f,显示格式
    显示格式和print命令的格式一样(’x',’d',’u',’o',’t',’a',’c',’f',’s'),外加’i'(表示机器指令格式)。默认是’x'(16
    进制)。默认格式在用x或print命令的时候都会改变。
u,单元大小
    单元大小如下:
    b    字节
    h    2节节
    w    4字节。默认值。
    g    8字节。
    每次用x指定单元长度,这个长度就成为默认值,知道下一次用x再设置。(对于’s'和’i'格式,单元长度会被忽略而不会改写)
addr,要打印的起始位置
    addr是要GDB开始打印的内存起始位置。表达式不需要指针值(虽然其可能是一个指针值);这个表达式总会翻译为内存中一个
    字节的整型地址。参见8.1节[表达式],75页,更多关于表达式的信息。默认的addr通常是紧随最近查看地址之后–但其它几个
    命令也可以设置默认地址:info breakpoints(设置为最近断点的地址),info line(设置一行代码的起始地址),和print(
    如果用了print来显示内存中的一个值)。
  例如,’x/3uh 0×54320′打印3个半字(6字节)的内存数据,以10进制整型格式打印(’u'),从地址0×54320开始。’x/4xw $sp’打印4
个字(’w')的内存数据,以16进制从堆栈指针指向的内存开始(这里’$sp’;参见8.10节[寄存器],90页)打印。
  由于制定单元长度的字符和制定输出格式的字符是截然不同的,因此不需要记住单元长度和格式字符的先后顺序;无论哪个在先都可以
。输出格式声明’4xw’和’4wx’是一样的。(不过,次数n必须在先;’wx4′就是无效的。)
  即使对于格式’s'和’i'来说单元长度u是忽略不计的,用户也可能要用一个计数n;例如,’3i’指定要看3个机器指令,包括操作数。为方便起见,特别 是在用display命令时,’i'格式会超过计数所知定的长度打印延迟转移槽指令,如果有的话,这个转移指令就紧接在计数长度的指令之后。 disassemble命令提供了另一种查看机器指令的方式;参见7.6节[源代码和机器代码],72页。
  x命令的全部缺省参数都为方便的继续扫描内存而设计的,这样每次继续使用x命令的时候就只需要很少的指定了。例如,用’x/3i addr’命令查看机器指令后,可以只用’x/7′来查看下7个指令。如果用回车键来重复x命令的话,就会重复n次;其它参数就成为接下来的x命令的缺省 值。
  由于x命令打印的地址和内容通常是非常多而且可能会变成瓶颈,因此不会在值历史里保留。 相反,GDB将那些在后续表达式里用到的值形成惯用变量$_和$__。一个x命令之后,最后被查看的地址可以用惯用变量$_来在表达式里引用。这个地址的 内容,如前所查,可以用变量$__来引用。如果x命令带有重复次数参数,地址和内容会保存最后打印的内存单元;如果有多个单元在最后一行打印的话,就不是 记录最后打印的地址。
  如果调试一个在远程机器上运行的程序(参见17章[远程调试],179页),你可能希望确认和下载到远程机器上的可执行文件相比的内存中的程序文件。compare-sections命令提供了这样的功能。
compare-sections [section-name]
    用可执行文件里的名为section-name的可加载段数据和远程机器内存中相同的段数据比较,并且打印不匹配的数据。如果不带参数,比
   较所有的可加载段数据。这个命令的可用性依赖于系统对于”qCRC”远程请求的支持与否。

8.7 自动显示
  如果你觉得需要频繁打印一个表达式的值(来查看其如何改变的),可能要把它加到自动显示列表里让GDB在每次程序中断时打印这个表达式的值。每个加入列表的表达式会有一个编号来标识;要将一个表达式从列表里删除,可以用这个编号。自动显示如下所示:
2: foo = 38
3: bar[5] = (struct hack *) 0×3804
这个输出显示了条目编号,表达式和它们目前的值。如同你手工用x或print命令那样打印输出那样,可以指定你喜欢的输出格式;事实上
display命令决定是用print还是用x命令,这取决于你指定的格式–如果你指定了’i'或者’s'格式的话,或者有一个单元长度的话,就用x;
否则就用print。
display expr
    将表达式expr加入表达式列表,每次程序中断时自动显示。参见8.1节[表达式],75页。
    在时候此命令后再按回车键时,display不会重复执行。
display/fmt expr
    fmt只指定显示格式,不指定大小和次数,将表达式expr加入自动显示列表;每次用指定格式fmt输出。参见8.4节[输出格式],
    78页。
display/fmt addr
    对于’i'或者’s'格式,或者包含一个单元长度或一个单元数量的话,将表达式addr作为一个要查看的内存地址加入列表,每次程
    序中断的时候打印。”查看”用’x/fmt addr’命令来实现。参见8.5节[查看内存],79页。
  例如,要在每次执行中断时查看机器指令,’display/i $pc’就很有用的(’$pc’是程序计数器的通用名;参见8.10节[寄存器],90页)。
undisplay dnums…
delete display dnums…
    从显示列表中删除编号为dnums的显示项。
    在执行undisplay后再回车的话,undisplay不会重复。(否则你会得到’No display number….’的错误信息)
disable display dnums
    禁用编号为dnums的显示项。禁用的显示项不会自动输出,但系统仍会记录它。可以再次激活。
enable display dnums…
    激活编号为dnums的显示项。会再次自动显示其表达式的值,直到你禁用它。
display
    显示当前列表中的变大是的值,就如同程序中断那样输出。
info display
    打印此前设置的自动显示列表里的表达式,每个表达式带一个编号,但不显示其值。包括禁用的表达式,这类表达式会标明为禁
    用。也包括目前不能显示的表达式,这类表达式引用了当前不可用的自动变量。
  如果显示表达式引用了本地变量,那么在其设置范围外是没有意义的。在执行到其变量无定义的上下文时,这类表达式会被禁用。
例如,如果你在一个函数内执行了命令display last_char,last_char是此函数的参数,GDB会在程序再次执行到这个函数并在此函数中断
时自动显示此参数。要是在别的位置中断的话–那里没有变量last_char–就会将此显示项自动禁用。下次程序在last_char有意义的位置中
断时,可以再次激活这个显示表达式。

8.7 打印设置
  GDB提供如下数组,结构体和符号的打印设置方法。在任何语言里下列设置对于调试都是很有用的:
set print address
set print address on
    GDB打印内存地址,显示堆栈回溯的位置,结构体的值,指针值,断点等等,甚至在其也显示哪些地址上的内容时。缺省是on。
    例如,下面是用set print address on来设置后,堆栈帧的输出:
        (gdb) f
        #0 set_quotes (lq=0x34c78 “<<”, rq=0x34c88 “>>”)
        at input.c:530
        530 if (lquote != def_lquote)
set print address off
    在现实其值的时候不打印地址。例如,下面是用set print address off设置后相同的堆栈帧的输出:
        (gdb) set print addr off
        (gdb) f
        #0 set_quotes (lq=”<<”, rq=”>>”) at input.c:530
        530 if (lquote != def_lquote)
    可以用’set print address off’来从GDB接口中取消所有机器相关的显示。例如,使用print address off,可以在所有机器上
    得到相同的内容的回溯–不论时候牵涉到指针参数。
show print address
    显示是否打印地址。
  GDB打印符号的地址时,通常会打印离此地址最近且位置靠前的符号,外加打印偏移。如果符号不能指定位置的地址(例如,在一个文
件里的一个名字),你就需要确认它。一个确认的方法是用info line,例如’info line *0×4537′。另外一方法是,在打印一个符号的地
址时设置GDB要打印的源文件和行号:
set print symbol-filename on
    设置GDB要打印的符号的源文件名和行号。
set print symbol-filename off
    不打印符号的源文件名和行号。默认方式。
show print symbo-filename
    显示是否打印符号的源文件名和行号。
  显示符号文件名和行号的另外一种有用的情况是,在反汇编代码时打印文件名和行号。GDB会显示相应于每个指令的行号和源文件。
  另外,你可能希望确认被打印地址的符号形式是否是离得最近且位置考前的符号:
set print max-symbolic-offset max-offset
    设置GDB只显示地址的符号形式,如果偏移是在最近且靠前的符号和比max-offset低的地址区间。缺省值是0,GDB总是打印比
    此地址靠前的符号。
show print max-symbolic-offset
    显示GDB打印一个符号地址的最大偏移量。
  如果有一个指针但不能确定它指向何处,可以用’set print symbol-filename on’来尝试。然后用’p/a pointer’来确认此指针指向的
名字和源文件的位置。这个命令可以将地址转换为符号形式。例如,下面是GDB显示的变量ptt指向另一个变量t,于’hi2.c’定义:
    (gdb) set print symbol-filename on
    (gdb) p/a ptt
    $4 = 0xe008 <t in hi2.c>
    警告:对于执行一个本地变量的指针,’p/a’不显示涉及到符号名和文件名,即使是把相关的set print选项打开也如此。
  其他设置控制如何打印不同类型的对象的方法如下:
set print array
set print array on
    以习惯方式打印数组。这个格式更便于阅读,但要更多空间。默认是关闭的。
set print array off
    返回到压缩方式打印数组。
show print array
    显示何种方式显示数组。
set print array-indexes
set print array-indexes on
    在打印数组的时候打印每个数组成员的下标。可以方便的找到一个给定的数组成员的位置,或者查找一个给定成员的下标。缺省
    是关闭的。
set print array-indexes off
    在现实数组时,不打印数组成员下标。
show print array-indexes
    显示在打印数组时是否输出成员下标。
set print elements number-of-elements
    设置GDB打印的数组成员的数量。如果GDB打印一个大数组,在打印完set print elements命令设置的限制之后就不再继续打印此
    数组成员。这个限制也会应用于字符串打印。GDB启动时,这个限制设置为200。将number-of-element设置为0意味着打印数组时
    没有长度限制。
show print elements
    显示GDB打印大数组的长度。如果是0,那么没有限制。
set print frame-arguments value
    这个命令允许控制在调试器打印一个堆栈帧的时候,如何打印参数的值(参见6.1节[帧],61页)。可能的值:
    all    打印所有的参数值。缺省的。
    scalars    只打印非向量参数。复杂的参数如数组,结构体,联合等,用…替代。下面是非向量参数的打印例子:
        #1 0×08048361 in call_me (i=3, s=…, ss=0xbf8d508c, u=…, e=green)
        at frame-args.c:23
    none    不打印参数。所有的参数都用…替代。下面是这样的例子:
        #1 0×08048361 in call_me (i=…, s=…, ss=…, u=…, e=…)
        at frame-args.c:23
    缺省的,总是打印所有的参数。不过这个命令在好几情况下是非常有用的。例如,在打印每个帧时可以用来减少输出的信息,使
    得回溯更加可读。而且,在打印Ada帧时这个命令可以提高执行效率,因为有时大参数的计算可能是CPU密集型的,特别是在大程
    序里。设置print frame-arguments为scalars或none可以避免这类运算,因此可以加速打印Ada帧。
show print frame-arguments
    显示打印帧时如何显示参数。
set print repeats
    设置打印数组的长度上限值。如果数组中连续相同的成员的数量超过这个上限,GDB会打印字符串”<repeats n times>”,这里n
    是同样的重复次数,而不是重复打印这些相同的成员。将这个上限设置为0的话,打印所有的成员。默认上限时10。
show print repeats
    显示打印重复相同成员的上限数量。
set print null-stop
    设置GDB在初次遇到NULL字符是终止打印字符串。如果大数组里包含短字符串时很有用。默认关闭。
show print null-stop
    显示GDB是否在初次遇到NULL字符串时停止打印。
set print pretty on
    设置GDB在打印结构体时,以缩进的格式每行打印一个结构体成员,如下:
        $1 = {
        next = 0×0,
        flags = {
            sweet = 1,
            sour = 1
        },
        meat = 0×54 “Pork”
        }
set print pretty off
    设置GDB以紧凑方式打印结构体,如下所示:
        $1 = {next = 0×0, flags = {sweet = 1, sour = 1}, \
        meat = 0×54 “Pork”}
    默认方式。
set print sevenbit-strings on
    只打印7bit的字符串。如果设置了这个选项,GDB用\nnn来显示8bit字符。如果在英语(ASCII)环境下执行或者将高位作为标记
    位或作为元数据位的话,这个设置是非常有用的。
set print sevenbit-strings off
    打印8bit字符。允许使用国际化字符集,缺省的。
show print sevenbit-strings
    显示GDB是否打印7bit字符。
set print union on
    设置GDB打印包含结构体或其他联合的联合。缺省设置。
set print union off
    设置GDB不打印包含结构体或其他联合的联合。GDB用”{…}”替代之。
show print union
    显示GDB是否打印包含结构体和其它联合的联合。
    例如,假设下列声明
        typedef enum {Tree, Bug} Species;
        typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
        typedef enum {Caterpillar, Cocoon, Butterfly}
        Bug_forms;
        struct thing {
        Species it;
        union {
            Tree_forms tree;
            Bug_forms bug;
        } form;
        };
        struct thing foo = {Tree, {Acorn}};   
    设置set print union on,’p foo’会打印如下输出:
        $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
    设置set print union off,’p foo’会打印如下输出:
        $1 = {it = Tree, form = {…}}
    set print union对于类似C和Pascal的程序有效。
下面这些设置对于调试C++程序很有用:
set print demangle
set print demangle on
    用源代码的形式打印C++名,而不是用编码后传递给汇编器和连接器的形式。默认打开。
show print demangle
    显示是否用源码形式打印C++名。
set print asm-demangle
set print asm-demangle on
    用源代码的形式打印C++名,而不用编码形式,即使在汇编代码的输出如指令反汇编。默认关闭。
show print asm-demangle
    显示是否用源码形式打印汇编代码。
set demangle-style style
    从编码方式中选择一种编码体系,解析C++名。style的选择有如下几种:
    auto    设置GDB通过探测程序来选择一种解码方式。
    gnu    基于GNU C++编译器(g++)的编码算法的解码方式。缺省方式。
    hp    基于HP ANSI C++(aCC)编码算法的解码方式。
    lucid    基于Lucid C++编译器编码算法的解码方式。
    arm    用C++ Annotated Reference Manual里定义的算法解码。警告:这个选项不足与调试cfront产生的可执行程序。GDB要
        改进才能调试此类程序。
    如果忽略了style,可能会看多多种格式的输出。
show demangle-style
    显示目前C++符号解析使用的编码方式。
set print object
set print object on
    在打印一个指针指向的对象时,使用虚函数表来标明对象真实的类型,而不是其声明的类型。
set print object off
    只显示对象所声明的类型,不引用虚函数表。默认选项。
show print object
    显示是否打印真实的,或声明的对象类型。
set print static-members
set print static-members on
    打印C++对象的静态成员。选项缺省打开。
set print static-members off
    打印C++对象时不打印静态成员。
show print static-members
    显示是否打印C++静态成员。
set print pascal_static-members
set print pascal_static-members on
    打印Pascal对象的静态成员。选项默认打开。
set print pascal_static-members off
    不打印Pascal对象的静态成员。
show print pascal_static-members
    显示是否打印Pascal静态成员。
set print vtbl
set print vtbl on
    以习惯方式打印C++虚函数表。默认关闭。(vtbl命令在HP ANSI C++编译器(aCC)编译的程序上无效。)
set print vtbl off
    不以习惯方式打印C++虚函数表。
show print vtbl
    显示是否以习惯方式打印C++虚函数表。

8.8 值历史
  以print命令打印的值保存于GDB值历史里。这种方式使得在其它表达式里引用这些值。值会保留到符号重载或者被丢弃(例如用file或
者symbol-file命令)。在符号表改变时,值历史会被丢弃,因为值可能包含指向符号表里定义的类型。
  打印过的值在历史表里都有编号,可以用此编号来引用值。这个编号是从1开始的连续整数。print在打印值的时候会在值前打印’$num=
‘,num是历史表里的编号。
  要引用此前的值,用’$'后接值历史编号就可以了。print打印标记’$'就是提醒你这个的。只有一个$指最近的值,$$指倒数第二近的值
。$$n指倒数n近的值;$$2是比$$靠前一个的值,$$1和$$相等,$$0和$相等。
  例如,假设刚打印过一个指针指向的结构体,想要查看这个结构体的内容。输入下列命令就可以了:
    p *$
  如果有一个结构体链表,其结构体里有一个成员next指向下一个结构体,可以用下面的命令来打印下一个结构体的内容:
    p *$.next
可以重复执行这个命令来连续打印这个链表–只需要输入回车键。
  注意,值历史记录值,不记录表达式。如果x的值是4,输入如下命令:
    print x
    set x=5
那么值历史里记录的值是4,即使x的值已经变为5了。
show values
    打印值历史表里最近的10个值,带其编号打印。和’p $$9′重复类似,除了show values不改变值历史。
show values n
    打印值历史表里的10个记录,以编号n为中心打印。
show values +
    打印最近打印过的值前的10个值。如果没有记录,show values +不产生输出。
  输入回车键来重复show values n和’show values +’效果一样。

8.9 惯用变量
  GDB提供了惯用变量,用户可以在GDB里用来存储数据,在以后引用。这类变量在GDB里全程存在;它们不是被调试程序的组成部分,设置惯用变量对程序执行没有直接影响。这就是为什么可以自由使用这类变量的原因。
  惯用变量有个前缀’$'。任何前导’$'的名字都可以用作惯用变量,除非是已经定义好的,系统指定的寄存器名(参见8.10节[寄存器],
90页)。(相反,引用值历史,是在数字前加’$'。参见8.8节[值历史],88页)
  可以将一个表达式的值保存在惯用变量里,就如同在程序里设置一个变量一样。例如:
    set $foo = *object_ptr
可以将指针object_ptr指向的值保存在$foo里。
  第一次使用惯用变量的时候会创建此变量,但其值是void,直到设置一个值为止。可以在任何时间改变此值。
  惯用变量没有固定的类型。可以为惯用变量指定任意类型的值,包括结构体和数组,即使此变量已经有一个不同类型的值。惯用变量,
在一个表达式里用时,其类型是当前值的类型。
show convenience
    打印目前为止的惯用变量列表和它们的值。缩写为show conv。
init-if-undefined $variable=expression
    设置一个惯用变量,如果其尚未设置的话。对于用户定义的保持某些状态的命令而言很有用。在概念上和在C语言里带初始化的
    使用本地静态变量很相似(除了惯用变量是全局的)。也可以用于覆盖在命令脚本里设置的缺省值。
    如果变量已经定义了,那么不计算表达式,因此也就没有边际效应。
  惯用变量的一种使用方式是作为一个增量计数器或者是一个指针。例如,要打印一个结构体数组成员里的域:
    set $i = 0
    print bar[$i++]->contents
用回车键重复命令。
  有些惯用变量是GDB自动创建的,记录有用的值。
$_    变量$_是x命令自动设置的,记录最近查看的地址(参见8.5节[查看内存],79页)。其它提供一个默认地址给x来查看的命令也
    会设置这个变量;这些命令包括info line和info breakpoint。$_的类型是void *;在x命令设置之后,其类型是$__的指针。
$__    变量$__是x命令自动设置的,记录最近查看地址上的值。其类型是打印的数据所匹配的类型。
$_exitcode
    变量$_exitcode在程序调试结束时自动记录退出码。
  在HP-UX系统里,如果被引用的函数或变量名前有一个$符号,GDB会先搜索用户或系统名,其后再搜索惯用变量。

8.10 寄存器
  在表达式里可以引用系统寄存器内容,将在寄存器名前置$符作为变量来用。寄存器名对于各系统可能不一样;使用info registers可
以查看系统的寄存器名。
info registers
    打印所有的寄存器名和值,除了浮点和向量寄存器(在选定的堆栈帧里)。
info all-registers
    打印所有的寄存器名和值,包括浮点和向量寄存器(在选定的堆栈帧里)。
info registers regname …
    打印所有指定寄存器对应的值。如下面详细讨论的那样,寄存器值通常是相对于选定的堆栈帧的。regname可能是系统里可用的
    ,任意的寄存器名带不带’$'都可以。
  GDB有4个在多数系统里可用的(在表达式里)”标准” 寄存器名–他们和系统标准的寄存器名总是不冲突的。寄存器名$pc和$sp由于记
录程序计数器寄存器和堆栈指针。$fp用于记录当前堆栈帧的指针,$ps用于记录处理器状态的寄存器。例如,可以用16进制打印程序计数
器:
    p/x $pc
或者打印下一条要执行的指令
    x/i $pc
或者将堆栈指针加4(注):
    set $sp += 4
  只要有可能,这4个标准寄存器名在系统里都是可用的,即使系统有不同的命名,只要没有冲突就行。info registers命令显示标准寄
存器名。例如,在SPARC系统里,info registers显示处理器状态寄存器为$psr,但也可应用$ps来引用;在基于x86的系统里$ps是EFLAGS
寄存器的别名。
  GDB总是将一个普通寄存器的内容作为一个整型值,寄存器也是这样查看的。某些系统具有只能存储浮点数据的特殊寄存器;这类寄存
器因此应该认为具有浮点类型的值。没有方法将普通寄存器作为浮点型来引用(虽然可以用用print将此寄存器作为浮点数打印,’print/
f $regname’)。
  某些寄存器具有不同的’原始’和’虚拟’的数据格式。这意味着由操作系统设置的寄存器值的数据格式和程序通常得到的不一样。例如,
68881浮点协处理器的寄存器总是保存”扩展”(原始)的数据格式,但所有C程序会以”double”(虚拟)的格式处理。在这些情况下,GDB通
常以虚拟格式处理(程序能够处理的格式),但info registers命令会以两种格式打印这个数据。
注:这是从堆栈里删除一个字的方法,在系统内存中堆栈是向下增长的(现代多数系统)。这种方法假设选定的是最内层的堆栈帧;在选
定别的堆栈帧时不允许设置$sp,使用return;参见14.4节[从函数返回],151页。
  某些系统具有一些其它特殊的寄存器,它们的内容可以有多种转换方式。例如,现代基于x86的系统有SSE何MMX寄存器,它们以不同的格
式保存打包在一起的多个值。GDB用结构体方式来引用这些寄存器:
    (gdb) print $xmm1
    $1 = {
        v4_float = {0, 3.43859137e-038, 1.54142831e-044, 1.821688e-044},
        v2_double = {9.92129282474342e-303, 2.7585945287983262e-313},
        v16_int8 = “\000\000\000\000\3706;\001\v\000\000\000\r\000\000″,
        v8_int16 = {0, 0, 14072, 315, 11, 0, 13, 0},
        v4_int32 = {0, 20657912, 11, 13},
        v2_int64 = {88725056443645952, 55834574859},
        uint128 = 0x0000000d0000000b013b36f800000000
    }
  要设置这类寄存器,需要告诉GDB要设置寄存器的哪部分,就如设置一个结构体的域那样:
    (gdb) set $xmm1.uint128 = 0x000000000000000000000000FFFFFFFF
  通常,寄存器值和选定堆栈帧是相对应的(参见6.3节[选择帧],64页)。这就是说,如果已经退出所有更深层的堆栈帧并且已经保存了
它们的寄存器值的话,你就可以得到这些寄存器的值。要查看硬件寄存器里的真实内容,必须选择最内层的堆栈帧(用’frame 0′)。
  然而,GDB需要从编译器产生的机器代码里推导出寄存器保存于何处。如果某些寄存器没有保存的话,或者GDB不能定位已保存的寄存器
的话,那么选定的堆栈帧就没法区分了。

8.11 浮点硬件
  取决于是如何配置的,GDB可以提供关于浮点硬件的状态信息。
info float
    显示挂于浮点单元的硬件相关的信息。确切内容和布局随浮点芯片不同而有所差异。目前,’info float’在ARM和x86平台上支持

8.12 向量单元
  取决于是如何配置的,GDB可以提供关于向量单元的状态信息。
info vector
    显示向量单元的信息。确切内容和布局随硬件不同而有所差异。

8.13 操作系统辅助信息
  GDB提供操作系统有用的工具的接口,用户可以用来帮助调试程序。
  如果运行于Posix系统(如GNU或者Unix系统),GDB通过系统调用ptrace和操作系统内部进行通信。操作系统为这个接口创建了特殊的数
据结构,称为struct user。可以用命令info udot 来显示这个数据结构的内容。
info udot
    显示操作系统内核维护的struct user结构体的内容。GDB用类似于examine命令的形式来显示struct user内容,打印出16进制数
    据的列表。
  某些操作系统在程序启动时提供了一个辅助向量。这个向量等效于为程序指定的参数、环境变量,包含一些系统相关的二进制的值,让
系统库得到关于硬件,操作系统和进程的重要的细节。每个值的目的都由一个整数标签指定;其含义是众所周知而又系统相关的。取决于
配置和操作系统的工具,GDB可以显示这些信息。对于远程系统,这个功能可能进步依赖于远程存根对于’qXfer:suxv:read’包的支持,参
见[qXfer辅助向量读],354页。
info auxv
    显示内部辅助向量,此向量可以是一个正在执行的进程或者是一个core dump文件。GDB以数值形式打印每个标签,并显示名称和
    对可识别的标签显示文字描述。向量里的某些值是数字,某些位(bit)是掩码,某些是指向字符串或其它数据的指针。GDB会以适
    当的方式显示每个可识别的标签,对于不可识别的标签则以16进制的形式显示。

8.14 内存区域属性
  内存区域属性提供了描述由系统内存请求的特殊处理的功能。GDB使用属性来判断是否允许某些类型的内存访问;是否使用明确的访问宽
度;时候缓存系统内存。缺省的,内存区域的描述取自系统(如果当前系统支持的话),但用户可以覆盖被取的区域。
  已定义的内存区域可以单独的激活或禁用。如果禁用一个内存区域,GDB会在访问这个区域时使用缺省属性。类似的,如果没有定义内存
区域的话,GDB在访问任何内存时都使用缺省属性。
  如果定义了内存区域,会有一个整数来标识;要激活,禁用或删除它的话,应该用这个编号。
mem lower upper attributes…
    定义一个内存区域,从lower到upper,属性是attribute…,并将其加入由GDB监控的区域列表。注意,upper==0是个特殊例子:
    当作系统最大内存地址。(16位系统里是0xffff,32位系统是0xffffffff)
mem auto
    放弃用户对内存区域的改变,并使用系统提供的区域,如果有的话,如果系统不提供的话就不适用内存区域。
delete mem nums…
    从GDB监控的内存列表里删除内存区域nums…。
disable mem nums…
    禁止监视内存区域nums…被禁用的内存区域不会被遗忘。可以在此激活之。
enable mem nums…
    激活监控内存区域nums…
info mem
    打印所有定义的内存区域列表,每个区域都有下面的列:
    Memory Region Number
    Enabled or Disabled.
        以激活的内存区域标记为’y'。已禁用的内存区域标记为’n'。
    Lo Address
        内存区域最低地址。
    Hi Address
        内存区域最高地址。
    Attributes
        内存区域的属性集。
8.14.1 属性
8.14.1.1 内存访问模式
  访问模式属性决定GDB是否可以对一个内存区域进行读写访问。
  要是这些属性阻止GDB进行非法内存访问的话,它们将组织系统I/O,DMA之类的内存访问。
ro    内存只读。
wo    内存只写。
rw    内存可读写。默认属性。
8.14.1.2 内存访问的尺寸
  访问尺寸属性告诉GDB使用指定大小的内存访问。通常内存和设备寄存器要求的指定大小的访问匹配。如果不指定访问尺寸属性,GDB可
能使用任意大小的访问。
8    使用8位内存访问。
16    使用16位内存访问。
32    使用32位内存访问。
64    使用64位内存访问。
8.14.1.3 数据缓冲
  数据缓冲属性设置GDB是否缓冲系统内存。由于减少了调试协议的开销,这个属性可以改善性能,与此同时也可能导致错误的结果,因为
GDB不知道volatile变量和内存映射寄存器。
cache    激活缓存系统内存。
nocache    禁用缓冲系统内存。默认属性。

8.14.2 内存访问检查
  GDB可以设置拒绝访问没有明确描述的内存。如果在某个系统下,访问这些内存区域存在不能预料的效果的话,要预防这种状况,或者要
提供一个更好的错误检查,都是很大帮助的。下列命令控制这种行为。
set mem inaccessible-by-default [on|off]
    如果设置on,设置GDB将未明确描述范围的内存当作不存在的并拒绝对此内存的访问。只有在至少有一个已定义的内存范围的情况
    下才会进行检查。如果设置了off,设置GDB将此未明确描述范围的内存作为RAM。默认值是on。
show mem inaccessible-by-default
    显示当前对于未知内存访问的设置。

8.15 在内存和文件之间复制数据
  可以用命令dump,append和restore来在目标内存和文件直线复制数据。dump和append命令将数据写入文件,restore命令将文件数据读入
到内存中。文件可以是二进制,Motorola S-record,Inetl16进制,或着Tekrronix16进制格式的;不过,GDB只支持将数据附加到二进制文
件。
dump [format] memory filename start_addr end_addr
dump [format] value filename expr
    将内存从start_addr开始到end_addr的内容,或表达式expr的值,以指定格式转储到文件。
    格式参数可以是下面类型之一:
    binary    原始二进制形式
    ihex    Intel 16进制格式
    srec    Motorola S-record格式
    tekhex    Tektronix 16进制格式
    GDB使用的格式和GNU二进制工具所使用的一样,比如’objdump’和’objcopy’。如果省略format,GDB用原始二进制格式转储数据。
append [binary] memory filename start_addr end_addr
append [binary] value filename expr
    将内存从start_addr开始到end_addr的内容,或表达式expr的值,以原始二进制格式附加到文件。(GDB只能用原始二进制格式附
    加数据到文件。)
restore filename [binary] bias start end
    将文件filename的内容恢复到内存中。restore命令可以自动识别任何已知的BFD文件格式,除了原始二进制文件。要恢复原始二进
    制文件,必须在文件名后指定可选关键字binary。
    如果bias非零,它是指从文件开头的偏移量。二进制文件总是荣地址0开始,所以会从地址bias开始恢复。其他bfd文件有一个内置
    位置;可以从那个位置再偏移bias开始恢复。
    如果start和/或end是非零的话,那么只有在文件偏移start和文件偏移end之间的数据会恢复。这些偏移是相对于文件内的位置的
    ,且是在bias参数相加之前的偏移。

8.16 如何从程序里产生Core文件
  core文件或者core dump记录执行中的进程的内存镜像和状态(例如寄存器值)。它的主用作用是对崩溃的程序事后调试。发生崩溃
的程序会自动产生core文件,除非这个功能被用户禁用了。关于事后调试模式的信息,参见15.1节[文件],155页。
  偶尔的,可能希望在调试程序期间产生core文件来保存进程的状态快照。GDB为此提供了一个特殊的命令。
generate-core-file [file]
gcore [file]
    为调试进程产生core dump。可选参数file指定存储core dump的文件名。如果没有指定,文件名那个默认是’core.pid’,这里pid
    是被调试进程的进程ID。
    注意,这个命令只在某些系统上实现(到手册编写时,GNU/Linux,FreeBSD,Unixware和S390)。

8.17 字符集
  如果调试中的程序使用的字符集和GDB使用的不一样,GDB可以自动为用户转换字符集。GDB使用的字符集我们称为宿主字符集;调试程序
使用的称为目标字符集。
  例如,如果在GNU/Linux系统上运行GDB,GNU/Linux系统使用ISO Latin 1字符集,而用户用GDB远程协议(参见17章[远程调试],171页
)来调试在IBM框架下运行的程序,其字符集是EBCDIC字符集,那么宿主字符集是Latin-1,而目标字符集是EBCDIC。如果用命令set
target-charset EBCDIC-US设置GDB,那么在输入字符或字符串或在表达式里使用字符和字符串时,GDB会在EBCDIC和Latin 1之间转换。
  GDB不能自动识别调试中的程序所使用的字符集;用户必须告诉它,使用set target-charset命令,如下所述。
  下面是控制GDB字符集的命令:
set target-charset charset
    将当前目标字符集设置为charset。下面会列举GDB能识别的字符集名称,不过如果输入set target-charset接着再敲两次TAB键的
    话,GDB会列出它所能识别的字符集。
set host-charset charset
    设置当前的宿主字符集为charset。
    缺省的,GDB使用的宿主字符集和系统的相近;可以用set host-charset命令覆盖默认值。
    GDB只能使用某些字符集作为宿主字符集。下面会列举GDB能识别的字符集名称,并指明哪种可以用作宿主字符集,不过如果输入
    set target-charset接着再敲两次TAB键的话,GDB会列出它所支持的宿主字符集。
set charset charset
    涩会址当前的宿主和目标字符集为charset。如前所述,如果输入set charset接着再敲两次TAB键的话,GDB会列出它所支持的宿
    主/目标字符集。
show charset
    显示当前宿主和目标字符集。
show host-charset
    显示当前宿主字符集名。
show target-charset
    显示当前目标字符集名。
  GDB目前支持下列字符集:
ASCII    U.S. ASCII 7-bit。GDB可使之为其宿主字符集。
ISO-8859-1
    ISO Latin 1字符集。为法语,德语和西班牙语的重音符号而扩展到字符集。GDB可使之为其宿主字符集。
EBCDIC-US
IBM1047
    EBCDIC字符集的变体,用于某些IBM架构的操作系统。(S/390上的GNU/Linux使用U.S. ASCII)GDB不可使之为其宿主字符集。

  注意,这些都是单字节字符集。GDB里的很多处理都需要支持多字节或可变长度字符编码,例如Unicode的UTF-8和UCS-2编码方法。
  下面是GDB字符集支持的实际例子。假设下面的源代码在文件’charset-test.c’里:
    #include <stdio.h>
    char ascii_hello[]
        = {72, 101, 108, 108, 111, 44, 32, 119,
            111, 114, 108, 100, 33, 10, 0};
    char ibm1047_hello[]
        = {200, 133, 147, 147, 150, 107, 64, 166,
            150, 153, 147, 132, 90, 37, 0};
    main ()
    {
        printf (“Hello, world!\n”);
    }
  在此程序里,ascii_hello和ibm1047_hello是包含字符串”hello,world!”的数组,用ASCII和IBM1047字符集编码。
  编译此程序并开始调试之:
    $ gcc -g charset-test.c -o charset-test
    $ gdb -nw charset-test
    GNU gdb 2001-12-19-cvs
    Copyright 2001 Free Software Foundation, Inc.
    …
    (gdb)
  用show charset命令来查看GDB目前使用哪中字符集来转换和显示字符和字符串:
    (gdb) show charset
    The current host and target character set is ‘ISO-8859-1’.
    (gdb)
  出于打印手册的缘故,让我们用ASCII作为初始字符集:
    (gdb) set charset ASCII
    (gdb) show charset
    The current host and target character set is ‘ASCII’.
    (gdb)
  假设ASCII是目前宿主系统的真正字符集–换句话说,假设GDB用ASCII字符集打印字符,终端会正确的显示字符。由于当前的目标字符集
也是ASCII,ascii_hello的内容会以可读的形式打印:
    (gdb) print ascii_hello
    $1 = 0×401698 “Hello, world!\n”
    (gdb) print ascii_hello[0]
    $2 = 72 ’H’
    (gdb)
  GDB使用目标字符集来打印字符和字符串常量:
    (gdb) print ’+’
    $3 = 43 ’+’
    gdb)
  ASCII字符集使用数字43来编码字符’+'。
  GDB依赖用户告知目标程序使用的是何种字符集。如果目标字符集还是ASCII,我们试图打印ibm1047_hello就会得到乱码:
    (gdb) print ibm1047_hello
    $4 = 0x4016a8 “\310\205\223\223\226k@\246\226\231\223\204Z%”
    (gdb) print ibm1047_hello[0]
    $5 = 200 ’\310’
    (gdb)
  如果输入set target-charset接着再敲两次TAB键,GDB会告知其所支持的字符集:
    (gdb) set target-charset
    ASCII EBCDIC-US IBM1047 ISO-8859-1
    (gdb) set target-charset
  我们可以选择IBM1047作为目标字符集,并再次检查程序字符串。现在ASCII字符串就是错误的了,但GDB会将ibm1047_hello从目标字符
集转换到宿主字符集ASCII,这样就可以正确显示了:
    (gdb) set target-charset IBM1047
    (gdb) show charset
    The current host character set is ‘ASCII’.
    The current target character set is ‘IBM1047’.
    (gdb) print ascii_hello
    $6 = 0×401698 “\110\145%%?\054\040\167?\162%\144\041\012″
    (gdb) print ascii_hello[0]
    $7 = 72 ’\110’
    (gdb) print ibm1047_hello
    $8 = 0x4016a8 “Hello, world!\n”
    (gdb) print ibm1047_hello[0]
    $9 = 200 ’H’
    (gdb)
  如前所示,GDB用目标字符集来打印字符和字符串常量:
    (gdb) print ’+’
    $10 = 78 ’+’
    (gdb)
  IBM1047字符集使用数字78来编码字符’+'。

8.18 缓存远程目标的数据
  GDB可以缓存在调试器和远程目标之间交换的数据(参见17章[远程调试],171页)。这种缓存通常可以改善性能,因为其可减少由于内
存读写所带来的远程协议的开销。不幸的是,目前GDB对volatile寄存器无能为力,因此如果使用了volatile寄存器的时候,数据缓存就会
带来错误的结果。
set remotecache on
set remotecache off
    为远程目标设置缓存状态。如果是on的话,使用数据缓存。缺省的,此选项是off。
show remotecache
    显示目前远程目标的数据缓存状态。
ifo dcache
    打印数据缓存性能的信息。显示的信息包括:dcache的宽度和深度;对于每个缓存行,其被多少次引用到了,其数据和状态(脏
    ,坏,好,等等)。对于调试数据缓存操作,这个命令很有帮助。

原创粉丝点击