gdb 如何打印变量名和变量值,如“$number = variable-name = variable-value”

gdb how to print variable name along with variable value like "$number = variable-name = variable-value"

默认情况下,使用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/...

一种解决方案是先将需要的变量添加到显示列表,然后将它们全部显示在一起。注意,在使用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:

If you find that you want to print the value of an expression frequently (to see how it changes), you might want to add it to the automatic display list so that GDB prints its value each time your program stops. Each expression added to the list is given a number to identify it; to remove an expression from the list, you specify that number. The automatic display looks like this:
2: foo = 38
3: bar[5] = (struct hack *) 0x3804

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

简而言之shell,我们要输出

$num = variable-name = variable-value

而不是

$num = variable-value

据我所知,gdb 只在三个地方添加值历史记录:print 命令、call 命令和 history-append! 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 &&  == \"=\") {  = \"= \" name \" =\" }; print }'", $i, $i
    set $i++
  end
end

Pipe 是 gdb 10 中的新内容。

那个awk命令是,在unescaping之后,

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

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

安全说明:gdb 的 pipe 命令似乎将 shell_command 解析为标记并使用 execve 到 运行 它,而不是将其传递给实际的 shell。这可以防止某些代码注入攻击(例如,如果 name='$arg%d' 中的 $arg%d 包含单引号),但是您应该小心 运行ning 任何由以下内容组成的 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
 = i = 0
 = argc = 4
 = argv = (char **) 0x7ffffffee278
 = argv[0]@argc = {0x7ffffffee49f "/home/mp/argprint", 0x7ffffffee4b1 "a", 0x7ffffffee4b3 "b", 0x7ffffffee4b5 "c"}