├── README.md ├── gdb_newlib.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | This repo will hopefully eventually hold a collection of useful gdb-python scripts for debug. 2 | 3 | If you don't know much about GDBs python scripting API check out [this writeup](https://github.com/chrisc11/debug-tips/blob/master/gdb/python-linked-list.md)! 4 | 5 | PS: I tried to search the interwebs first for a pre-existing implementation for commands added but 6 | could not find anything. If you know of a repo that provides similar functionality for any of the 7 | command you see, do let me know! 8 | 9 | 10 | # Available Commands 11 | 12 | ## Newlib 13 | 14 | `newlib heapdump` - Pretty prints the blocks in a newlib libc heap 15 | -------------------------------------------------------------------------------- /gdb_newlib.py: -------------------------------------------------------------------------------- 1 | try: 2 | import gdb 3 | except ImportError: 4 | error_str = """ 5 | This script can only be run within gdb! 6 | You need to 'source gdb_newlib.py' from (gdb) or in your init file 7 | """ 8 | raise Exception(error_str) 9 | 10 | from prettytable import PrettyTable 11 | 12 | 13 | class NewlibCommand(gdb.Command): 14 | """Utility commands for debugging newlib""" 15 | 16 | def __init__(self): 17 | super(NewlibCommand, self).__init__( 18 | 'newlib', gdb.COMMAND_USER, gdb.COMPLETE_NONE, prefix=True) 19 | 20 | def invoke(self, arg, from_tty): 21 | gdb.execute('help newlib') 22 | NewlibCommand() 23 | 24 | 25 | class NewlibDefaultHeapDump(gdb.Command): 26 | """Prints the current blocks in a newlib heap 27 | 28 | Newlib uses a heap implementaion written by Doug Lea. You can find the implementation as part 29 | of the newlib sources here: 30 | https://github.com/bminor/newlib/blob/master/newlib/libc/stdlib/mallocr.c#L11 31 | 32 | This python-gdb utility command attempts to print all the malloc_chunk's that currently make up 33 | the heap in an easy to read format. This can be useful to get a better understanding of 34 | fragmentation and free space 35 | 36 | Note: The function currently assumes you are linking newlib with debug so it can find the 37 | following symbol information: 38 | * '__malloc_sbrk_base' static 39 | * '__malloc_av_' static 40 | * 'struct malloc_chunk' type 41 | 42 | This could probably be improved in the future by also allowing a user to specify this info via 43 | command args and loading the 'struct malloc_chunk' symbol definition into gdb as part of a 44 | dummy elf 45 | """ 46 | def __init__(self): 47 | super(NewlibDefaultHeapDump, self).__init__('newlib heapdump', gdb.COMMAND_USER) 48 | 49 | def invoke(self, unicode_args, from_tty): 50 | results = PrettyTable() 51 | results.field_names = list(['Block Addr', 'User Data Start', 'Tot Size (bytes)']) 52 | 53 | heap_start = gdb.parse_and_eval('__malloc_sbrk_base') 54 | 55 | malloc_chunk_ptr_type = gdb.lookup_type("struct malloc_chunk").pointer() 56 | next_malloc_chunk_ptr = heap_start 57 | malloc_chunk = next_malloc_chunk_ptr.cast(malloc_chunk_ptr_type) 58 | running_total = 0 59 | bytes_free = 0 60 | blocks_allocated = 0 61 | 62 | top_bin = gdb.parse_and_eval('__malloc_av_[2]') 63 | 64 | while True: 65 | flags = malloc_chunk['size'] & 0x3 66 | block_size = malloc_chunk['size'] & ~0x3 67 | running_total += block_size 68 | next_malloc_chunk_ptr += block_size 69 | next_malloc_chunk = next_malloc_chunk_ptr.cast(malloc_chunk_ptr_type) 70 | blocks_allocated += 1 71 | 72 | # Check the PREV_INUSE flag to figure out if the current block is free 73 | in_use = next_malloc_chunk['size'] & 0x1 74 | user_data = '0x%x' % malloc_chunk['fd'].address if in_use else 'FREE' 75 | bytes_free += block_size if not in_use else 0 76 | 77 | results.add_row([str(malloc_chunk), user_data, str(block_size)]) 78 | 79 | if top_bin == malloc_chunk: # We are done 80 | break 81 | malloc_chunk = next_malloc_chunk 82 | 83 | print(results) 84 | print("%d blocks: %d/%d bytes free" % (blocks_allocated, bytes_free, running_total)) 85 | 86 | NewlibDefaultHeapDump() 87 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | prettytable >= 0.7.2 2 | --------------------------------------------------------------------------------