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 12import commands 13import platform 14import os 15import re 16import sys 17 18try: 19 # Just try for LLDB in case PYTHONPATH is already correctly setup 20 import lldb 21except 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 49import commands 50import optparse 51import shlex 52import string 53import struct 54import time 55 56def 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 82def create_memfind_options(): 83 usage = "usage: %prog [options] STARTADDR [ENDADDR]" 84 description='''This command can find data in a specified address range. 85Options are used to specify the data that is to be looked for and the options 86can 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 100def 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 116def print_error(str, show_usage, result): 117 print >>result, str 118 if show_usage: 119 print >>result, create_memfind_options().format_help() 120 121def 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 176if __name__ == '__main__': 177 print 'error: this script is designed to be used within the embedded script interpreter in LLDB' 178elif 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