Memory dump formatted like xxd from gdb Memory dump formatted like xxd from gdb python python

Memory dump formatted like xxd from gdb


(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

Seems easy enough ;-)

You could likely write a Python script (modern GDB versions have embedded Python interpreter) to do the same, and get rid of the need to "shell out".


So, I ended up playing around with the python interface and came up with this:

import gdbfrom curses.ascii import isgraphdef 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 = widthclass 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()

I realize it might not be the most beautiful and elegant solution, but it gets the job done and works as a first draft. It could be included in ~/.gdbinit like:

pythonsys.path.insert(0, '/path/to/module/dir')import hexdumpend

Then could be used with the program above like so:

(gdb) hex-dump buf 1000x7fffffffdf00:  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                                      ....

And a few other touches for good measure:

(gdb) set hex-dump-align onDetermines if hex-dump always starts at an "aligned" address (see hex-dump-width(gdb) hex-dump &buf[5] 950x7fffffffdf00:                 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 8Set the number of bytes per line of hex-dump(gdb) hex-dump &buf[5] 950x7fffffffdf00:                 74 72 69       tri0x7fffffffdf08:  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              ....

No promises that there aren't bugs :). I might stick it up in github or something if people are interested.

I've only tested it with GDB 7.4.


My own contribution, from Employed Russian solution and Roger Lipscombe comments:

  • use xxd,
  • preserve the address (xxd -o)
  • size argument is optional
  • small documentation included

The script (tested with 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)enddocument 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 defaultend

Examples:

(gdb) p &m_data$1 = (data_t *) 0x200130dc <m_data>(gdb) p sizeof(m_data)$2 = 32(gdb) xxd &m_data 32200130dc: 0300 0000 e87c 0400 0000 0000 0100 0000  .....|..........200130ec: 0c01 0000 b831 0020 0100 0000 0100 0000  .....1. ........(gdb) xxd &m_data200130dc: 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