Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | #---------------------------------------------------------------------- |
| 4 | # Be sure to add the python path that points to the LLDB shared library. |
| 5 | # |
| 6 | # # To use this in the embedded python interpreter using "lldb" just |
| 7 | # import it with the full path using the "command script import" |
| 8 | # command |
| 9 | # (lldb) command script import /path/to/heap.py |
| 10 | # |
| 11 | # For the shells csh, tcsh: |
| 12 | # ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./heap.py ) |
| 13 | # |
| 14 | # For the shells sh, bash: |
| 15 | # PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./heap.py |
| 16 | #---------------------------------------------------------------------- |
| 17 | |
| 18 | import lldb |
| 19 | import commands |
| 20 | import optparse |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 21 | import os |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 22 | import shlex |
| 23 | |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 24 | def heap_search(options, arg_str): |
| 25 | expr = None |
| 26 | if options.type == 'pointer': |
| 27 | ptr = int(arg_str, 0) |
| 28 | expr = 'find_pointer_in_heap(0x%x)' % ptr |
| 29 | elif options.type == 'cstr': |
| 30 | expr = 'find_cstring_in_heap("%s")' % arg_str |
| 31 | else: |
| 32 | print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type |
| 33 | return |
| 34 | |
| 35 | expr_sbvalue = lldb.frame.EvaluateExpression (expr) |
| 36 | if expr_sbvalue.error.Success(): |
| 37 | if expr_sbvalue.unsigned: |
| 38 | match_value = lldb.value(expr_sbvalue) |
| 39 | i = 0 |
| 40 | while 1: |
| 41 | match_entry = match_value[i]; i += 1 |
| 42 | malloc_addr = match_entry.addr.sbvalue.unsigned |
| 43 | if malloc_addr == 0: |
| 44 | break |
| 45 | malloc_size = int(match_entry.size) |
| 46 | offset = int(match_entry.offset) |
| 47 | dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget) |
| 48 | # If the type is still 'void *' then we weren't able to figure |
| 49 | # out a dynamic type for the malloc_addr |
| 50 | type_name = dynamic_value.type.name |
| 51 | if type_name == 'void *': |
| 52 | if options.type == 'pointer' and malloc_size == 4096: |
| 53 | error = lldb.SBError() |
| 54 | data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error)) |
| 55 | if data == '\xa1\xa1\xa1\xa1AUTORELEASE!': |
| 56 | print 'found %s %s: block = 0x%x, size = %u, offset = %u, type = (autorelease object pool)' % (options.type, arg_str, malloc_addr, malloc_size, offset) |
| 57 | continue |
| 58 | |
| 59 | print 'found %s %s: block = 0x%x, size = %u, offset = %u, type = \'%s\'' % (options.type, arg_str, malloc_addr, malloc_size, offset, type_name), |
| 60 | derefed_dynamic_value = dynamic_value.deref |
| 61 | ivar_member = None |
| 62 | if derefed_dynamic_value: |
| 63 | derefed_dynamic_type = derefed_dynamic_value.type |
| 64 | member = derefed_dynamic_type.GetFieldAtIndex(0) |
| 65 | search_bases = False |
| 66 | if member: |
| 67 | if member.GetOffsetInBytes() <= offset: |
| 68 | for field_idx in range (derefed_dynamic_type.GetNumberOfFields()): |
| 69 | member = derefed_dynamic_type.GetFieldAtIndex(field_idx) |
| 70 | member_byte_offset = member.GetOffsetInBytes() |
| 71 | if member_byte_offset == offset: |
| 72 | ivar_member = member |
| 73 | break |
| 74 | else: |
| 75 | search_bases = True |
| 76 | else: |
| 77 | search_bases = True |
| 78 | |
| 79 | if not ivar_member and search_bases: |
| 80 | for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()): |
| 81 | member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx) |
| 82 | member_byte_offset = member.GetOffsetInBytes() |
| 83 | if member_byte_offset == offset: |
| 84 | ivar_member = member |
| 85 | break |
| 86 | if not ivar_member: |
| 87 | for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()): |
| 88 | member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx) |
| 89 | member_byte_offset = member.GetOffsetInBytes() |
| 90 | if member_byte_offset == offset: |
| 91 | ivar_member = member |
| 92 | break |
| 93 | if ivar_member: |
| 94 | print ", ivar = %s" % ivar_member.name, |
| 95 | print "\n", dynamic_value.deref |
| 96 | else: |
| 97 | print |
| 98 | if options.print_object_description: |
| 99 | desc = dynamic_value.GetObjectDescription() |
| 100 | if desc: |
| 101 | print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc) |
| 102 | else: |
| 103 | print '%s %s was not found in any malloc blocks' % (options.type, arg_str) |
| 104 | else: |
| 105 | print expr_sbvalue.error |
| 106 | |
| 107 | def heap_ptr_refs(debugger, command, result, dict): |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 108 | command_args = shlex.split(command) |
| 109 | usage = "usage: %prog [options] <PATH> [PATH ...]" |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 110 | description='''Searches the heap for pointer references on darwin user space programs. |
| 111 | |
| 112 | Any matches that were found will dump the malloc blocks that contain the pointers |
| 113 | and might be able to print what kind of objects the pointers are contained in using |
| 114 | dynamic type information from the program.''' |
| 115 | parser = optparse.OptionParser(description=description, prog='heap_ptr_refs',usage=usage) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 116 | parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 117 | parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 118 | try: |
| 119 | (options, args) = parser.parse_args(command_args) |
| 120 | except: |
| 121 | return |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 122 | |
| 123 | options.type = 'pointer' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 124 | |
| 125 | if args: |
| 126 | |
| 127 | for data in args: |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 128 | heap_search (options, data) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 129 | else: |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 130 | print 'error: no pointer arguments were given' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 131 | |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 132 | def heap_cstr_refs(debugger, command, result, dict): |
| 133 | command_args = shlex.split(command) |
| 134 | usage = "usage: %prog [options] <PATH> [PATH ...]" |
| 135 | description='''Searches the heap for C string references on darwin user space programs. |
| 136 | |
| 137 | Any matches that were found will dump the malloc blocks that contain the C strings |
| 138 | and might be able to print what kind of objects the pointers are contained in using |
| 139 | dynamic type information from the program.''' |
| 140 | parser = optparse.OptionParser(description=description, prog='heap_cstr_refs',usage=usage) |
| 141 | parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) |
| 142 | parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False) |
| 143 | try: |
| 144 | (options, args) = parser.parse_args(command_args) |
| 145 | except: |
| 146 | return |
| 147 | |
| 148 | options.type = 'cstr' |
| 149 | |
| 150 | if args: |
| 151 | |
| 152 | for data in args: |
| 153 | heap_search (options, data) |
| 154 | else: |
| 155 | print 'error: no c string arguments were given to search for' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 156 | |
| 157 | def __lldb_init_module (debugger, dict): |
| 158 | # This initializer is being run from LLDB in the embedded command interpreter |
| 159 | # Add any commands contained in this module to LLDB |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame^] | 160 | libheap_dylib_path = os.path.dirname(__file__) + '/libheap.dylib' |
| 161 | debugger.HandleCommand('process load "%s"' % libheap_dylib_path) |
| 162 | debugger.HandleCommand('command script add -f heap.heap_ptr_refs heap_ptr_refs') |
| 163 | debugger.HandleCommand('command script add -f heap.heap_cstr_refs heap_cstr_refs') |
| 164 | print '"heap_ptr_refs" and "heap_cstr_refs" commands have been installed, use the "--help" options on these commands for detailed help.' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 165 | |
| 166 | |
| 167 | |
| 168 | |