【问题标题】:gdb how to print variable name along with variable value like "$number = variable-name = variable-value"gdb如何打印变量名称以及变量值,例如“$number = variable-name = variable-value”
【发布时间】:2020-05-25 13:50:57
【问题描述】:

默认情况下,使用p variable-name 将显示$num = variable-value$numvalue history,但它有一种方法可以打印变量名称以及变量值,例如$num = variable-name = variable-value

我想要这个,因为我使用了

define p
  set $i = 0
  while $i < $argc
    eval "print $arg%d", $i
    set $i = $i + 1
  end
end

在我的 ~/.gdbinit 中,重新定义 p 命令,以便我可以使用 p var1 var2 var3... 一次打印多个变量,但打印命令只输出 $num = variable-value,我不知道确切的变量在什么输出,另一种情况是当我只使用 p $num 打印值历史时,它不那么可读,我不知道确切的变量名称。

注意:变量可能是 int/char/pointer/array/vector/...

【问题讨论】:

    标签: gdb


    【解决方案1】:

    一种解决方案可能是首先将所需变量添加到显示列表中,然后将所有这些变量一起显示。请注意,之前需要使用undisplay 释放显示列表,否则它还会打印之前执行的变量。

    define p
      set confirm off
      eval "undisplay"
      set confirm on
      set $i = 0
      while $i < $argc
        eval "display $arg%d", $i
        set $i = $i + 1
      end
      display
    end
    

    undisplay 评估包含在 set confirm off/on 之间以禁止显示以下消息:

    [answered Y; input not from terminal]
    

    如果您已经在 ~/gdbinit 文件中设置了 confirm off 选项,则需要删除这两行。

    编辑:老实说,我知道display 命令正在为这个问题寻找解决方案。虽然这个答案对于打印具有各自名称的多个变量可能很有用,但在我的工作流程中使用display 几天后,我不鼓励使用这个答案,因为我得出的结论是display 本身至少更适合我的需求(在每一站打印多个变量)。这里official doc

    如果您发现要经常打印表达式的值(以查看它如何变化),您可能希望将其添加到自动显示列表中,以便 GDB 在每次程序停止时打印其值。添加到列表中的每个表达式都有一个编号来标识它;要从列表中删除表达式,请指定该数字。自动显示如下:
    2:foo = 38
    3: bar[5] = (struct hack *) 0x3804

    基本上,我已经开始使用这样的命令:我将带有display $var 的变量添加到变量列表中,并且每次到达断点时都会自动打印列出的变量。在 gdb 中拥有这样的功能是有意义的。感谢@CodyChan 的鼓励。

    【讨论】:

      【解决方案2】:

      简而言之,我们要输出

      $num = variable-name = variable-value
      

      而不是

      $num = variable-value
      

      据我所知,gdb 仅在三个地方添加了值历史记录:print 命令、call 命令和history-append! Scheme 函数。由于我的 Scheme 已生锈,我们需要使用 CLI 或 Python 来运行 print 并修改其输出。

      使用 CLI

      define pp
        set $i = 0
        while $i < $argc
          eval "pipe print $arg%d | awk -v name='$arg%d' '{ if (NR == 1 && $2 == \"=\") { $2 = \"= \" name \" =\" }; print }'", $i, $i
          set $i++
        end
      end
      

      Pipe 是 gdb 10 中的新功能。

      那个 awk 命令是,在取消转义之后,

      awk -v name='$arg%d' '{ if (NR == 1 && $2 == "=") { $2 = "= " name " =" }; print }'
      

      $num = variable-value 中的=(第二个字段)更改为= variable-name =。如果 gdb 的 print 命令输出多行,则 awk 命令中的 NR == 1 确保仅在第一行进行替换。

      安全说明:gdb 的 pipe 命令似乎将 shell_command 解析为令牌并使用 execve 运行它,而不是将其传递给实际的 shell。这可以防止一些代码注入攻击(例如,如果name='$arg%d' 中的$arg%d 包含单引号),但您应该小心运行任何包含未经审查的文本的shell 命令。

      使用 Python

      class PP(gdb.Command):
        """print value history index, name, and value of each arg"""
      
        def __init__(self):
          super(PP, self).__init__("pp", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION)
      
        def invoke(self, argstr, from_tty):
          for arg in gdb.string_to_argv(argstr):
            line = gdb.execute("print " + arg, from_tty=False, to_string=True)
            line = line.replace("=", "= " + arg + " =", 1)
            gdb.write(line)
      
      PP()
      

      在这里,我们使用了更类似于sed 的方法,使用string.replace

      示例会话:

      (gdb) set args a b c
      (gdb) start
      Starting program: /home/mp/argprint a b c
      
      Temporary breakpoint 2, main (argc=4, argv=0x7ffffffee278) at argprint.c:4
      4               for(int i=0; i < argc; i++) {
      (gdb) pp i argc argv argv[0]@argc
      $1 = i = 0
      $2 = argc = 4
      $3 = argv = (char **) 0x7ffffffee278
      $4 = argv[0]@argc = {0x7ffffffee49f "/home/mp/argprint", 0x7ffffffee4b1 "a", 0x7ffffffee4b3 "b", 0x7ffffffee4b5 "c"}
      

      【讨论】:

        猜你喜欢
        • 2020-06-06
        • 1970-01-01
        • 2019-06-04
        • 1970-01-01
        • 1970-01-01
        • 2023-01-15
        • 2015-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多