Как заставить gdb печатать непечатаемые символы строки в шестнадцатеричном виде вместо восьмеричного, сохраняя символы ascii в форме ascii?
Предположим, что у меня есть буфер buf
, чье строковое представление
char* buf = "Hello World \x1c"
Когда я печатаю этот buf в gdb с помощью команды p buf
, я получаю следующее
$1 = "Hello World \034"
Есть ли команда печати или параметр gdb, который будет печатать следующее вместо?
$1 = "Hello World \x1c"
Я пробовал различные параметры формата, такие как /c
и /x
, но ни один из них не получил эффект, который я ищу. Я также играл с printf, но не смог добиться желаемого эффекта.
Обновление: я использую "GNU gdb (GDB) 7.0.1-debian".
Обновление:
Я тоже играл с х.
Если я делаю x/c
, он печатает восьмеричные и десятичные значения для непечатаемых символов, а затем печатает печатные символы с ascii и decimal.
Если я делаю x/s
, он выводит точно так же, как и команда p.
Если я делаю x/x
, он просто выводит hex, но затем мы теряем символы ascii для печатаемой части.
Обновление: эта ссылка, если она не является неполной, предполагает, что то, чего я хочу, недоступно, но может ли кто-нибудь подтвердить?
Ответы
Ответ 1
В отсутствие существующего решения я создал эту команду gdb, которая печатает ascii и hex для строк, которые содержат смешанные печатные символы ascii и непечатаемые символы. Источник воспроизводится ниже.
from __future__ import print_function
import gdb
import string
class PrettyPrintString (gdb.Command):
"Command to print strings with a mix of ascii and hex."
def __init__(self):
super (PrettyPrintString, self).__init__("ascii-print",
gdb.COMMAND_DATA,
gdb.COMPLETE_EXPRESSION, True)
gdb.execute("alias -a pp = ascii-print", True)
def invoke(self, arg, from_tty):
arg = arg.strip()
if arg == "":
print("Argument required (starting display address).")
return
startingAddress = gdb.parse_and_eval(arg)
p = 0
print('"', end='')
while startingAddress[p] != ord("\0"):
charCode = int(startingAddress[p].cast(gdb.lookup_type("char")))
if chr(charCode) in string.printable:
print("%c" % chr(charCode), end='')
else:
print("\\x%x" % charCode, end='')
p += 1
print('"')
PrettyPrintString()
Чтобы использовать это, можно просто поместить source AsciiPrintCommand.py
а затем запустить следующее в gdb. Для удобства можно поместить $HOME/.gdbinit
выше исходную команду в их $HOME/.gdbinit
.
ascii-print buf
"Hello World \x1c"
Ответ 2
Вы можете использовать команду x
, чтобы выгрузить память, на которую ссылаются ваши строковые ориентиры:
(gdb) x/32xb buf
показывает первые 32 байта.
См.
(gdb) help x
для деталей
Ответ 3
Небольшой вариант ответа OP для варианта использования 8-битных массивов, которые не обязательно заканчиваются при первом появлении \0
, и который также пытается print elements
print repeats
и параметры print repeats
в GDB:
from __future__ import print_function
def print_extended_ascii_char(charCode):
if charCode == ord('"'): return r'\"'
if charCode == ord('\\'): return r'\\'
if 32 <= charCode <= 126: return "%c" % charCode
return r"\x%02x" % charCode
def get_gdb_value(command, output_re):
try:
import re
s = gdb.execute(command, to_string=True)
m = re.match(output_re, s)
value = m.group(1)
if value != 'unlimited':
value = int(value)
return value
except Exception as e:
print("Sorry, ran into an error running '%s' and getting the value." % command)
raise e
class PrettyPrintString(gdb.Command):
"""Command to print an array of 8-bit bytes, using ASCII when possible and hex otherwise.
https://stackoverflow.com/a/54469844/4958"""
def __init__(self):
super (PrettyPrintString, self).__init__(name="ascii-print",
command_class=gdb.COMMAND_DATA,
completer_class=gdb.COMPLETE_EXPRESSION, prefix=True)
def invoke(self, arg, from_tty):
if not arg.strip():
print("What do you want me to print?")
return
limit = get_gdb_value('show print elements', 'Limit on string chars or array elements to print is (.*).\n')
repeats = get_gdb_value('show print repeats', 'Threshold for repeated print elements is (.*).\n')
start = gdb.parse_and_eval(arg)
p = 0
print('"', end='')
i = 0
unprinted = (None, 0)
while i < start.type.sizeof:
i += 1
charCode = int(start[p])
toPrint = print_extended_ascii_char(charCode)
if toPrint == unprinted[0]:
unprinted = (toPrint, unprinted[1] + 1)
else:
if unprinted[0] is not None:
print(unprinted[0] * min(unprinted[1], limit - (i - unprinted[1])), end='')
if i > limit:
print('...', end='')
break
unprinted = (toPrint, 1)
p += 1
if i - unprinted[1] > limit or unprinted[0] is None:
print('"')
elif repeats == 'unlimited' or unprinted[1] < repeats:
print(unprinted[0] * unprinted[1], end='')
print('"')
else:
print('",')
print("'%s' <repeats %d times>" % (unprinted[0], unprinted[1] - 1))
PrettyPrintString()
Как и прежде, поместите вышеприведенное в некоторый файл (скажем, ~/.gdb-AsciiPrint.py
) и либо запустите source ~/.gdb-AsciiPrint.py
либо поместите этот оператор в файл .gdbinit
. Результат/сравнения:
(gdb) p tokmem[3]
$1 = "\000\030\000-1\320\a\200\031:\200\032[\200\024]\200\033\200\023;\200\034:\200\032[\200\023]\200\033\200\024;\320\r\200$:\200\030;\320\020\200 k\030\060\200!255\200\"\200\r\200\060(k:3,': \"');l\030k;\200+(\250\061)\200,\200\r\200\060(\200\034[\200\062],\200\034[\200\062]);\200+k<\f100\200,l\030k+\f100\200.\200+k<\f200\200,l\030k-\f100\200.\200\r\200*(k\200\063\061\066);\200\060(\200\034[l]);\200*(k\200\064\061\066);\200\020(\200$);\200\017;\200$\030\200$+2;\200\017;\200+l=\200\065\200,\200\060(\200\034[l],\200\034[l])\200.\200\060(\200\034[l]);\200\020(\200$);\200&('\"');\200\017", '\000' <repeats 65285 times>
(gdb) ascii-print tokmem[3]
"\x00\x18\x00-1\xd0\x07\x80\x19:\x80\x1a[\x80\x14]\x80\x1b\x80\x13;\x80\x1c:\x80\x1a[\x80\x13]\x80\x1b\x80\x14;\xd0\x0d\x80$:\x80\x18;\xd0\x10\x80 k\x180\x80!255\x80\"\x80\x0d\x800(k:3,': \"');l\x18k;\x80+(\xa81)\x80,\x80\x0d\x800(\x80\x1c[\x802],\x80\x1c[\x802]);\x80+k<\x0c100\x80,l\x18k+\x0c100\x80.\x80+k<\x0c200\x80,l\x18k-\x0c100\x80.\x80\x0d\x80*(k\x80316);\x800(\x80\x1c[l]);\x80*(k\x80416);\x80\x10(\x80$);\x80\x0f;\x80$\x18\x80$+2;\x80\x0f;\x80+l=\x805\x80,\x800(\x80\x1c[l],\x80\x1c[l])\x80.\x800(\x80\x1c[l]);\x80\x10(\x80$);\x80&('\"');\x80\x0f",
'\x00' <repeats 65285 times>
Это немного странно, так что, надеюсь, эта функция будет добавлена в саму GDB.
(В сторону: Некоторое время назад я задал аналогичный вопрос для Emacs, и один из людей, который видел этот вопрос, представил патч для Emacs. Похоже, что восьмеричное в наши дни менее популярно, чем раньше; например, JavaScript устарел восьмеричным escape-последовательности для строковых литералов.)
Ответ 4
вы можете распечатать буфер как строку с помощью команды: print/s. Следовательно
$ print /s buf
должен решить вашу проблему.