【问题标题】:How do you watch the value of a changing pointer in gdb?您如何查看 gdb 中更改指针的值?
【发布时间】:2013-09-20 19:57:51
【问题描述】:

我有一个指针 (**A) 指向另一个指针 (*B)。在程序中的某个地方,B 正在损坏。但是,B 在存储在*A 之前已损坏。 B 并不总是位于相同的地址(&B 并不总是相同)。但是 B 总是被相同的值破坏(B 总是相同的)。我知道这一点是因为我有一个损坏检测例程,它查看要存储在 *A 上的 next 值,所以我只知道它已经损坏的点。

我想要(当然)是找出B 被破坏的地方。

我已经在A 上尝试了一个 gdb 观察点,它会在 A 指向 (*A) 的任何位置上自动生成一个观察点,希望在 B 第一次存储在 *A 时捕获它, 在它不再存储在 *A 之前,它会损坏,然后重新存储在 *A 上。

watch A
commands
  silent
  watch *A
  commands
    silent
    if *A == magicalcorruptedvalue
      where
    end
  end
end

但问题是,对于硬件观察点,太多的中间内容存储在*A 上,所以我很快就用完了观察点。我没有尝试过软件观察点,因为它们不适用于线程。

在这一点上,我认为唯一的解决方案是返回并更仔细地阅读代码(始终是一个不错的选择),构建更多的单元测试,或者创建一个专门的线程来持续扫描所有分配的内存对于这个值。

但是,我怀疑我不是第一个遇到这个问题的人。一个更通用表达这个问题的方式可能是:当所有简单的技术都失败时,有哪些技术可以调试缓冲区溢出?

元参数:

  • 在 Linux 上

  • 这是一个多线程回调样式的应用程序。

【问题讨论】:

  • 为什么不在 B 上设置一个写观察点?
  • 因为我不知道 B 是什么,直到 after 它已损坏。我只知道 A 是什么,并且它会在某个时候指向某个已损坏的 B。我想实际上我可能已经弄清楚了,但是每当 A 更改时,它需要复杂的 gdb 调试来动态删除和设置新的观察点。如果我确实这样做了,我会在这里为下一个不幸进入调试地狱的人发布答案。
  • 另外,我应该提一下,B 肯定会在损坏发生之前 存储在 A 上。否则根本就无法处理 B。

标签: c gdb buffer-overflow


【解决方案1】:

我想出了两个答案,其中一个确实对我有用。

  1. 为工作使用正确的工具。 gdb 用于调试程序流程。 valgrind 似乎更适合调试内存/缓冲区错误。用 valgrind 运行程序,我很快就发现了错误。

  2. 理论上在 gdb 中实际上有一种方法可以做到这一点。在实践中,只有在 *A 相对很少更改时才会足够快。不是在这个特定程序中改变了 10k+ 次。

这里是:

set $A = (void ***) &whateveritis
set $B = (void **) 0
set $WPN = 2
set $WP = 0
watch *$A
commands
  silent
  set $B = *$A
  if $WP != 0
    delete $WP
    set $WP = 0
  end
  if $B != (void *) 0
    watch *$B
    commands
      silent
      if *$B == magicalcorruptedvalue
        where
      else
        continue
      end
    end
    set $WP = $WPN++
  end
  continue
end

这会在A 上设置一个观察点,删除之前*A 上存在的任何以前的观察(最终将设置为B),然后为当前*A 设置观察。手表总是在寻找magiccorruptedvalue,尽管在我的情况下,任何B 存储在*A 中的更改都是错误的,所以我省略了整个部分。

注意 $WPN 是下一个断点的编号。请注意它会因临时隐式断点(例如通过 start 创建的断点而改变)。

这应该可以工作,但请注意,在我的情况下,该程序是如此陷入困境,以至于它从未进入损坏的部分,因此B 的观察点从未被触发。 YMMV。

回到现实世界,没有人用 gdb 做过如此复杂的事情。这里的教训是:(1)了解那里有哪些工具。 Valgrind 很棒,我完全不确定任何 C 程序员,包括我自己,在没有它的情况下是如何应对的。 (2) 仔细考虑问题域及其与您尝试使用的工具的关系。如果该工具不适合,请使用或编写其他内容。不要让语言欺骗你:仅仅因为你在“调试”并不意味着你应该用“调试器”来做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-08
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 2012-03-13
    • 1970-01-01
    • 2012-05-02
    相关资源
    最近更新 更多