Hexagon GDB Debugger介绍(20)

Hexagon GDB Debugger介绍(20)

2.12.3 数组

在内存中打印出几个连续的相同类型的对象通常很有用; 如数组的一部分,或由指针实现的动态数组。
你可以通过使用二元运算符 @ 将连续的内存范围视作数组来实现此目的。 @ 的左操作数应该是所需数组的第一个元素,并且是一个单独的对象。 正确的操作数应该是数组的所需长度。 结果是一个数组值,其元素都是左参数的类型。 第一个元素实际上是左参数; 第二个元素来自紧跟在第一个元素之后的内存字节,依此类推。

给定以下数组声明:

int *array = (int *) malloc (len * sizeof (int));

…你可以打印数组的内容:

p *array@len

@ 的左操作数必须驻留在内存中。 以这种方式使用 @ 生成的数组值在下标方面的行为与其他数组一样,并且在表达式中使用时被类型强制转换为指针。 数组常通过打印的value history出现在表达式中(参见第 2.12.8 节)。

创建数组的另一种方法是使用cast。 将一个值重新解释为一个数组。 该值不需要在内存中:

(hexagon-gdb) p/x (short<:2:>)0x12345678
$1 = {0x1234, 0x5678}

为方便起见,如果省略数组长度(即 (type<::>)value),调试器将计算填充值的大小 (sizeof(value)/sizeof(type)):

(hexagon-gdb) p/x (short<::>)0x12345678
$2 = {0x1234, 0x5678}

有时数组机制还不够; 在更为复杂的数据结构中,感兴趣的元素实际上可能并不相邻,例如,如果你对数组中指针的值感兴趣。 在这种情况下,一个有用的解决方法是使用便利变量(参见第 2.12.9 节)作为打印第一个感兴趣值的表达式中的计数器,然后通过 重复该表达式。 例如,假设你有一个指向结构的指针数组 dtab,并且你对每个结构中字段 fv 的值感兴趣。 以下是你可能键入的内容的示例:

t_set i 0
p dtab<:$i++:>->fv
<RET>
<RET>
...

注意
    上面的示例使用为调试器定义的非标准数组索引运算符。  见第 2.15.4.2 节。

2.12.4 输出格式

默认情况下,调试器根据其数据类型打印一个值。 有时这不是你想要的。 例如,你可能想以十六进制打印一个数字,或以十进制打印一个指针。 或者,你可能希望以字符串或指令的形式查看内存中某个地址处的数据。 要执行这些操作,请在打印值时指定输出格式。
输出格式的最简单用途是说明如何打印已计算的值。 这是通过使用斜杠和格式字母开始打印命令的参数来完成的。
支持的格式字母是:

  • x 将值的位视为整数,并以十六进制打印整数。
  • d 显示为有符号十进制整数。
  • u 显示为无符号十进制整数。
  • o 以八进制显示为整数。
  • t 以二进制显示为整数。 字母 t 代表“2”。
b 不能使用,因为这些格式字母也与 x 命令一起使用,其中 b 代表“字节”;  见第 2.12.5 节。
  • a 显示为地址,以十六进制绝对地址和最近的前一个符号的偏移量显示。 你可以使用这种格式来发现未知地址的位置(在什么函数中):(hexagon-gdb) p/a 0x54320 $3 = 0x54320 <_initialize_vx+396>
    命令信息符号 0x54320 产生类似的结果。 见第 2.16 节。
  • c 将其视为整数并将其打印为字符常量。
  • f 将值的位视为浮点数,并使用典型的浮点语法打印。

例如,要以十六进制打印程序计数器(请参阅第 2.12.10 节),请键入:

p/x $pc
注意 
    斜线前不需要空格;  调试器中的命令名称不能包含斜杠

要使用不同的格式重新打印值历史记录中的最后一个值,你可以使用仅带格式而不带表达式的打印命令。 例如,p/x 以十六进制重新打印最后一个值。

2.12.5 检查内存

你可以使用命令 x(用于“检查”)以独立于程序数据类型的多种格式中的任何一种检查内存。

x /nfu addr
x addr
x

  以指定格式显示内存内容。

n、f 和 u 都是可选参数,它们指定要显示多少内存以及如何对其进行格式化; addr 是一个表达式,给出了要开始显示内存的地址。 如果对 nfu 使用默认值,则无需键入斜杠 /。 有几个命令为 addr 设置了方便的默认值。

n
  重复计数是一个十进制整数; 默认值为 1。它指定要显示多少内存(按单位 u 计数)。
f
  显示格式是 print、s(以空字符结尾的字符串)或 i(机器指令)使用的格式之一。 最初的默认值为 x(十六进制)。 每次使用 x 或 print 时,默认值都会更改。

u
  单位大小是以下任何一项:
  b 字节。
  h 半字(两个字节)。
  w 字(四个字节)。 这是初始默认值。
  g 双字(8 个字节)。

每次使用 x 指定单位大小时,该大小将在你下次使用 x 时成为默认单位。 (对于 s 和 i 格式,单位大小被忽略并且通常不写入。)

addr
  addr 是你希望调试器开始显示内存的地址。
  表达式不需要有指针值(尽管可能); 它总是被解释为一个内存字节的整数地址。 有关表达式的更多信息,请参见第 2.12.1 节。 addr 的默认值通常在检查的最后一个地址之后,但其他几个命令也设置了默认地址:info breakpoints(到列出的最后一个断点的地址)、info line(到一行的起始地址)和 print (如果你使用它来显示内存中的值)。

例如,x /3uh 0x54320 是显示内存的三个半字 (h) 的请求,格式为无符号十进制整数 (u),从地址 0x54320 开始。 x /4xw $sp 以十六进制 (x) 打印堆栈指针(此处为 $sp;参见第 2.12.10 节)上方的内存的四个字 (w)。

由于表示单位大小的字母都不同于指定输出格式的字母,因此你不必记住是单位大小还是格式在前; 任何一个订单都有效。 输出规格 4xw 和 4wx 的含义完全相同。 (但是,计数 n 必须在前;wx4 不起作用。)

即使格式 s 和 i 忽略了单位大小 u,你可能仍然希望使用计数 n; 例如,3i 指定你要查看三个机器指令,包括任何操作数。 命令 disassemble 提供了一种检查机器指令的替代方法。 见第 2.11.6 节。

x 参数的所有默认值旨在使你每次使用 x 时都可以轻松地以最少的规格继续扫描内存。 例如,在你用 x /3i addr 检查了三个机器指令之后,你可以只用 x /7 检查接下来的七个。 如果使用 重复 x 命令,则重复次数 n 将再次使用; 其他参数默认为 x 的连续使用。

x 命令打印的地址和内容不会保存在值历史记录中(第 2.12.8 节),因为它们通常太多而无法很好地与该功能配合使用。相反,调试器使 x 命令输出可供后续使用在表达式中作为便利变量 $_ 和 $__ 的值。 在 x 命令之后,检查的最后一个地址可用于便利变量 $_ 中的表达式。所检查的该地址的内容在便利变量 $__ 中可用。

如果 x 命令有重复计数,则保存的地址和内容来自最后打印的内存单元; 如果在输出的最后一行打印了多个单元,则这与打印的最后一个地址不同。

注意 
    x 命令要求在斜杠字符 / 之前有一个空格。  这与标准 GDB 不同,这样做是为了避免与 Tcl 脚本语言(第 4.4 节)发生冲突。
上一篇:linux调试工具-gdb安装使用


下一篇:反汇编测试