【问题标题】:Setting GDB hardware watchpoint/how to set software watchpoint设置 GDB 硬件观察点/如何设置软件观察点
【发布时间】:2011-03-29 02:16:38
【问题描述】:

An earlier question 解释说,在 x86 上,正在监视的对象的大小受调试寄存器的限制。正如所料,我可以“观察”一个双变量。但是我不能看双数据成员,例如,

watch pObject->dPrice

生产

Hardware watchpoint 1: pObject->dPrice

但是当你尝试继续执行时,它会说

无法插入硬件断点: 您可能请求了太多的硬件断点/观察点。

即使这是唯一断点/观察点。

我很好奇为什么会这样,但更重要的是有没有办法解决它?根据 GDB 文档,如果它不能使用硬件,它可能会使用软件观察点。在这种情况下,它不会尝试使用软件观察点——有没有办法强制它这样做?

【问题讨论】:

  • 你能打印出那个成员变量的地址吗?我的怀疑是它被优化成一个寄存器。如果不是这样,它是否正确对齐?

标签: c++ linux gdb x86


【解决方案1】:

简答:使用watch -location pObject->dPrice,或简写形式watch -l

长答案:Quoting the GDB manual:

查看引用许多变量的复杂表达式也会耗尽硬件辅助观察点的可用资源。这是因为 GDB 需要使用单独分配的资源来监视表达式中的每个变量。

GDB 从字面上看是观察表达式本身,而不是它指向的任何地址。在这种情况下,这意味着如果将pObject本身更改为指向新的dPrice,则断点将命中; pObject->dPrice 不仅有一个观察点,pObject 本身也有一个观察点。这可能比现有的更多。

一个更全面的例子:

// Set a watchpoint on '*p' before running
#include <stdio.h>

int a = 0;
int b = 0;
int c = 0;
int* p = &a;

int main()
{
    puts("Hi"); // Dummy lines to make the results clearer, watchpoints stop at the line after the change
    *p = 1; // Breaks: *p was changed from 0 to 1
    puts("Hi");
    a = 2; // Breaks: a is *p, which changed from 1 to 2
    puts("Hi");
    p = &b; // Breaks: p is now b, changing *p from 2 to 0
    puts("Hi");
    p = &c; // Doesn't break: while p changed, *p is still 0
    puts("Hi");
    p = NULL; // Breaks: *p is now unreadable
    puts("Hi");
    return 0;
}

理论上,这是一个有用的功能;你可以看到一个复杂的表达式,一旦它是假的就会中断,有点像一个不断测试的断言。例如,您可以在上述程序中watch a==b

在实践中,这是出乎意料的,经常触发这个问题,而且通常不是你想要的。

要仅查看目标地址,请使用watch -location pObject-&gt;dPrice。 (从 2011 年 7 月发布的 GDB 7.3 开始提供此功能;如果您使用的是旧版本,请使用 print &amp;pObject-&gt;dPricewatch *(double*)0x12345678,或任何它打印的地址。)

【讨论】:

  • 将此答案交叉发布到this question,它同时回答了这两个问题。
  • 哦,好的,所以watch pObject-&gt;dPrice 必须同时查看“pObject 的所有字段”和pObject-&gt;dPrice 或类似的东西。
【解决方案2】:

我不是 100% 确定,但我的理解是,当您观看 pObject-&gt;dPrice 时,GDB 会尝试观看任何可以改变观看值的内容。

使用软件观察点,在每一步之后,GDB 都会检查表达式是否已更改。使用硬件观察点,GDB 必须为dprice 设置观察点,正如您所期望的那样,但也为pObject 设置观察点。

现在,您将问题标记为“x86”。在 x86 上,您最多可以为四个字节设置断点。双精度是八个字节。如果你想看双打,我猜 GDB 需要两个硬件观察点。您还需要为pObject 设置一个额外的观察点。我猜 GDB 会尝试观看pObject所有,这可以追溯到您在问题中链接的问题。

当我想做类似的事情时,如果我确定指针pObject不会改变,我通常会这样做:

p &pObject->dprice

假设 GDB 说地址是(double *) 0xabcdef10,现在我这样做了:

watch (double *) *0xabcdef10

只看我想看的。

注意:我面前没有打开 GDB,所以我可能有 watch 命令的确切语法错误(关于 * 的位置),所以先检查一下。

【讨论】:

  • 如果 gdb 提供“只看最终目标”的快捷方式就更好了
  • @CraigRinger: It does. watch -location pObject-&gt;dprice
  • @Alcaro: 1.任何版本的gdb都支持这个? 2. 这是一个足够好的答案,它应该是一个独立的答案,而不是对我的答案的评论。
  • (1) 经测试可在 GDB 7.7.1、Ubuntu 14.04 上运行。我将下载一些 tarball 并准确检查它何时出现。 (而且我怀疑 -location 在它成为显式标志之前是默认值。非常令人惊讶的行为。)(2)可以。
【解决方案3】:

是的,您可以:

设置 can-use-hw-watchpoints 0

来自5.1.2 Setting Watchpoints

您可以使用 set can-use-hw-watchpoints 0 命令强制 GDB 仅使用软件观察点。将此变量设置为零,GDB 将永远不会尝试使用硬件观察点,即使底层系统支持它们。 (请注意,在将 can-use-hw-watchpoints 设置为零之前设置的硬件辅助观察点仍将使用观察表达式值的硬件机制。)

set can-use-hw-watchpoints

    设置是否使用硬件观察点。

show can-use-hw-watchpoints

    显示当前使用硬件观察点的模式。

【讨论】:

  • 谢谢!我只是在阅读那部分,但显然我没有仔细阅读。
  • 它可以工作,但它比硬件慢一点。就我而言,大约是速度的 1/5000。
  • 导致Can't set read/access watchpoint when hardware watchpoints are disabled.
  • @Blauhirn 这是一个 8 岁的答案。您提到的更改是incorporated 5 years ago。如果你能解决它,请告诉我们。
  • @wallyk 是的,GDB 手册说“GDB 通过单步执行程序并每次测试变量的值来进行软件观察点,这比正常执行慢数百倍”,所以这不会是在大多数调试场景中都很有用。
猜你喜欢
  • 2011-11-15
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多