web-dev-qa-db-ja.com

アスキー文字をアスキー形式で保持しながら、gdbで文字列の印刷不可能な文字を8進数ではなく16進数で印刷するにはどうすればよいですか?

C文字列表現がであるバッファbufがあるとします。

 char* buf = "Hello World \x1c"

コマンドp bufを使用してこのbufをgdbに出力すると、次のようになります。

 $1 = "Hello World \034"

代わりに以下を出力するprintコマンドまたはgdb設定はありますか?

$1 = "Hello World \x1c"

/c/xなどのさまざまなフォーマットパラメータを試しましたが、どれも私が探している効果が得られません。私もprintfで遊んだことがありますが、目的の効果を得ることができませんでした。

更新:「GNUgdb(GDB)7.0.1-debian」を使用しています。

更新:私もxで遊んだことがあります。

x/cを実行すると、印刷できない文字の8進数と10進数が出力され、次にASCIIと10進数の印刷可能な文字が印刷されます。

x/sを実行すると、pコマンドとまったく同じように出力されます。

x/xを実行すると、16進数が出力されるだけですが、印刷可能な部分のASCII文字が失われます。

更新:これ 参照 は、不完全でない限り、私が望むものが利用できないことを示唆していますが、誰かが確認できますか?

21
merlin2011

既存のソリューションがないため、印刷可能なASCII文字と印刷不可能な文字が混在する文字列に対してasciiとhexを出力する このgdbコマンド を作成しました。ソースは以下に再現されています。

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"
6
merlin2011

xコマンドを使用して、文字列参照が指すメモリをダンプできます。

(gdb) x/32xb buf

は最初の32バイトを示しています。

見る

(gdb) help x

詳細については。

5
alk

GDBの8進エスケープシーケンスと苛立ちを共有している他の人にとっては、簡単に修正できます(GDBを自分でビルドする準備ができている場合):gdb/valprint.cで、コメントを見つけてください:

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

次の4行をコメントアウトします。すべてのエスケープシーケンスは16進数として出力されます。

3
Michael Haben

\0の最初の出現で必ずしも終了せず、GDBのprint elementsおよびprint repeatsパラメーターも尊重しようとする8ビット配列のユースケースに対するOPの回答の小さなバリエーション:

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の同様の質問 と尋ねました、そして質問を見た人の1人が Emacsへのパッチ です。8進数は少ないようです最近では以前よりも人気があります。たとえば、JavaScriptには 非推奨の8進数 文字列リテラルのエスケープシーケンスがあります。)

1
ShreevatsaR