1515bc8c1Sserge-sans-paille#!/usr/bin/env python 204bd6840SGreg Clayton 304bd6840SGreg Clayton#---------------------------------------------------------------------- 404bd6840SGreg Clayton# Be sure to add the python path that points to the LLDB shared library. 504bd6840SGreg Clayton# 604bd6840SGreg Clayton# # To use this in the embedded python interpreter using "lldb" just 704bd6840SGreg Clayton# import it with the full path using the "command script import" 804bd6840SGreg Clayton# command 904bd6840SGreg Clayton# (lldb) command script import /path/to/cmdtemplate.py 1004bd6840SGreg Clayton#---------------------------------------------------------------------- 1104bd6840SGreg Clayton 12525cd59fSSerge Gueltonfrom __future__ import print_function 13525cd59fSSerge Guelton 1404bd6840SGreg Claytonimport platform 1504bd6840SGreg Claytonimport os 1604bd6840SGreg Claytonimport re 1704bd6840SGreg Claytonimport sys 181a12dd70SSerge Gueltonimport subprocess 191a12dd70SSerge Guelton 2004bd6840SGreg Claytontry: 2104bd6840SGreg Clayton # Just try for LLDB in case PYTHONPATH is already correctly setup 2204bd6840SGreg Clayton import lldb 2304bd6840SGreg Claytonexcept ImportError: 2404bd6840SGreg Clayton lldb_python_dirs = list() 2504bd6840SGreg Clayton # lldb is not in the PYTHONPATH, try some defaults for the current platform 2604bd6840SGreg Clayton platform_system = platform.system() 2704bd6840SGreg Clayton if platform_system == 'Darwin': 2804bd6840SGreg Clayton # On Darwin, try the currently selected Xcode directory 29185de8eeSDavide Italiano xcode_dir = subprocess.check_output("xcode-select --print-path", shell=True) 3004bd6840SGreg Clayton if xcode_dir: 31b9c1b51eSKate Stone lldb_python_dirs.append( 32b9c1b51eSKate Stone os.path.realpath( 33b9c1b51eSKate Stone xcode_dir + 34b9c1b51eSKate Stone '/../SharedFrameworks/LLDB.framework/Resources/Python')) 35b9c1b51eSKate Stone lldb_python_dirs.append( 36b9c1b51eSKate Stone xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 37b9c1b51eSKate Stone lldb_python_dirs.append( 38b9c1b51eSKate Stone '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 3904bd6840SGreg Clayton success = False 4004bd6840SGreg Clayton for lldb_python_dir in lldb_python_dirs: 4104bd6840SGreg Clayton if os.path.exists(lldb_python_dir): 4204bd6840SGreg Clayton if not (sys.path.__contains__(lldb_python_dir)): 4304bd6840SGreg Clayton sys.path.append(lldb_python_dir) 4404bd6840SGreg Clayton try: 4504bd6840SGreg Clayton import lldb 4604bd6840SGreg Clayton except ImportError: 4704bd6840SGreg Clayton pass 4804bd6840SGreg Clayton else: 49525cd59fSSerge Guelton print('imported lldb from: "%s"' % (lldb_python_dir)) 5004bd6840SGreg Clayton success = True 5104bd6840SGreg Clayton break 5204bd6840SGreg Clayton if not success: 53525cd59fSSerge Guelton print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly") 5404bd6840SGreg Clayton sys.exit(1) 5504bd6840SGreg Clayton 5604bd6840SGreg Claytonimport optparse 5704bd6840SGreg Claytonimport shlex 5804bd6840SGreg Claytonimport string 5904bd6840SGreg Claytonimport struct 6004bd6840SGreg Claytonimport time 6104bd6840SGreg Clayton 62b9c1b51eSKate Stone 6304bd6840SGreg Claytondef append_data_callback(option, opt_str, value, parser): 6404bd6840SGreg Clayton if opt_str == "--uint8": 6504bd6840SGreg Clayton int8 = int(value, 0) 6604bd6840SGreg Clayton parser.values.data += struct.pack('1B', int8) 6704bd6840SGreg Clayton if opt_str == "--uint16": 6804bd6840SGreg Clayton int16 = int(value, 0) 6904bd6840SGreg Clayton parser.values.data += struct.pack('1H', int16) 7004bd6840SGreg Clayton if opt_str == "--uint32": 7104bd6840SGreg Clayton int32 = int(value, 0) 7204bd6840SGreg Clayton parser.values.data += struct.pack('1I', int32) 7304bd6840SGreg Clayton if opt_str == "--uint64": 7404bd6840SGreg Clayton int64 = int(value, 0) 7504bd6840SGreg Clayton parser.values.data += struct.pack('1Q', int64) 7604bd6840SGreg Clayton if opt_str == "--int8": 7704bd6840SGreg Clayton int8 = int(value, 0) 7804bd6840SGreg Clayton parser.values.data += struct.pack('1b', int8) 7904bd6840SGreg Clayton if opt_str == "--int16": 8004bd6840SGreg Clayton int16 = int(value, 0) 8104bd6840SGreg Clayton parser.values.data += struct.pack('1h', int16) 8204bd6840SGreg Clayton if opt_str == "--int32": 8304bd6840SGreg Clayton int32 = int(value, 0) 8404bd6840SGreg Clayton parser.values.data += struct.pack('1i', int32) 8504bd6840SGreg Clayton if opt_str == "--int64": 8604bd6840SGreg Clayton int64 = int(value, 0) 8704bd6840SGreg Clayton parser.values.data += struct.pack('1q', int64) 8804bd6840SGreg Clayton 89b9c1b51eSKate Stone 9004bd6840SGreg Claytondef create_memfind_options(): 9104bd6840SGreg Clayton usage = "usage: %prog [options] STARTADDR [ENDADDR]" 9204bd6840SGreg Clayton description = '''This command can find data in a specified address range. 9304bd6840SGreg ClaytonOptions are used to specify the data that is to be looked for and the options 9404bd6840SGreg Claytoncan be specified multiple times to look for longer streams of data. 9504bd6840SGreg Clayton''' 96b9c1b51eSKate Stone parser = optparse.OptionParser( 97b9c1b51eSKate Stone description=description, 98b9c1b51eSKate Stone prog='memfind', 99b9c1b51eSKate Stone usage=usage) 100b9c1b51eSKate Stone parser.add_option( 101b9c1b51eSKate Stone '-s', 102b9c1b51eSKate Stone '--size', 103b9c1b51eSKate Stone type='int', 104b9c1b51eSKate Stone metavar='BYTESIZE', 105b9c1b51eSKate Stone dest='size', 106b9c1b51eSKate Stone help='Specify the byte size to search.', 107b9c1b51eSKate Stone default=0) 108b9c1b51eSKate Stone parser.add_option( 109b9c1b51eSKate Stone '--int8', 110b9c1b51eSKate Stone action="callback", 111b9c1b51eSKate Stone callback=append_data_callback, 112b9c1b51eSKate Stone type='string', 113b9c1b51eSKate Stone metavar='INT', 114b9c1b51eSKate Stone dest='data', 115b9c1b51eSKate Stone help='Specify a 8 bit signed integer value to search for in memory.', 116b9c1b51eSKate Stone default='') 117b9c1b51eSKate Stone parser.add_option( 118b9c1b51eSKate Stone '--int16', 119b9c1b51eSKate Stone action="callback", 120b9c1b51eSKate Stone callback=append_data_callback, 121b9c1b51eSKate Stone type='string', 122b9c1b51eSKate Stone metavar='INT', 123b9c1b51eSKate Stone dest='data', 124b9c1b51eSKate Stone help='Specify a 16 bit signed integer value to search for in memory.', 125b9c1b51eSKate Stone default='') 126b9c1b51eSKate Stone parser.add_option( 127b9c1b51eSKate Stone '--int32', 128b9c1b51eSKate Stone action="callback", 129b9c1b51eSKate Stone callback=append_data_callback, 130b9c1b51eSKate Stone type='string', 131b9c1b51eSKate Stone metavar='INT', 132b9c1b51eSKate Stone dest='data', 133b9c1b51eSKate Stone help='Specify a 32 bit signed integer value to search for in memory.', 134b9c1b51eSKate Stone default='') 135b9c1b51eSKate Stone parser.add_option( 136b9c1b51eSKate Stone '--int64', 137b9c1b51eSKate Stone action="callback", 138b9c1b51eSKate Stone callback=append_data_callback, 139b9c1b51eSKate Stone type='string', 140b9c1b51eSKate Stone metavar='INT', 141b9c1b51eSKate Stone dest='data', 142b9c1b51eSKate Stone help='Specify a 64 bit signed integer value to search for in memory.', 143b9c1b51eSKate Stone default='') 144b9c1b51eSKate Stone parser.add_option( 145b9c1b51eSKate Stone '--uint8', 146b9c1b51eSKate Stone action="callback", 147b9c1b51eSKate Stone callback=append_data_callback, 148b9c1b51eSKate Stone type='string', 149b9c1b51eSKate Stone metavar='INT', 150b9c1b51eSKate Stone dest='data', 151b9c1b51eSKate Stone help='Specify a 8 bit unsigned integer value to search for in memory.', 152b9c1b51eSKate Stone default='') 153b9c1b51eSKate Stone parser.add_option( 154b9c1b51eSKate Stone '--uint16', 155b9c1b51eSKate Stone action="callback", 156b9c1b51eSKate Stone callback=append_data_callback, 157b9c1b51eSKate Stone type='string', 158b9c1b51eSKate Stone metavar='INT', 159b9c1b51eSKate Stone dest='data', 160b9c1b51eSKate Stone help='Specify a 16 bit unsigned integer value to search for in memory.', 161b9c1b51eSKate Stone default='') 162b9c1b51eSKate Stone parser.add_option( 163b9c1b51eSKate Stone '--uint32', 164b9c1b51eSKate Stone action="callback", 165b9c1b51eSKate Stone callback=append_data_callback, 166b9c1b51eSKate Stone type='string', 167b9c1b51eSKate Stone metavar='INT', 168b9c1b51eSKate Stone dest='data', 169b9c1b51eSKate Stone help='Specify a 32 bit unsigned integer value to search for in memory.', 170b9c1b51eSKate Stone default='') 171b9c1b51eSKate Stone parser.add_option( 172b9c1b51eSKate Stone '--uint64', 173b9c1b51eSKate Stone action="callback", 174b9c1b51eSKate Stone callback=append_data_callback, 175b9c1b51eSKate Stone type='string', 176b9c1b51eSKate Stone metavar='INT', 177b9c1b51eSKate Stone dest='data', 178b9c1b51eSKate Stone help='Specify a 64 bit unsigned integer value to search for in memory.', 179b9c1b51eSKate Stone default='') 18004bd6840SGreg Clayton return parser 18104bd6840SGreg Clayton 182b9c1b51eSKate Stone 18304bd6840SGreg Claytondef memfind_command(debugger, command, result, dict): 18404bd6840SGreg Clayton # Use the Shell Lexer to properly parse up command options just like a 18504bd6840SGreg Clayton # shell would 18604bd6840SGreg Clayton command_args = shlex.split(command) 18704bd6840SGreg Clayton parser = create_memfind_options() 18804bd6840SGreg Clayton (options, args) = parser.parse_args(command_args) 18904bd6840SGreg Clayton # try: 19004bd6840SGreg Clayton # (options, args) = parser.parse_args(command_args) 19104bd6840SGreg Clayton # except: 19204bd6840SGreg Clayton # # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 19304bd6840SGreg Clayton # # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 19404bd6840SGreg Clayton # result.SetStatus (lldb.eReturnStatusFailed) 19504bd6840SGreg Clayton # print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string 19604bd6840SGreg Clayton # return 19704bd6840SGreg Clayton memfind(debugger.GetSelectedTarget(), options, args, result) 19804bd6840SGreg Clayton 199b9c1b51eSKate Stone 20004bd6840SGreg Claytondef print_error(str, show_usage, result): 201525cd59fSSerge Guelton print(str, file=result) 20204bd6840SGreg Clayton if show_usage: 203525cd59fSSerge Guelton print(create_memfind_options().format_help(), file=result) 20404bd6840SGreg Clayton 205b9c1b51eSKate Stone 20604bd6840SGreg Claytondef memfind(target, options, args, result): 20704bd6840SGreg Clayton num_args = len(args) 20804bd6840SGreg Clayton start_addr = 0 20904bd6840SGreg Clayton if num_args == 1: 21004bd6840SGreg Clayton if options.size > 0: 211b9c1b51eSKate Stone print_error( 212b9c1b51eSKate Stone "error: --size must be specified if there is no ENDADDR argument", 213b9c1b51eSKate Stone True, 214b9c1b51eSKate Stone result) 21504bd6840SGreg Clayton return 21604bd6840SGreg Clayton start_addr = int(args[0], 0) 21704bd6840SGreg Clayton elif num_args == 2: 21804bd6840SGreg Clayton if options.size != 0: 219b9c1b51eSKate Stone print_error( 220b9c1b51eSKate Stone "error: --size can't be specified with an ENDADDR argument", 221b9c1b51eSKate Stone True, 222b9c1b51eSKate Stone result) 22304bd6840SGreg Clayton return 22404bd6840SGreg Clayton start_addr = int(args[0], 0) 22504bd6840SGreg Clayton end_addr = int(args[1], 0) 22604bd6840SGreg Clayton if start_addr >= end_addr: 227b9c1b51eSKate Stone print_error( 228b9c1b51eSKate Stone "error: inavlid memory range [%#x - %#x)" % 229b9c1b51eSKate Stone (start_addr, end_addr), True, result) 23004bd6840SGreg Clayton return 23104bd6840SGreg Clayton options.size = end_addr - start_addr 23204bd6840SGreg Clayton else: 23304bd6840SGreg Clayton print_error("error: memfind takes 1 or 2 arguments", True, result) 23404bd6840SGreg Clayton return 23504bd6840SGreg Clayton 23604bd6840SGreg Clayton if not options.data: 237525cd59fSSerge Guelton print('error: no data specified to search for', file=result) 23804bd6840SGreg Clayton return 23904bd6840SGreg Clayton 24004bd6840SGreg Clayton if not target: 241525cd59fSSerge Guelton print('error: invalid target', file=result) 24204bd6840SGreg Clayton return 24304bd6840SGreg Clayton process = target.process 24404bd6840SGreg Clayton if not process: 245525cd59fSSerge Guelton print('error: invalid process', file=result) 24604bd6840SGreg Clayton return 24704bd6840SGreg Clayton 24804bd6840SGreg Clayton error = lldb.SBError() 24904bd6840SGreg Clayton bytes = process.ReadMemory(start_addr, options.size, error) 25004bd6840SGreg Clayton if error.Success(): 25104bd6840SGreg Clayton num_matches = 0 252525cd59fSSerge Guelton print("Searching memory range [%#x - %#x) for" % ( 253525cd59fSSerge Guelton start_addr, end_addr), end=' ', file=result) 25404bd6840SGreg Clayton for byte in options.data: 255525cd59fSSerge Guelton print('%2.2x' % ord(byte), end=' ', file=result) 256525cd59fSSerge Guelton print(file=result) 25704bd6840SGreg Clayton 25804bd6840SGreg Clayton match_index = string.find(bytes, options.data) 25904bd6840SGreg Clayton while match_index != -1: 26004bd6840SGreg Clayton num_matches = num_matches + 1 261525cd59fSSerge Guelton print('%#x: %#x + %u' % (start_addr + 262525cd59fSSerge Guelton match_index, start_addr, match_index), file=result) 26304bd6840SGreg Clayton match_index = string.find(bytes, options.data, match_index + 1) 26404bd6840SGreg Clayton 26504bd6840SGreg Clayton if num_matches == 0: 266525cd59fSSerge Guelton print("error: no matches found", file=result) 26704bd6840SGreg Clayton else: 268525cd59fSSerge Guelton print('error: %s' % (error.GetCString()), file=result) 26904bd6840SGreg Clayton 27004bd6840SGreg Clayton 27104bd6840SGreg Claytonif __name__ == '__main__': 272525cd59fSSerge Guelton print('error: this script is designed to be used within the embedded script interpreter in LLDB') 273*1441ffe6SDave Lee 274*1441ffe6SDave Leedef __lldb_init_module(debugger, internal_dict): 27504bd6840SGreg Clayton memfind_command.__doc__ = create_memfind_options().format_help() 276*1441ffe6SDave Lee debugger.HandleCommand( 277b9c1b51eSKate Stone 'command script add -f memory.memfind_command memfind') 278525cd59fSSerge Guelton print('"memfind" command installed, use the "--help" option for detailed help') 279