バイナリ形式のメッセージを含むが、文字列データも含むバッファを検査しようとしています。例として、私はこのCコードを使用しています:
int main (void) {
char buf[100] = "\x01\x02\x03\x04String Data\xAA\xBB\xCC";
return 0;
}
buf
に似た形式のxxd
にある16進ダンプを取得したいです(完全に一致するかどうかは気にしません。本当に探しているのは印刷可能な文字を並べた16進ダンプ)。
GDB内では、次のようなものを使用できます。
(gdb) x /100bx buf
0x7fffffffdf00: 0x01 0x02 0x03 0x04 0x53 0x74 0x72 0x69
0x7fffffffdf08: 0x6e 0x67 0x20 0x44 0x61 0x74 0x61 0xaa
0x7fffffffdf10: 0xbb 0xcc 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
それは問題ありませんが、そのように文字列を選ぶのは難しいです...または私は使用することができます
(gdb) x /100bs buf
0x7fffffffdf00: "\001\002\003\004String Data\252\273\314"
0x7fffffffdf13: ""
0x7fffffffdf14: ""
0x7fffffffdf15: ""
0x7fffffffdf16: ""
0x7fffffffdf17: ""
...
バイナリ部分を読むのが難しくなります...私が扱っている実際のメッセージにも多くのアスキー文字が含まれているので、本当に混乱のように見えます。
私が思いつくことができる最善の方法はこれを行うことです:
(gdb) dump binary memory dump.bin buf buf+100
その後
$ xxd dump.bin
0000000: 0102 0304 5374 7269 6e67 2044 6174 61aa ....String Data.
0000010: bbcc 0000 0000 0000 0000 0000 0000 0000 ................
0000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000060: 0000 0000 ....
しかし、それを毎回行うのは苦痛です。私は以前に誰かがこれを望んでいたと考えていたので、誰かがgdb内でそれを行う方法を見つけたかどうか疑問に思いました。さらに、この方法で元のメモリからアドレスを失います。
私はGDB 7.4をpythonサポートを組み込みで使用しているので、きれいなプリンターなどを使用するという考えに心を開いていますが、その設定方法はわかりません。
(gdb) define xxd
>dump binary memory dump.bin $arg0 $arg0+$arg1
>Shell xxd dump.bin
>end
(gdb) xxd &j 10
0000000: 0000 0000 0000 0000 0000 0000 4d8c a7f7 ............M...
0000010: ff7f 0000 0000 0000 0000 0000 c8d7 ffff ................
0000020: ff7f 0000 0000 0000
簡単そう;-)
Pythonスクリプト(現代のGDBバージョンにはPythonインタープリターが組み込まれています)を記述して同じことを行い、「シェルアウト」する必要性を取り除くことができます。 。
だから、pythonインターフェースで遊んで、これを思いついた:
import gdb
from curses.ascii import isgraph
def groups_of(iterable, size, first=0):
first = first if first != 0 else size
chunk, iterable = iterable[:first], iterable[first:]
while chunk:
yield chunk
chunk, iterable = iterable[:size], iterable[size:]
class HexDump(gdb.Command):
def __init__(self):
super (HexDump, self).__init__ ('hex-dump', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
if len(argv) != 2:
raise gdb.GdbError('hex-dump takes exactly 2 arguments.')
addr = gdb.parse_and_eval(argv[0]).cast(
gdb.lookup_type('void').pointer())
try:
bytes = int(gdb.parse_and_eval(argv[1]))
except ValueError:
raise gdb.GdbError('Byte count numst be an integer value.')
inferior = gdb.selected_inferior()
align = gdb.parameter('hex-dump-align')
width = gdb.parameter('hex-dump-width')
if width == 0:
width = 16
mem = inferior.read_memory(addr, bytes)
pr_addr = int(str(addr), 16)
pr_offset = width
if align:
pr_offset = width - (pr_addr % width)
pr_addr -= pr_addr % width
for group in groups_of(mem, width, pr_offset):
print '0x%x: ' % (pr_addr,) + ' '*(width - pr_offset),
print ' '.join(['%02X' % (ord(g),) for g in group]) + \
' ' * (width - len(group) if pr_offset == width else 0) + ' ',
print ' '*(width - pr_offset) + ''.join(
[g if isgraph(g) or g == ' ' else '.' for g in group])
pr_addr += width
pr_offset = width
class HexDumpAlign(gdb.Parameter):
def __init__(self):
super (HexDumpAlign, self).__init__('hex-dump-align',
gdb.COMMAND_DATA,
gdb.PARAM_BOOLEAN)
set_doc = 'Determines if hex-dump always starts at an "aligned" address (see hex-dump-width'
show_doc = 'Hex dump alignment is currently'
class HexDumpWidth(gdb.Parameter):
def __init__(self):
super (HexDumpWidth, self).__init__('hex-dump-width',
gdb.COMMAND_DATA,
gdb.PARAM_INTEGER)
set_doc = 'Set the number of bytes per line of hex-dump'
show_doc = 'The number of bytes per line in hex-dump is'
HexDump()
HexDumpAlign()
HexDumpWidth()
私はそれが最も美しくエレガントなソリューションではないかもしれないことを理解していますが、それは仕事を完了させ、最初のドラフトとして機能します。次のような~/.gdbinit
に含めることができます。
python
sys.path.insert(0, '/path/to/module/dir')
import hexdump
end
次に、上記のプログラムで次のように使用できます。
(gdb) hex-dump buf 100
0x7fffffffdf00: 01 02 03 04 53 74 72 69 6E 67 20 44 61 74 61 AA ....String Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf60: 00 00 00 00 ....
そして、適切な測定のための他のいくつかのタッチ:
(gdb) set hex-dump-align on
Determines if hex-dump always starts at an "aligned" address (see hex-dump-width
(gdb) hex-dump &buf[5] 95
0x7fffffffdf00: 74 72 69 6E 67 20 44 61 74 61 AA tring Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf60: 00 00 00 00 ....
(gdb) set hex-dump-width 8
Set the number of bytes per line of hex-dump
(gdb) hex-dump &buf[5] 95
0x7fffffffdf00: 74 72 69 tri
0x7fffffffdf08: 6E 67 20 44 61 74 61 AA ng Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 ........
0x7fffffffdf18: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf20: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf28: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf30: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf38: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf40: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf48: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf50: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf58: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf60: 00 00 00 00 ....
バグがないという約束はありません:)。人々が興味を持っているなら、私はそれをgithubか何かに貼り付けるかもしれません。
GDB 7.4でのみテストしました。
ユーザーFatalErrorのソリューションの適応バージョン
例
hd 0xbfffe4f1
hd 0xbfffe4f1 500
import gdb
from curses.ascii import isgraph
def groups_of(iterable, size, first=0):
first = first if first != 0 else size
chunk, iterable = iterable[:first], iterable[first:]
while chunk:
yield chunk
chunk, iterable = iterable[:size], iterable[size:]
class HexDump(gdb.Command):
def __init__(self):
super (HexDump, self).__init__ ('hd', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
addr = gdb.parse_and_eval(argv[0]).cast(
gdb.lookup_type('void').pointer())
if len(argv) == 2:
try:
bytes = int(gdb.parse_and_eval(argv[1]))
except ValueError:
raise gdb.GdbError('Byte count numst be an integer value.')
else:
bytes = 500
inferior = gdb.selected_inferior()
align = gdb.parameter('hex-dump-align')
width = gdb.parameter('hex-dump-width')
if width == 0:
width = 16
mem = inferior.read_memory(addr, bytes)
pr_addr = int(str(addr), 16)
pr_offset = width
if align:
pr_offset = width - (pr_addr % width)
pr_addr -= pr_addr % width
start=(pr_addr) & 0xff;
print (' ' , end="")
print (' '.join(['%01X' % (i&0x0f,) for i in range(start,start+width)]) , end="")
print (' ' , end="")
print (' '.join(['%01X' % (i&0x0f,) for i in range(start,start+width)]) )
for group in groups_of(mem, width, pr_offset):
print ('0x%x: ' % (pr_addr,) + ' '*(width - pr_offset), end="")
print (' '.join(['%02X' % (ord(g),) for g in group]) + \
' ' * (width - len(group) if pr_offset == width else 0) + ' ', end="")
print (' '*(width - pr_offset) + ' '.join(
[chr( int.from_bytes(g, byteorder='big')) if isgraph( int.from_bytes(g, byteorder='big') ) or g == ' ' else '.' for g in group]))
pr_addr += width
pr_offset = width
class HexDumpAlign(gdb.Parameter):
def __init__(self):
super (HexDumpAlign, self).__init__('hex-dump-align',
gdb.COMMAND_DATA,
gdb.PARAM_BOOLEAN)
set_doc = 'Determines if hex-dump always starts at an "aligned" address (see hex-dump-width'
show_doc = 'Hex dump alignment is currently'
class HexDumpWidth(gdb.Parameter):
def __init__(self):
super (HexDumpWidth, self).__init__('hex-dump-width',
gdb.COMMAND_DATA,
gdb.PARAM_INTEGER)
set_doc = 'Set the number of bytes per line of hex-dump'
show_doc = 'The number of bytes per line in hex-dump is'
HexDump()
HexDumpAlign()
HexDumpWidth()
残念ながら、@ FatalErrorおよび@gunthorのバージョンは私にとってはうまくいきませんでした。これはどのように見えるかです:
(gdb) xxd hello_string 0xc
00000001_00000f87: 48 656c 6c6f 0957 6f72 Hello.Wor
00000001_00000f90: 6c64 0a ld.
xxd
の新しいバージョンは、-o
フラグをサポートします。これにより、表示されるオフセットに追加するオフセットを指定できます(常に0000000
で始まります)。
xxd -o
が利用できない場合は、xxd
'dである場所の住所を正しく調整して表示する代替手段があります。
xxd
コマンド:
define xxd
dump binary memory /tmp/dump.bin $arg0 $arg0+$arg1
eval "Shell xxd-o %p /tmp/dump.bin", $arg0
end
間違いなくいPerlスクリプト xxd-o
(xxd
with offset):
#!/usr/bin/env Perl
use IPC::Open2;
$SIG{'__WARN__'} = sub{ die "$0: $!\n" };
my $offset = shift // "0";
$offset = oct($offset) if $offset =~ /^0/;
my $base = $offset >= 2**32 ? 16 : 8;
my $zeroes = $offset % 16;
my $padding = 1 + int($zeroes / 2) + 2*$zeroes;
my $bytestr = "\0" x $zeroes;
{ local $/; $bytestr .= <> }
open2(\*XXD_OUT, \*XXD_IN, "xxd") or die "xxd is not available!";
print XXD_IN $bytestr; close XXD_IN;
if ($zeroes) {
$_ = <XXD_OUT>;
s/^(.{50}).{$zeroes}/$1 . (' ' x $zeroes)/ge;
s/^([[:xdigit:]]+:).{$padding}/$1 . (' ' x $padding)/ge;
my $newoff = sprintf("%0${base}x",hex($1)+$offset) =~ s/^(.{8})(.{8})$/$1_$2/r;
s/^([[:xdigit:]]+):/$newoff:/g;
print
}
while (<XXD_OUT>) {
s/^([[:xdigit:]]+)(?=:)/sprintf("%0${base}x", hex($1)+$offset-$offset%16) =~ s[^(.{8})(.{8})$][$1_$2]r/ge;
print
}
改善を歓迎します! :-)
Employed RussianソリューションおよびRoger Lipscombeコメントからの私自身の貢献:
スクリプト(gdb 7.8.1でテスト済み):
define xxd
if $argc < 2
set $size = sizeof(*$arg0)
else
set $size = $arg1
end
dump binary memory dump.bin $arg0 ((void *)$arg0)+$size
eval "Shell xxd -o %d dump.bin; rm dump.bin", ((void *)$arg0)
end
document xxd
Dump memory with xxd command (keep the address as offset)
xxd addr [size]
addr -- expression resolvable as an address
size -- size (in byte) of memory to dump
sizeof(*addr) is used by default
end
例:
(gdb) p &m_data
$1 = (data_t *) 0x200130dc <m_data>
(gdb) p sizeof(m_data)
$2 = 32
(gdb) xxd &m_data 32
200130dc: 0300 0000 e87c 0400 0000 0000 0100 0000 .....|..........
200130ec: 0c01 0000 b831 0020 0100 0000 0100 0000 .....1. ........
(gdb) xxd &m_data
200130dc: 0300 0000 e87c 0400 0000 0000 0100 0000 .....|..........
200130ec: 0c01 0000 b831 0020 0100 0000 0100 0000 .....1. ........
(gdb) help xxd
Dump memory with xxd command (keep the address as offset)
xxd addr [size]
addr -- expression resolvable as an address
size -- size (in byte) of memory to dump
sizeof(*addr) is used by default