【问题标题】:How to watch a member of a struct for every struct variable that has that type?如何查看具有该类型的每个结构变量的结构成员?
【发布时间】:2015-07-28 00:24:23
【问题描述】:

我正在损坏一个结构成员,其中结构用于构建一个 大树。我正在尝试设置观察点,但“变量”有 各种名称(我见过的所有示例都使用显式全局变量, 所以不要显示我正在寻找的示例)。

(gdb) 观看 *(OP*)->op.sibling 表达式中的语法错误,在 `->op.sibling' 附近。 (gdb) 观看 *(struct op*)->op.sibling 表达式中的语法错误,在 `->op.sibling' 附近。 (gdb) watch (struct op*)->op.sibling 表达式中的语法错误,在 `->op.sibling' 附近。

我最接近可接受的语法不起作用

(gdb) 观察 (struct op*)o->op.sibling 当前上下文中没有符号“o”。

是否存在我缺少的独立表达形式 变量名称,并注意它是一个特定的事实 什么样的结构?

这是否能够检测到结构的 memset 覆盖? (即使没有,也能帮我排除一些原因)

是否有超出基本用法的 gdb 参考? (对于一些'basic'的定义)

【问题讨论】:

    标签: gdb


    【解决方案1】:

    正如 ninjalj 所说,您确实必须有一个可以观看的地址;这就是观察点的全部意义所在。考虑以下示例:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef struct node {
      long value;
      struct node *next;
    } node;
    
    node *build_node(int x, node *next)
    {
      node *n = malloc(sizeof(*n));
      n->value = x;
      n->next = next;
      return n;
    }
    
    int main()
    {
      node *n = build_node(1, NULL);
      n = build_node(2, n);
      n = build_node(3, n);
    
      memset(&n->next->value, 0xFF, sizeof(long) + 3);  // corrupt the list
    
      return 0;
    }
    

    我在这里生成一个整数列表,然后破坏它。让我们看看这在 GDB 中是什么样子的:

    gdb -q ./a.out
    Reading symbols for shared libraries .. done
    (gdb) b main
    Breakpoint 1 at 0x100000e0c: file foo.c, line 20.
    (gdb) r
    Starting program: /tmp/a.out 
    Reading symbols for shared libraries +. done
    
    Breakpoint 1, main () at foo.c:20
    20    node *n = build_node(1, NULL);
    
    (gdb) b 26
    Breakpoint 2 at 0x100000e8d: file foo.c, line 26.
    (gdb) c
    Continuing.
    
    Breakpoint 2, main () at foo.c:26
    26    return 0;
    (gdb) p *n
    $1 = {
      value = 3, 
      next = 0x100100090
    }
    (gdb) p *n.next
    $2 = {
      value = -1, 
      next = 0x100ffffff
    }
    

    在这里我们清楚地看到n-&gt;next 已被彻底损坏。假设我们不知道发生在哪里,并想通过 GDB 观察点找出来。

    首先,我们需要建立已损坏的地址:

    (gdb) print &n.next.value
    $3 = (long int *) 0x100100090
    (gdb) watch *$3
    Hardware watchpoint 3: *$3
    

    这里我只是在地址 0x100100090 上设置了一个 8 个字节的观察点。

    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /private/tmp/a.out 
    warning: Could not set watchpoint 3
    warning: Could not set watchpoint 3
    
    Breakpoint 1, main () at foo.c:20
    20    node *n = build_node(1, NULL);
    

    我使用的是相当旧的 GDB 版本,它不知道如何在程序重新启动时正确禁用和重新启用硬件观察点。如果您使用更新的版本,您可能不会看到上述警告。当我在断点 1 处停止时,我可以简单地重新启用观察点:

    (gdb) enable 3
    (gdb) c
    Continuing.
    Hardware watchpoint 3: *$3
    
    Old value = 0
    New value = 2
    build_node (x=2, next=0x100100080) at foo.c:14
    14    n->next = next;
    

    好的,我们已经达到了预期点和预期值。下一次修改会破坏它,我们想知道发生了什么。

    (gdb) c
    Continuing.
    Hardware watchpoint 3: *$3
    
    Old value = 2
    New value = 255
    0x00007fff82fae450 in memset ()
    (gdb) bt
    #0  0x00007fff82fae450 in memset ()
    #1  0x0000000100000ebe in __inline_memset_chk (__dest=0x100100090, __val=255, __len=11) at _string.h:80
    #2  0x0000000100000e8d in main () at foo.c:24
    

    瞧,你现在知道意外修改的来源了。

    【讨论】:

      【解决方案2】:

      您希望它如何工作? gdb 观察点转换为适当的硬件调试观察点,即它们是内存地址。因此,它们旨在覆盖内存区域,而不是数据类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-19
        • 2021-08-22
        • 2013-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多