Hexagon GDB Debugger介绍(19)

Hexagon GDB Debugger介绍(19)

2.12 检查数据

检查程序中数据的常用方法是使用print命令(缩写为 p)或其同义词检查。 它计算并打印你的程序所用语言的表达式的值(参见第 2.15 节)。

print [/f ] expr
  expr 是一个表达式(在源语言中)。 默认情况下,expr 的值以适合其数据类型的格式打印; 你可以通过指定 /f 来选择不同的格式,其中 f 是指定格式的字母。 见后续第 2.12.4 节。

print [/f ]
  如果省略 expr,调试器将再次显示最后一个值(来自value history;参见第 2.12.8 节)。 这使你可以方便地以替代格式检查相同的值。

检查数据的一种更底层的方法是使用 x 命令。 它检查内存中指定地址的数据并以指定格式打印它。 见第 2.12.5 节。
如果你对有关类型的信息或有关如何声明结构体或类的字段的信息感兴趣,请使用 ptype exp 命令而不是print。 见第 2.16 节。

2.12.1 表达式

print和许多其他调试器命令接受表达式并计算其值。由你使用的编程语言定义的任何类型的常量、变量或运算符在调试器中的表达式中都是有效的。 包括条件表达式、函数调用、强制转换和字符串常量。 如果你编译程序以包含此信息,则它还包括预处理器宏。 见第 2.8.1 节。

调试器支持用户输入的表达式中的数组常量。 语法是 {element, element…}。 例如,你可以使用命令 print {1, 2, 3} 来构建目标程序使用 malloc 创建的数组。

因为 C 非常普遍,所以本手册示例中显示的大多数表达式都是用 C 编写的。有关如何使用其他语言中的表达式的信息,请参阅第 2.15 节。

在本节中,我们将讨论你可以在调试器表达式中使用的运算符,而不管你使用何种编程语言。
所有语言都支持强制转换,而不仅仅是在 C 语言中,因为将数字强制转换为指针以便检查内存中该地址处的结构非常有用。
除了编程语言常见的操作符外,调试器还支持这些操作符:

@
  @ 是一个二元运算符,用于将部分内存视为数组。 有关更多信息,请参阅第 2.12.3 节。

::
  :: 允许你根据定义变量的文件或函数来指定变量。 见第 2.12.2 节。

{type} addr
  指存储在内存中地址 addr 的 type 类型的对象。 addr 可以是任何值为整数或指针的表达式(但二元运算符周围需要括号,就像在强制转换中一样)。 无论什么样的数据通常应该驻留在 addr 中,都允许使用此构造。

2.12.2 程序变量

最常用的表达式类型是程序中变量的名称。
表达式中的变量在选定的堆栈帧中被理解(参见第 2.10.3 节);它们必须是以下之一:

  • 全局(或文件静态)
  • 从该框架中的执行点,根据编程语言的范围规则可见

这意味着在函数中:

foo (a)
int a;
{
    bar (a);
    {
        int b = test ();
        bar (b);
    }
}

…你可以在程序在函数 foo 中执行时检查和使用变量 a,但你只能在程序在声明 b 的块内执行时使用或检查变量 b。

有一个例外:即使当前执行点不在此文件中,你也可以引用作用域为单个源文件的变量或函数。 但是可能有多个这样的变量或函数具有相同的名称(在不同的源文件中)。 如果发生这种情况,提及该名称会产生不可预测的影响。 如果需要,你可以使用冒号-冒号表示法在特定函数或文件中指定静态变量:

file::variable
function::variable

这里的文件或函数是静态变量的上下文名称。 对于文件名,你可以使用引号来确保调试器将文件名解析为单个单词:例如,打印 f2.c 中定义的 x 的全局值:

(hexagon-gdb) p 'f2.c'::x

:: 的这种用法很少与 C++ 中相同符号的非常相似的用法发生冲突。 调试器还支持在调试器表达式中使用 C++ 范围解析运算符。

注意 
    有时,局部变量可能会在函数的某些点出现错误的值:在进入新作用域之后,在退出之前

当你按照机器指令逐步执行时,你可能会看到此问题。 这是因为,在大多数机器上,设置堆栈帧(包括局部变量定义)需要不止一条指令; 如果你按机器指令逐步执行,则在完全构建堆栈帧之前,变量可能看起来具有错误的值。 在退出时,通常也需要多条机器指令来销毁堆栈帧; 在你开始逐步执​​行该组指令后,局部变量定义可能会消失。

当编译器进行重大优化时,也可能发生这种情况。 为确保始终看到准确的值,请在编译时关闭所有优化。
编译器优化的另一个可能效果是优化不存在的变量,或将变量分配给寄存器(与内存地址相反)。 根据编译器使用的调试信息格式对此类情况的支持,调试器可能无法显示此类局部变量的值。 如果发生这种情况,它将打印如下消息:

No symbol "foo" in current context.

要解决此类问题,请在不优化的情况下重新编译,或使用不同的调试信息格式(如果编译器支持多种此类格式)。 例如,C 编译器支持 -gstab+ 选项。 你可以使用 DWARF 2 (-gdwarf-2),这也是一种有效的调试信息形式。 请参阅 Hexagon GNU C/C++ 编译器手册。

上一篇:反汇编测试


下一篇:反汇编测试