gdb, как напечатать имя переменной вместе со значением переменной, например "$ number = имя-переменной = значение-переменной" - PullRequest
1 голос
/ 25 мая 2020

По умолчанию при использовании p variable-name будет отображаться $num = variable-value, $num - это история значений , но есть ли способ распечатать имя переменной вместе со значением переменной, например $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 /...

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Вкратце, мы хотим вывести

$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 && $2 == \"=\") { $2 = \"= \" name \" =\" }; print }'", $i, $i
    set $i++
  end
end

Pipe - это new в gdb 10.

Эта команда awk после отмены экранирования выглядит как

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

, которая изменяет = (второе поле) в $num = variable-value на = variable-name =. Если команда gdb print выводит более одной строки, NR == 1 в команде awk гарантирует, что подстановка выполняется только в первой строке.

Примечание по безопасности: команда gdb pipe, похоже, анализирует shell_command в токены и использует execve для его запуска, а не передает его реальной оболочке. Это предотвращает некоторые атаки внедрения кода (если, например, $arg%d в name='$arg%d' содержит одинарные кавычки), но вы должны быть осторожны при запуске любой команды оболочки, состоящей из текста, который вы не проверили.

Использование 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"}
1 голос
/ 28 мая 2020

Решением может быть сначала добавить в список отображения требуемые переменные, а затем отобразить их все вместе. Обратите внимание, что перед этим необходимо освободить список отображения с помощью 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]

Если вы уже установили параметр confirm off в ~ / gdbinit файл, вам нужно будет удалить эти две строки.

Изменить: Честно говоря, я узнал о команде display, которая нашла решение для этого вопроса. Хотя этот ответ может быть полезен для печати нескольких переменных с их соответствующими именами, после нескольких дней использования display в моем рабочем процессе я не рекомендую использовать этот ответ, так как я пришел к выводу, что display сам по себе лучше подходит, по крайней мере, моим потребностям (печать нескольких переменных на каждой остановке). Здесь официальный do c:

Если вы обнаружите, что хотите часто печатать значение выражения (чтобы увидеть, как оно меняется), вы можете добавить его в список автоматического c отображения, чтобы GDB печатал его значение каждый раз, когда ваша программа останавливается. Каждому выражению, добавленному в список, присваивается номер для его идентификации; чтобы удалить выражение из списка, укажите это число. Отображение automati c выглядит так:
2: foo = 38
3: bar [5] = (struct hack *) 0x3804

По сути, я начал использовать команду следующим образом: я добавляю переменную с display $var в список переменных, и каждый раз, когда достигается точка останова, перечисленные переменные автоматически печатаются. Имеет смысл иметь такую ​​возможность в gdb. Спасибо @CodyChan за мотивацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...