xref: /llvm-project/lldb/examples/python/memory.py (revision b9c1b51e45b845debb76d8658edabca70ca56079)
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(
30                os.path.realpath(
31                    xcode_dir +
32                    '/../SharedFrameworks/LLDB.framework/Resources/Python'))
33            lldb_python_dirs.append(
34                xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
35        lldb_python_dirs.append(
36            '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
37    success = False
38    for lldb_python_dir in lldb_python_dirs:
39        if os.path.exists(lldb_python_dir):
40            if not (sys.path.__contains__(lldb_python_dir)):
41                sys.path.append(lldb_python_dir)
42                try:
43                    import lldb
44                except ImportError:
45                    pass
46                else:
47                    print 'imported lldb from: "%s"' % (lldb_python_dir)
48                    success = True
49                    break
50    if not success:
51        print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
52        sys.exit(1)
53
54import commands
55import optparse
56import shlex
57import string
58import struct
59import time
60
61
62def append_data_callback(option, opt_str, value, parser):
63    if opt_str == "--uint8":
64        int8 = int(value, 0)
65        parser.values.data += struct.pack('1B', int8)
66    if opt_str == "--uint16":
67        int16 = int(value, 0)
68        parser.values.data += struct.pack('1H', int16)
69    if opt_str == "--uint32":
70        int32 = int(value, 0)
71        parser.values.data += struct.pack('1I', int32)
72    if opt_str == "--uint64":
73        int64 = int(value, 0)
74        parser.values.data += struct.pack('1Q', int64)
75    if opt_str == "--int8":
76        int8 = int(value, 0)
77        parser.values.data += struct.pack('1b', int8)
78    if opt_str == "--int16":
79        int16 = int(value, 0)
80        parser.values.data += struct.pack('1h', int16)
81    if opt_str == "--int32":
82        int32 = int(value, 0)
83        parser.values.data += struct.pack('1i', int32)
84    if opt_str == "--int64":
85        int64 = int(value, 0)
86        parser.values.data += struct.pack('1q', int64)
87
88
89def create_memfind_options():
90    usage = "usage: %prog [options] STARTADDR [ENDADDR]"
91    description = '''This command can find data in a specified address range.
92Options are used to specify the data that is to be looked for and the options
93can be specified multiple times to look for longer streams of data.
94'''
95    parser = optparse.OptionParser(
96        description=description,
97        prog='memfind',
98        usage=usage)
99    parser.add_option(
100        '-s',
101        '--size',
102        type='int',
103        metavar='BYTESIZE',
104        dest='size',
105        help='Specify the byte size to search.',
106        default=0)
107    parser.add_option(
108        '--int8',
109        action="callback",
110        callback=append_data_callback,
111        type='string',
112        metavar='INT',
113        dest='data',
114        help='Specify a 8 bit signed integer value to search for in memory.',
115        default='')
116    parser.add_option(
117        '--int16',
118        action="callback",
119        callback=append_data_callback,
120        type='string',
121        metavar='INT',
122        dest='data',
123        help='Specify a 16 bit signed integer value to search for in memory.',
124        default='')
125    parser.add_option(
126        '--int32',
127        action="callback",
128        callback=append_data_callback,
129        type='string',
130        metavar='INT',
131        dest='data',
132        help='Specify a 32 bit signed integer value to search for in memory.',
133        default='')
134    parser.add_option(
135        '--int64',
136        action="callback",
137        callback=append_data_callback,
138        type='string',
139        metavar='INT',
140        dest='data',
141        help='Specify a 64 bit signed integer value to search for in memory.',
142        default='')
143    parser.add_option(
144        '--uint8',
145        action="callback",
146        callback=append_data_callback,
147        type='string',
148        metavar='INT',
149        dest='data',
150        help='Specify a 8 bit unsigned integer value to search for in memory.',
151        default='')
152    parser.add_option(
153        '--uint16',
154        action="callback",
155        callback=append_data_callback,
156        type='string',
157        metavar='INT',
158        dest='data',
159        help='Specify a 16 bit unsigned integer value to search for in memory.',
160        default='')
161    parser.add_option(
162        '--uint32',
163        action="callback",
164        callback=append_data_callback,
165        type='string',
166        metavar='INT',
167        dest='data',
168        help='Specify a 32 bit unsigned integer value to search for in memory.',
169        default='')
170    parser.add_option(
171        '--uint64',
172        action="callback",
173        callback=append_data_callback,
174        type='string',
175        metavar='INT',
176        dest='data',
177        help='Specify a 64 bit unsigned integer value to search for in memory.',
178        default='')
179    return parser
180
181
182def memfind_command(debugger, command, result, dict):
183    # Use the Shell Lexer to properly parse up command options just like a
184    # shell would
185    command_args = shlex.split(command)
186    parser = create_memfind_options()
187    (options, args) = parser.parse_args(command_args)
188    # try:
189    #     (options, args) = parser.parse_args(command_args)
190    # except:
191    #     # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
192    #     # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
193    #     result.SetStatus (lldb.eReturnStatusFailed)
194    #     print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string
195    #     return
196    memfind(debugger.GetSelectedTarget(), options, args, result)
197
198
199def print_error(str, show_usage, result):
200    print >>result, str
201    if show_usage:
202        print >>result, create_memfind_options().format_help()
203
204
205def memfind(target, options, args, result):
206    num_args = len(args)
207    start_addr = 0
208    if num_args == 1:
209        if options.size > 0:
210            print_error(
211                "error: --size must be specified if there is no ENDADDR argument",
212                True,
213                result)
214            return
215        start_addr = int(args[0], 0)
216    elif num_args == 2:
217        if options.size != 0:
218            print_error(
219                "error: --size can't be specified with an ENDADDR argument",
220                True,
221                result)
222            return
223        start_addr = int(args[0], 0)
224        end_addr = int(args[1], 0)
225        if start_addr >= end_addr:
226            print_error(
227                "error: inavlid memory range [%#x - %#x)" %
228                (start_addr, end_addr), True, result)
229            return
230        options.size = end_addr - start_addr
231    else:
232        print_error("error: memfind takes 1 or 2 arguments", True, result)
233        return
234
235    if not options.data:
236        print >>result, 'error: no data specified to search for'
237        return
238
239    if not target:
240        print >>result, 'error: invalid target'
241        return
242    process = target.process
243    if not process:
244        print >>result, 'error: invalid process'
245        return
246
247    error = lldb.SBError()
248    bytes = process.ReadMemory(start_addr, options.size, error)
249    if error.Success():
250        num_matches = 0
251        print >>result, "Searching memory range [%#x - %#x) for" % (
252            start_addr, end_addr),
253        for byte in options.data:
254            print >>result, '%2.2x' % ord(byte),
255        print >>result
256
257        match_index = string.find(bytes, options.data)
258        while match_index != -1:
259            num_matches = num_matches + 1
260            print >>result, '%#x: %#x + %u' % (start_addr +
261                                               match_index, start_addr, match_index)
262            match_index = string.find(bytes, options.data, match_index + 1)
263
264        if num_matches == 0:
265            print >>result, "error: no matches found"
266    else:
267        print >>result, 'error: %s' % (error.GetCString())
268
269
270if __name__ == '__main__':
271    print 'error: this script is designed to be used within the embedded script interpreter in LLDB'
272elif getattr(lldb, 'debugger', None):
273    memfind_command.__doc__ = create_memfind_options().format_help()
274    lldb.debugger.HandleCommand(
275        'command script add -f memory.memfind_command memfind')
276    print '"memfind" command installed, use the "--help" option for detailed help'
277