Skip to content

Instantly share code, notes, and snippets.

@Kazurin-775
Created October 11, 2023 11:25
Show Gist options
  • Select an option

  • Save Kazurin-775/b9a57e05e4e7617f40ba42d7278f7843 to your computer and use it in GitHub Desktop.

Select an option

Save Kazurin-775/b9a57e05e4e7617f40ba42d7278f7843 to your computer and use it in GitHub Desktop.
GDB-Python script to trace calls to `malloc()` and `free()`
# This script can print out the arguments and return values of `malloc()` and
# `free()`, thanks to the power of GDB-Python.
#
# Usage: load the target program in gdb, wait until libc is loaded (e.g. by
# executing `start`), then execute `source malloc-trace.py`, and enjoy!
#
# Note: this only works for Linux x86_64. Porting should not be difficult if
# you are familiar with the C calling convention on the target platform.
#
# Also, feel free to extend this script with the functionalities you want (e.g.
# printing out the callers of `malloc()`).
#
# Ref: https://stackoverflow.com/questions/4060565/how-to-script-gdb-with-python
class MallocBp(gdb.Breakpoint):
'A breakpoint on malloc() which records the size argument for later use.'
def stop(self):
top = gdb.newest_frame()
size = top.read_register('rdi')
# Note: this is not thread safe (multithreading is not fully supported)
self.state['size'] = size
return False
class MallocRetBp(gdb.Breakpoint):
'''
A breakpoint set on `ret` instructions in malloc().
Prints out the addresses and sizes of the allocated chunks when hit.
'''
def stop(self):
top = gdb.newest_frame()
ptr = top.read_register('rax')
size = self.state['size']
self.state['size'] = None
print(f'malloc({size}) = {int(ptr):#x}')
return False
class FreeBp(gdb.Breakpoint):
'A breakpoint on free() which simply prints its argument when hit.'
def stop(self):
top = gdb.newest_frame()
ptr = top.read_register('rdi')
print(f'free({int(ptr):#x})')
return False
# We need to find the offsets of 'ret's in 'malloc()' beforehand (there
# # should be around 3 of them)
malloc_disasm = gdb.execute('disassemble malloc', to_string=True)
malloc_ret_addrs = []
for line in malloc_disasm.split('\n'):
# 0x00007ffff7e1cd14 <+260>: ret
if line.endswith(':\tret'):
# print(line)
malloc_ret_addrs.append(line.split()[0])
# Make sure we have found at least one of them (or this script won't work at all)
assert malloc_ret_addrs
# Set up breakpoints
state = {'size': None}
bp = MallocBp('malloc')
bp.state = state
for addr in malloc_ret_addrs:
bp = MallocRetBp(f'*{addr}')
bp.state = state
FreeBp('free')
print('Breakpoints have been set up')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment