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 |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 26 | arg_str_description = arg_str |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 27 | if options.type == 'pointer': |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 28 | expr = 'find_pointer_in_heap(%s)' % arg_str |
| 29 | arg_str_description = 'malloc block containing pointer %s' % arg_str |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 30 | elif options.type == 'cstr': |
| 31 | expr = 'find_cstring_in_heap("%s")' % arg_str |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 32 | arg_str_description = 'malloc block containing "%s"' % arg_str |
| 33 | elif options.type == 'addr': |
| 34 | expr = 'find_block_for_address(%s)' % arg_str |
| 35 | arg_str_description = 'malloc block for %s' % arg_str |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 36 | else: |
| 37 | print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type |
| 38 | return |
| 39 | |
| 40 | expr_sbvalue = lldb.frame.EvaluateExpression (expr) |
| 41 | if expr_sbvalue.error.Success(): |
| 42 | if expr_sbvalue.unsigned: |
| 43 | match_value = lldb.value(expr_sbvalue) |
| 44 | i = 0 |
| 45 | while 1: |
| 46 | match_entry = match_value[i]; i += 1 |
| 47 | malloc_addr = match_entry.addr.sbvalue.unsigned |
| 48 | if malloc_addr == 0: |
| 49 | break |
| 50 | malloc_size = int(match_entry.size) |
| 51 | offset = int(match_entry.offset) |
| 52 | dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget) |
| 53 | # If the type is still 'void *' then we weren't able to figure |
| 54 | # out a dynamic type for the malloc_addr |
| 55 | type_name = dynamic_value.type.name |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 56 | description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr) |
| 57 | if offset != 0: |
| 58 | description += ' + %u' % (offset) |
| 59 | description += ', size = %u' % (malloc_size) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 60 | if type_name == 'void *': |
| 61 | if options.type == 'pointer' and malloc_size == 4096: |
| 62 | error = lldb.SBError() |
| 63 | data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error)) |
| 64 | if data == '\xa1\xa1\xa1\xa1AUTORELEASE!': |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 65 | description += ', type = (AUTORELEASE!)' |
| 66 | print description |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 67 | continue |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 68 | else: |
| 69 | description += ', type = %s' % (type_name) |
| 70 | derefed_dynamic_value = dynamic_value.deref |
| 71 | ivar_member = None |
| 72 | if derefed_dynamic_value: |
| 73 | derefed_dynamic_type = derefed_dynamic_value.type |
| 74 | member = derefed_dynamic_type.GetFieldAtIndex(0) |
| 75 | search_bases = False |
| 76 | if member: |
| 77 | if member.GetOffsetInBytes() <= offset: |
| 78 | for field_idx in range (derefed_dynamic_type.GetNumberOfFields()): |
| 79 | member = derefed_dynamic_type.GetFieldAtIndex(field_idx) |
| 80 | member_byte_offset = member.GetOffsetInBytes() |
| 81 | if member_byte_offset == offset: |
| 82 | ivar_member = member |
| 83 | break |
| 84 | else: |
| 85 | search_bases = True |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 86 | else: |
| 87 | search_bases = True |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 88 | |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 89 | if not ivar_member and search_bases: |
| 90 | for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()): |
| 91 | member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 92 | member_byte_offset = member.GetOffsetInBytes() |
| 93 | if member_byte_offset == offset: |
| 94 | ivar_member = member |
| 95 | break |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 96 | if not ivar_member: |
| 97 | for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()): |
| 98 | member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx) |
| 99 | member_byte_offset = member.GetOffsetInBytes() |
| 100 | if member_byte_offset == offset: |
| 101 | ivar_member = member |
| 102 | break |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 103 | if ivar_member: |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 104 | description +=', ivar = %s' % (ivar_member.name) |
| 105 | |
| 106 | print description |
| 107 | if derefed_dynamic_value: |
| 108 | print derefed_dynamic_value |
| 109 | if options.print_object_description: |
| 110 | desc = dynamic_value.GetObjectDescription() |
| 111 | if desc: |
| 112 | print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 113 | else: |
| 114 | print '%s %s was not found in any malloc blocks' % (options.type, arg_str) |
| 115 | else: |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 116 | print expr_sbvalue.error |
| 117 | print |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 118 | |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 119 | def ptr_refs(debugger, command, result, dict): |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 120 | command_args = shlex.split(command) |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 121 | usage = "usage: %prog [options] <PTR> [PTR ...]" |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 122 | description='''Searches the heap for pointer references on darwin user space programs. |
| 123 | |
| 124 | Any matches that were found will dump the malloc blocks that contain the pointers |
| 125 | and might be able to print what kind of objects the pointers are contained in using |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 126 | dynamic type information in the program.''' |
| 127 | parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 128 | 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] | 129 | parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False) |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 130 | parser.add_option('-m', '--memory', action='store_true', dest='show_memory', help='dump the memory for each matching block', default=False) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 131 | try: |
| 132 | (options, args) = parser.parse_args(command_args) |
| 133 | except: |
| 134 | return |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 135 | |
| 136 | options.type = 'pointer' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 137 | |
| 138 | if args: |
| 139 | |
| 140 | for data in args: |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 141 | heap_search (options, data) |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 142 | else: |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 143 | print 'error: no pointer arguments were given' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 144 | |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 145 | def cstr_refs(debugger, command, result, dict): |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 146 | command_args = shlex.split(command) |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 147 | usage = "usage: %prog [options] <CSTR> [CSTR ...]" |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 148 | description='''Searches the heap for C string references on darwin user space programs. |
| 149 | |
| 150 | Any matches that were found will dump the malloc blocks that contain the C strings |
| 151 | and might be able to print what kind of objects the pointers are contained in using |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 152 | dynamic type information in the program.''' |
| 153 | parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 154 | parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) |
| 155 | parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False) |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 156 | parser.add_option('-m', '--memory', action='store_true', dest='show_memory', help='dump the memory for each matching block', default=False) |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 157 | try: |
| 158 | (options, args) = parser.parse_args(command_args) |
| 159 | except: |
| 160 | return |
| 161 | |
| 162 | options.type = 'cstr' |
| 163 | |
| 164 | if args: |
| 165 | |
| 166 | for data in args: |
| 167 | heap_search (options, data) |
| 168 | else: |
| 169 | print 'error: no c string arguments were given to search for' |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 170 | |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 171 | def malloc_info(debugger, command, result, dict): |
| 172 | command_args = shlex.split(command) |
| 173 | usage = "usage: %prog [options] <ADDR> [ADDR ...]" |
| 174 | description='''Searches the heap a malloc block that contains the addresses specified as arguments. |
| 175 | |
| 176 | Any matches that were found will dump the malloc blocks that match or contain |
| 177 | the specified address. The matching blocks might be able to show what kind |
| 178 | of objects they are using dynamic type information in the program.''' |
| 179 | parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage) |
| 180 | parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) |
| 181 | parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False) |
| 182 | parser.add_option('-m', '--memory', action='store_true', dest='show_memory', help='dump the memory for each matching block', default=False) |
| 183 | try: |
| 184 | (options, args) = parser.parse_args(command_args) |
| 185 | except: |
| 186 | return |
| 187 | |
| 188 | options.type = 'addr' |
| 189 | |
| 190 | if args: |
| 191 | |
| 192 | for data in args: |
| 193 | heap_search (options, data) |
| 194 | else: |
| 195 | print 'error: no c string arguments were given to search for' |
| 196 | |
Greg Clayton | e93e24f | 2012-04-11 16:27:06 +0000 | [diff] [blame] | 197 | def __lldb_init_module (debugger, dict): |
| 198 | # This initializer is being run from LLDB in the embedded command interpreter |
| 199 | # Add any commands contained in this module to LLDB |
Greg Clayton | 9666644 | 2012-04-11 18:30:53 +0000 | [diff] [blame] | 200 | libheap_dylib_path = os.path.dirname(__file__) + '/libheap.dylib' |
| 201 | debugger.HandleCommand('process load "%s"' % libheap_dylib_path) |
Greg Clayton | bff7841 | 2012-04-12 18:57:36 +0000 | [diff] [blame^] | 202 | debugger.HandleCommand('command script add -f heap.ptr_refs ptr_refs') |
| 203 | debugger.HandleCommand('command script add -f heap.cstr_refs cstr_refs') |
| 204 | debugger.HandleCommand('command script add -f heap.malloc_info malloc_info') |
| 205 | print '"ptr_refs", "cstr_refs", and "malloc_info" 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] | 206 | |
| 207 | |
| 208 | |
| 209 | |