Home | History | Annotate | Download | only in python
      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