Skip to content

Instantly share code, notes, and snippets.

@itewqq
Last active September 19, 2023 20:16
Show Gist options
  • Save itewqq/805f4ae1680827e963c59d6fc17a15c8 to your computer and use it in GitHub Desktop.
Save itewqq/805f4ae1680827e963c59d6fc17a15c8 to your computer and use it in GitHub Desktop.
GDB python script to print the memory layout of structures.

Features

  1. Make sure you build the binary with debug symbols. For example: RUSTFLAGS=-g cargo build --release
  2. Use rust-gdb to start the binary and load the script: rust-gdb rust_binary -x memlayout-rust.py
  3. Break anywhere you like, and use the command mem-layout VARIABLE_NAME to print the layout of that variable:

image

  1. Custom structures are also supported:
struct S1 {
    v1: Vec<i32>,
    b2: u8,
    c3: Box<Vec<usize>>,
}

image

Known issues

  • Some pointers may not be translated correctly. If you see a member's type is 'None' and has size of 0x8, that's a pointer.
import gdb
# https://stackoverflow.com/questions/9788679/how-to-get-the-relative-address-of-a-field-in-a-structure-dump-c
class Memlayout(gdb.Command):
def __init__(self):
super (Memlayout, self).__init__ ('mem-layout', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
if len(argv) != 1:
raise gdb.GdbError('mem-layout takes exactly 1 argument.')
stype = gdb.parse_and_eval(argv[0]).type
dfs_offset(0, 0, stype, argv[0])
# print (argv[0], stype, '{')
# for field in stype.fields():
# tpsz = field.bitsize
# if tpsz == 0:
# tpsz = field.type.sizeof
# print (' [0x%x] %s, size=%x, is_arti=%s, is_basic=%s' % (field.bitpos//8, field.name, tpsz, str(field.artificial), str(field.is_base_class)) )
# print ('}')
# helper function
def dfs_offset(cur_level, cur_off, cur_type, filed_name = ""):
try:
fields = cur_type.fields()
except TypeError:
fields = []
addr = "[0x%03x]"%(cur_off)
addr = addr.ljust(12, ' ')
print("%s%s%s %s, size=0x%x " % (
addr, ' '*4*cur_level, cur_type.name, filed_name, cur_type.sizeof
), end='')
if len(fields) != 0:
print('{')
else:
print()
inner_off = 0
fields = sorted(fields, key=lambda x: x.bitpos)
for field in fields:
dfs_offset(cur_level+1, cur_off+inner_off, field.type, filed_name=field.name)
tpsz = field.bitsize
if tpsz == 0:
tpsz = field.type.sizeof
inner_off += tpsz
if len(fields) != 0:
print("%s%s}" % (' '*12, ' '*4*cur_level))
Memlayout()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment