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/cmdtemplate.py 10 #---------------------------------------------------------------------- 11 12 import commands 13 import platform 14 import os 15 import re 16 import sys 17 18 try: 19 # Just try for LLDB in case PYTHONPATH is already correctly setup 20 import lldb 21 except ImportError: 22 lldb_python_dirs = list() 23 # lldb is not in the PYTHONPATH, try some defaults for the current platform 24 platform_system = platform.system() 25 if platform_system == 'Darwin': 26 # On Darwin, try the currently selected Xcode directory 27 xcode_dir = commands.getoutput("xcode-select --print-path") 28 if xcode_dir: 29 lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) 30 lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 31 lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 32 success = False 33 for lldb_python_dir in lldb_python_dirs: 34 if os.path.exists(lldb_python_dir): 35 if not (sys.path.__contains__(lldb_python_dir)): 36 sys.path.append(lldb_python_dir) 37 try: 38 import lldb 39 except ImportError: 40 pass 41 else: 42 print 'imported lldb from: "%s"' % (lldb_python_dir) 43 success = True 44 break 45 if not success: 46 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" 47 sys.exit(1) 48 49 import commands 50 import optparse 51 import shlex 52 import string 53 import struct 54 import time 55 56 def append_data_callback(option, opt_str, value, parser): 57 if opt_str == "--uint8": 58 int8 = int(value, 0) 59 parser.values.data += struct.pack('1B',int8) 60 if opt_str == "--uint16": 61 int16 = int(value, 0) 62 parser.values.data += struct.pack('1H',int16) 63 if opt_str == "--uint32": 64 int32 = int(value, 0) 65 parser.values.data += struct.pack('1I',int32) 66 if opt_str == "--uint64": 67 int64 = int(value, 0) 68 parser.values.data += struct.pack('1Q',int64) 69 if opt_str == "--int8": 70 int8 = int(value, 0) 71 parser.values.data += struct.pack('1b',int8) 72 if opt_str == "--int16": 73 int16 = int(value, 0) 74 parser.values.data += struct.pack('1h',int16) 75 if opt_str == "--int32": 76 int32 = int(value, 0) 77 parser.values.data += struct.pack('1i',int32) 78 if opt_str == "--int64": 79 int64 = int(value, 0) 80 parser.values.data += struct.pack('1q',int64) 81 82 def create_memfind_options(): 83 usage = "usage: %prog [options] STARTADDR [ENDADDR]" 84 description='''This command can find data in a specified address range. 85 Options are used to specify the data that is to be looked for and the options 86 can be specified multiple times to look for longer streams of data. 87 ''' 88 parser = optparse.OptionParser(description=description, prog='memfind',usage=usage) 89 parser.add_option('-s', '--size', type='int', metavar='BYTESIZE', dest='size', help='Specify the byte size to search.', default=0) 90 parser.add_option('--int8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit signed integer value to search for in memory.', default='') 91 parser.add_option('--int16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit signed integer value to search for in memory.', default='') 92 parser.add_option('--int32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit signed integer value to search for in memory.', default='') 93 parser.add_option('--int64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit signed integer value to search for in memory.', default='') 94 parser.add_option('--uint8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit unsigned integer value to search for in memory.', default='') 95 parser.add_option('--uint16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit unsigned integer value to search for in memory.', default='') 96 parser.add_option('--uint32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit unsigned integer value to search for in memory.', default='') 97 parser.add_option('--uint64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit unsigned integer value to search for in memory.', default='') 98 return parser 99 100 def memfind_command (debugger, command, result, dict): 101 # Use the Shell Lexer to properly parse up command options just like a 102 # shell would 103 command_args = shlex.split(command) 104 parser = create_memfind_options() 105 (options, args) = parser.parse_args(command_args) 106 # try: 107 # (options, args) = parser.parse_args(command_args) 108 # except: 109 # # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 110 # # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 111 # result.SetStatus (lldb.eReturnStatusFailed) 112 # print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string 113 # return 114 memfind (debugger.GetSelectedTarget(), options, args, result) 115 116 def print_error(str, show_usage, result): 117 print >>result, str 118 if show_usage: 119 print >>result, create_memfind_options().format_help() 120 121 def memfind (target, options, args, result): 122 num_args = len(args) 123 start_addr = 0 124 if num_args == 1: 125 if options.size > 0: 126 print_error ("error: --size must be specified if there is no ENDADDR argument", True, result) 127 return 128 start_addr = int(args[0], 0) 129 elif num_args == 2: 130 if options.size != 0: 131 print_error ("error: --size can't be specified with an ENDADDR argument", True, result) 132 return 133 start_addr = int(args[0], 0) 134 end_addr = int(args[1], 0) 135 if start_addr >= end_addr: 136 print_error ("error: inavlid memory range [%#x - %#x)" % (start_addr, end_addr), True, result) 137 return 138 options.size = end_addr - start_addr 139 else: 140 print_error ("error: memfind takes 1 or 2 arguments", True, result) 141 return 142 143 if not options.data: 144 print >>result, 'error: no data specified to search for' 145 return 146 147 if not target: 148 print >>result, 'error: invalid target' 149 return 150 process = target.process 151 if not process: 152 print >>result, 'error: invalid process' 153 return 154 155 error = lldb.SBError() 156 bytes = process.ReadMemory (start_addr, options.size, error) 157 if error.Success(): 158 num_matches = 0 159 print >>result, "Searching memory range [%#x - %#x) for" % (start_addr, end_addr), 160 for byte in options.data: 161 print >>result, '%2.2x' % ord(byte), 162 print >>result 163 164 match_index = string.find(bytes, options.data) 165 while match_index != -1: 166 num_matches = num_matches + 1 167 print >>result, '%#x: %#x + %u' % (start_addr + match_index, start_addr, match_index) 168 match_index = string.find(bytes, options.data, match_index + 1) 169 170 if num_matches == 0: 171 print >>result, "error: no matches found" 172 else: 173 print >>result, 'error: %s' % (error.GetCString()) 174 175 176 if __name__ == '__main__': 177 print 'error: this script is designed to be used within the embedded script interpreter in LLDB' 178 elif getattr(lldb, 'debugger', None): 179 memfind_command.__doc__ = create_memfind_options().format_help() 180 lldb.debugger.HandleCommand('command script add -f memory.memfind_command memfind') 181 print '"memfind" command installed, use the "--help" option for detailed help' 182