如何在保留ascii形式的ascii字符的同时使gdb以十六进制而不是八进制打印字符串的不可打印字符?

时间:2013-04-16 07:24:40

标签: c string debugging assembly gdb

假设我有一个缓冲区buf,其c字符串表示为

 char* buf = "Hello World \x1c"

当我使用命令p buf在gdb中打印此buf时,我得到以下内容

 $1 = "Hello World \034"

是否有打印命令或gdb设置会打印以下内容?

$1 = "Hello World \x1c"

我尝试了各种格式参数,例如/c/x,但它们都没有达到我想要的效果。我也玩过printf但是无法达到预期的效果。

更新:我正在使用“GNU gdb(GDB)7.0.1-debian”。

更新: 我也玩过x。

如果我x/c,它会为非打印字符打印八进制和十进制,然后打印带有ascii和decimal的可打印字符。

如果我x/s,它输出与p命令完全相同。

如果我x/x它只输出十六进制但我们丢失了可打印部分的ascii字符。

更新:此reference,除非不完整,否则表示我想要的内容不可用,但有人可以确认吗?

5 个答案:

答案 0 :(得分:6)

在没有现有解决方案的情况下,我创建了this gdb command,它为具有混合可打印ascii和不可打印字符的字符串输出ascii和hex。来源转载如下。

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

ascii-print buf
"Hello World \x1c"

答案 1 :(得分:4)

您可以使用x命令转储字符串引用指向的内存:

(gdb) x/32xb buf

显示前32个字节。

(gdb) help x

了解详情。

答案 2 :(得分:4)

对于在GDB中与八进制转义序列有共同点的其他人,很容易解决(如果您准备自己构建GDB):在gdb / valprint.c中,找到注释:

/* If the value fits in 3 octal digits, print it that
                     way.  Otherwise, print it as a hex escape.  */

并注释掉以下4行-所有转义序列都将以十六进制打印。

答案 3 :(得分:1)

OP答案的一个小变化,适用于8位数组的用例,这些数组不一定在第一次出现[i][j]时就终止,并且还尝试遵守\0和GDB的print elements参数:

print repeats

像以前一样,将以上内容放入某个文件(例如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

这有点hacky,因此希望该功能将被添加到GDB本身。

(在旁边:我问a similar question for Emacs,看到这个问题的人中的一个人提出了a patch to Emacs。如今,八进制似乎比以前不那么流行了;例如JavaScript的字符串文字有deprecated octal个转义序列。)

答案 4 :(得分:1)

根据您在字符串中显示非 ascii 字符的原因,一种稍微不同的方法可能是使用不同的编码打印字符串。

就我而言,我想查看十六进制值以确保字符串是在 UTF-8 环境中使用 ISO8859-1 编码的。尽管 GDB has encoding,但它并非旨在或可用于此目的。

在探索由 OP 和 ShreevatsaR 创建的 gdb 命令时,我发现了 Value.string() function 将 GDB 值打印为字符串(如果它是字符串)。您可以给它一个编码选项,以便以下 Python 代码向 GDB 添加一个 isostring 命令:

from __future__ import print_function

class PrettyPrintString(gdb.Command):
    """Command to print an array of 8-bit bytes as ISO8859-1"""

    def __init__(self):
        super (PrettyPrintString, self).__init__(name="isostring",
                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
        value = gdb.parse_and_eval(arg)
        print('"' + value.string("iso8859-1")+ '"')

PrettyPrintString()