python debugging gdb pretty-print

python - Volcado de memoria formateado como xxd desde gdb



debugging pretty-print (4)

Desafortunadamente, las versiones de @ FatalError y @ gunthor no me funcionaron, así que escribí otra más. Así es como esto luce:

(gdb) xxd hello_string 0xc 00000001_00000f87: 48 656c 6c6f 0957 6f72 Hello.Wor 00000001_00000f90: 6c64 0a ld.

Las versiones más recientes de xxd admiten el indicador -o que permite especificar un desplazamiento para agregar al visualizado (que siempre comenzará en 0000000 ).

En caso de que xxd -o no esté disponible, aquí hay un sustituto que se alinea correctamente y muestra la dirección de la ubicación que es xxd ''d.

El comando xxd :

define xxd dump binary memory /tmp/dump.bin $arg0 $arg0+$arg1 eval "shell xxd-o %p /tmp/dump.bin", $arg0 end

La secuencia de comandos de perl posiblemente feo xxd-o ( xxd con desplazamiento):

#!/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 }

Mejoras bienvenidas! :-)

Estoy intentando inspeccionar un buffer que contiene un mensaje con formato binario, pero también contiene datos de cadena. Como ejemplo, estoy usando este código C:

int main (void) { char buf[100] = "/x01/x02/x03/x04String Data/xAA/xBB/xCC"; return 0; }

Me gustaría obtener un volcado hexadecimal de lo que está en buf , de un formato similar a xxd (no me importa si es una coincidencia exacta, lo que realmente estoy buscando es un volcado hexadecimal al lado del otro con caracteres imprimibles) .

Dentro de GDB puedo usar algo como:

(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

lo cual está bien, pero es difícil elegir cadenas de esa manera ... o puedo usar

(gdb) x /100bs buf 0x7fffffffdf00: "/001/002/003/004String Data/252/273/314" 0x7fffffffdf13: "" 0x7fffffffdf14: "" 0x7fffffffdf15: "" 0x7fffffffdf16: "" 0x7fffffffdf17: "" ...

lo que hace que sea difícil leer la parte binaria ... los mensajes reales con los que estoy lidiando tienen un montón de ascii nul también, así que realmente parece un desastre.

Lo mejor que se me ocurre es hacer esto:

(gdb) dump binary memory dump.bin buf buf+100

y entonces

$ 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 ....

pero eso es un dolor hacer eso cada vez. Pensé que alguien por ahí quería esto antes, así que me pregunto si alguien ha encontrado la manera de hacerlo dentro de gdb. Además, pierde las direcciones de la memoria original de esta manera.

Estoy usando GDB 7.4 con soporte de python integrado, por lo que estoy abierto a la idea de usar una impresora bonita o similar, pero no sé cómo configurarlo.


Entonces, terminé jugando con la interfaz de python y se me ocurrió esto:

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()

Me doy cuenta de que puede que no sea la solución más bella y elegante, pero hace el trabajo y funciona como un primer borrador. Podría incluirse en ~/.gdbinit como:

python sys.path.insert(0, ''/path/to/module/dir'') import hexdump end

Entonces podría ser utilizado con el programa anterior como así:

(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 ....

Y algunos otros toques para una buena medida:

(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 ....

No hay promesas de que no haya errores :). Podría ponerlo en github o algo si la gente está interesada.

Solo lo he probado con GDB 7.4.


una versión adaptada de la solución de User FatalError

  • funciona con python 3
  • agregado un encabezado hex-col-header
  • parámetro de longitud opcional
  • renombrado a hd

ejemplos

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()


(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

Parece bastante fácil ;-)

Es probable que pueda escribir un script de Python (las versiones modernas de GDB tienen incorporado el intérprete de Python) para hacer lo mismo y deshacerse de la necesidad de "pagar".