【问题标题】:How to set a write watchpoint for a variable on the stack如何为堆栈上的变量设置写观察点
【发布时间】:2017-07-24 21:04:12
【问题描述】:

在我的代码中,我有

mov x21, 0
str x21, [x29, 16]

然后在代码中,

ldr x22, [x29, 16]

将 0 存储到 x22 中。 然后,即使在代码的后面,我也有

ldr x23, [x29, 16]

即使两个 ldr 命令之间没有 str 命令,它最终也会将 214748364800 存储到 x23 中。

我的问题是如何为堆栈上的[x29, 16] 位置设置观察点,以便我可以看到它何时被写入?

我正在使用 gdb 进行调试。

编辑: 这是我在 x29+16 位置设置手表时 gdb 输出的一部分

Breakpoint 2, 0x0000000000400668 in inittest ()
1: x/i $pc
=> 0x400668 <inittest+8>:       mov     x21, #0x0                       // #0
(gdb) ni
0x000000000040066c in inittest ()
1: x/i $pc
=> 0x40066c <inittest+12>:      str     x21, [x29,#16]
(gdb) p/x $x29+16
$1 = 0x3fffffff340
(gdb) x/x $x29+16
0x3fffffff340:  0xb8002d40
(gdb) watch *(int*)0x3fffffff340
Hardware watchpoint 5: *(int*)0x3fffffff340
(gdb) c
Continuing.

Hardware watchpoint 5: *(int*)0x3fffffff340

Old value = -1207947968
New value = 0
0x0000000000400670 in inittest ()
1: x/i $pc
=> 0x400670 <inittest+16>:      b       0x4006d8 <testOut>

稍后在 gdb 输出中:

(gdb) p $x24
$4 = 103
(gdb) x/x $x29+24
0x3fffffff348:  0x00000000
(gdb) ni
0x00000000004006b4 in testIn ()
1: x/i $pc
=> 0x4006b4 <testIn+16>:        ldr     x24, [x29,#16]
(gdb) x/x $x29+16
0x3fffffff340:  0x00000000
(gdb) ni

如果我在这里输入p$x24,它会显示214748364800,即使它是从持有0 的[x29,#16] 加载的

0x00000000004006b8 in testIn ()
1: x/i $pc
=> 0x4006b8 <testIn+20>:        ldr     w23, [x19,x21,lsl #2]
(gdb) ni
0x00000000004006bc in testIn ()
1: x/i $pc
=> 0x4006bc <testIn+24>:        str     w23, [x29,#28]
(gdb)
0x00000000004006c0 in testIn ()
1: x/i $pc
=> 0x4006c0 <testIn+28>:        ldr     w23, [x19,x24,lsl #2]
(gdb)

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006c0 in testIn ()
1: x/i $pc
=> 0x4006c0 <testIn+28>:        ldr     w23, [x19,x24,lsl #2]

由于内存分配,x24 的最大值只能约为 54,因此出现错误

【问题讨论】:

  • str 上放置一个断点,然后在遇到断点时在x29+16 的任何值上添加监视。请注意,您还需要确保 x29 未更改。
  • 如果你确实使用watch(int *) 类型,你可以在dbg 中尝试:(gdb) print sizeof(int) 吗?如果它是 4,并且您使用的是 little-endian 模式,那么您只看到前 4 个字节(仍然为零),0x32 发生在第五个字节。
  • 我输入了 print sizeof (int),它说 4。此外,在调用 ldr 时它加载 0x3200000000 而不是 0,之后我输入 x/4x $x29+16 以查看所有 4 个字节,第二个字节,而不是0x00000000,实际上是0x00000032。我猜这就是改变的地方。如何在第二个字节上专门设置手表?它只是简单地设置当我输入p/x $x29+17 时显示的十六进制代码吗? (16 是第一个字节,17 是第二个等等?)

标签: assembly gdb stack armv8


【解决方案1】:

如何为 [x29, 16] 位置设置观察点

你描述的不是一个固定的位置——它取决于x29的值(你确定x29在两个指令之间没有变化吗?)。

ldr x23, [x29, 16]这一点,找出错误值的位置是什么:

(gdb) p/x $x29+16  # this is the location you'll want later
(gdb) x/x $x29+16  # should show 0x3200000000 == 214748364800

现在在第一条指令上设置断点并重新运行程序。一旦断点被​​命中,验证你期望的值是真的在那里:

(gdb) x/x 0x...    # should be 0, not 0x3200000000

并设置观察点:

(gdb) watch *(int*)0x....
(gdb) continue

...当值改变时,GDB 应该停止。

【讨论】:

  • 这有助于设置观察点。但事实证明问题不是我想的那样。当我在应该显示 0x3200000000 的初始 x/x $x29+16 时,它改为显示 0x0。因此,在该位置设置观察点对我没有任何作用,因为它确实保持 0。实际上发生的事情是 ldr x23, [x29, 16] 行,即使它调用保存 0 的位置,它也会存储值 0x3200000000
  • @ErickP ldr 加载,而不是存储。如果该内存仍然为零,那么x29 肯定是不同的,你不能从 8 个零字节加载0x3200000000
  • @ErickP 等一下……那个手表……在 gdb 64b 或 32b 中是 int? gdb 知道int64_t 吗?还是qword?或者,如果int 只有 32b,则可以在该内存上放置两个手表。 (我不使用gdb,所以如果是32b,我不确定什么是正确的答案和解决方案)
猜你喜欢
  • 2011-03-29
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
相关资源
最近更新 更多