(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”.
Update:
Here is a possible Python implementation (save this into xxd.py
):
class XXD(gdb.Command):
def __init__(self):
super(XXD, self).__init__("xxd", gdb.COMMAND_USER)
def _PrintLine(self, offset, bytes, size):
print('{:08x}: '.format(offset), end='')
todo = size
while todo >= 4:
print(''.join('{:02x}'.format(b) for b in bytes[0:4]), end='')
todo -= 4
bytes = bytes[3:]
if todo:
print(' ', end='')
# Print any remaining bytes
print(''.join('{:02x}'.format(b) for b in bytes[0:todo]), end='')
print()
return size
def invoke(self, arg, from_tty):
args = arg.split()
if len(args) != 2:
print("xxd: <addr> <count>")
return
size = int(args[1])
addr = gdb.parse_and_eval(args[0])
inferior = gdb.inferiors()[0]
bytes = inferior.read_memory(addr, size).tobytes()
offset = int(addr)
while size > 0:
n = self._PrintLine(offset, bytes, min(len(bytes), 16))
size -= n
offset += n
bytes = bytes[n:]
XXD()
Use it like so:
// Sample program x.c
char foo[] = "abcdefghijklmopqrstuvwxyz";
int main() { return 0; }
gcc -g x.c
gdb -q ./a.out
(gdb) source xxd.py
Temporary breakpoint 1, main () at x.c:3
3 int main() { return 0; }
(gdb) xxd &foo[0] 18
00404030: 61626364 64656667 6768696a 6a6b6c6d
00404040: 7273