xref: /openbsd-src/gnu/llvm/lldb/examples/python/memory.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick#!/usr/bin/env python
2061da546Spatrick
3061da546Spatrick#----------------------------------------------------------------------
4061da546Spatrick# Be sure to add the python path that points to the LLDB shared library.
5061da546Spatrick#
6061da546Spatrick# # To use this in the embedded python interpreter using "lldb" just
7061da546Spatrick# import it with the full path using the "command script import"
8061da546Spatrick# command
9061da546Spatrick#   (lldb) command script import /path/to/cmdtemplate.py
10061da546Spatrick#----------------------------------------------------------------------
11061da546Spatrick
12061da546Spatrickimport platform
13061da546Spatrickimport os
14061da546Spatrickimport re
15061da546Spatrickimport sys
16061da546Spatrickimport subprocess
17061da546Spatrick
18061da546Spatricktry:
19061da546Spatrick    # Just try for LLDB in case PYTHONPATH is already correctly setup
20061da546Spatrick    import lldb
21061da546Spatrickexcept ImportError:
22061da546Spatrick    lldb_python_dirs = list()
23061da546Spatrick    # lldb is not in the PYTHONPATH, try some defaults for the current platform
24061da546Spatrick    platform_system = platform.system()
25061da546Spatrick    if platform_system == 'Darwin':
26061da546Spatrick        # On Darwin, try the currently selected Xcode directory
27061da546Spatrick        xcode_dir = subprocess.check_output("xcode-select --print-path", shell=True)
28061da546Spatrick        if xcode_dir:
29061da546Spatrick            lldb_python_dirs.append(
30061da546Spatrick                os.path.realpath(
31061da546Spatrick                    xcode_dir +
32061da546Spatrick                    '/../SharedFrameworks/LLDB.framework/Resources/Python'))
33061da546Spatrick            lldb_python_dirs.append(
34061da546Spatrick                xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
35061da546Spatrick        lldb_python_dirs.append(
36061da546Spatrick            '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
37061da546Spatrick    success = False
38061da546Spatrick    for lldb_python_dir in lldb_python_dirs:
39061da546Spatrick        if os.path.exists(lldb_python_dir):
40061da546Spatrick            if not (sys.path.__contains__(lldb_python_dir)):
41061da546Spatrick                sys.path.append(lldb_python_dir)
42061da546Spatrick                try:
43061da546Spatrick                    import lldb
44061da546Spatrick                except ImportError:
45061da546Spatrick                    pass
46061da546Spatrick                else:
47061da546Spatrick                    print('imported lldb from: "%s"' % (lldb_python_dir))
48061da546Spatrick                    success = True
49061da546Spatrick                    break
50061da546Spatrick    if not success:
51061da546Spatrick        print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly")
52061da546Spatrick        sys.exit(1)
53061da546Spatrick
54061da546Spatrickimport optparse
55061da546Spatrickimport shlex
56061da546Spatrickimport string
57061da546Spatrickimport struct
58061da546Spatrickimport time
59061da546Spatrick
60061da546Spatrick
61061da546Spatrickdef append_data_callback(option, opt_str, value, parser):
62061da546Spatrick    if opt_str == "--uint8":
63061da546Spatrick        int8 = int(value, 0)
64061da546Spatrick        parser.values.data += struct.pack('1B', int8)
65061da546Spatrick    if opt_str == "--uint16":
66061da546Spatrick        int16 = int(value, 0)
67061da546Spatrick        parser.values.data += struct.pack('1H', int16)
68061da546Spatrick    if opt_str == "--uint32":
69061da546Spatrick        int32 = int(value, 0)
70061da546Spatrick        parser.values.data += struct.pack('1I', int32)
71061da546Spatrick    if opt_str == "--uint64":
72061da546Spatrick        int64 = int(value, 0)
73061da546Spatrick        parser.values.data += struct.pack('1Q', int64)
74061da546Spatrick    if opt_str == "--int8":
75061da546Spatrick        int8 = int(value, 0)
76061da546Spatrick        parser.values.data += struct.pack('1b', int8)
77061da546Spatrick    if opt_str == "--int16":
78061da546Spatrick        int16 = int(value, 0)
79061da546Spatrick        parser.values.data += struct.pack('1h', int16)
80061da546Spatrick    if opt_str == "--int32":
81061da546Spatrick        int32 = int(value, 0)
82061da546Spatrick        parser.values.data += struct.pack('1i', int32)
83061da546Spatrick    if opt_str == "--int64":
84061da546Spatrick        int64 = int(value, 0)
85061da546Spatrick        parser.values.data += struct.pack('1q', int64)
86061da546Spatrick
87061da546Spatrick
88061da546Spatrickdef create_memfind_options():
89061da546Spatrick    usage = "usage: %prog [options] STARTADDR [ENDADDR]"
90061da546Spatrick    description = '''This command can find data in a specified address range.
91061da546SpatrickOptions are used to specify the data that is to be looked for and the options
92061da546Spatrickcan be specified multiple times to look for longer streams of data.
93061da546Spatrick'''
94061da546Spatrick    parser = optparse.OptionParser(
95061da546Spatrick        description=description,
96061da546Spatrick        prog='memfind',
97061da546Spatrick        usage=usage)
98061da546Spatrick    parser.add_option(
99061da546Spatrick        '-s',
100061da546Spatrick        '--size',
101061da546Spatrick        type='int',
102061da546Spatrick        metavar='BYTESIZE',
103061da546Spatrick        dest='size',
104061da546Spatrick        help='Specify the byte size to search.',
105061da546Spatrick        default=0)
106061da546Spatrick    parser.add_option(
107061da546Spatrick        '--int8',
108061da546Spatrick        action="callback",
109061da546Spatrick        callback=append_data_callback,
110061da546Spatrick        type='string',
111061da546Spatrick        metavar='INT',
112061da546Spatrick        dest='data',
113061da546Spatrick        help='Specify a 8 bit signed integer value to search for in memory.',
114061da546Spatrick        default='')
115061da546Spatrick    parser.add_option(
116061da546Spatrick        '--int16',
117061da546Spatrick        action="callback",
118061da546Spatrick        callback=append_data_callback,
119061da546Spatrick        type='string',
120061da546Spatrick        metavar='INT',
121061da546Spatrick        dest='data',
122061da546Spatrick        help='Specify a 16 bit signed integer value to search for in memory.',
123061da546Spatrick        default='')
124061da546Spatrick    parser.add_option(
125061da546Spatrick        '--int32',
126061da546Spatrick        action="callback",
127061da546Spatrick        callback=append_data_callback,
128061da546Spatrick        type='string',
129061da546Spatrick        metavar='INT',
130061da546Spatrick        dest='data',
131061da546Spatrick        help='Specify a 32 bit signed integer value to search for in memory.',
132061da546Spatrick        default='')
133061da546Spatrick    parser.add_option(
134061da546Spatrick        '--int64',
135061da546Spatrick        action="callback",
136061da546Spatrick        callback=append_data_callback,
137061da546Spatrick        type='string',
138061da546Spatrick        metavar='INT',
139061da546Spatrick        dest='data',
140061da546Spatrick        help='Specify a 64 bit signed integer value to search for in memory.',
141061da546Spatrick        default='')
142061da546Spatrick    parser.add_option(
143061da546Spatrick        '--uint8',
144061da546Spatrick        action="callback",
145061da546Spatrick        callback=append_data_callback,
146061da546Spatrick        type='string',
147061da546Spatrick        metavar='INT',
148061da546Spatrick        dest='data',
149061da546Spatrick        help='Specify a 8 bit unsigned integer value to search for in memory.',
150061da546Spatrick        default='')
151061da546Spatrick    parser.add_option(
152061da546Spatrick        '--uint16',
153061da546Spatrick        action="callback",
154061da546Spatrick        callback=append_data_callback,
155061da546Spatrick        type='string',
156061da546Spatrick        metavar='INT',
157061da546Spatrick        dest='data',
158061da546Spatrick        help='Specify a 16 bit unsigned integer value to search for in memory.',
159061da546Spatrick        default='')
160061da546Spatrick    parser.add_option(
161061da546Spatrick        '--uint32',
162061da546Spatrick        action="callback",
163061da546Spatrick        callback=append_data_callback,
164061da546Spatrick        type='string',
165061da546Spatrick        metavar='INT',
166061da546Spatrick        dest='data',
167061da546Spatrick        help='Specify a 32 bit unsigned integer value to search for in memory.',
168061da546Spatrick        default='')
169061da546Spatrick    parser.add_option(
170061da546Spatrick        '--uint64',
171061da546Spatrick        action="callback",
172061da546Spatrick        callback=append_data_callback,
173061da546Spatrick        type='string',
174061da546Spatrick        metavar='INT',
175061da546Spatrick        dest='data',
176061da546Spatrick        help='Specify a 64 bit unsigned integer value to search for in memory.',
177061da546Spatrick        default='')
178061da546Spatrick    return parser
179061da546Spatrick
180061da546Spatrick
181061da546Spatrickdef memfind_command(debugger, command, result, dict):
182061da546Spatrick    # Use the Shell Lexer to properly parse up command options just like a
183061da546Spatrick    # shell would
184061da546Spatrick    command_args = shlex.split(command)
185061da546Spatrick    parser = create_memfind_options()
186061da546Spatrick    (options, args) = parser.parse_args(command_args)
187061da546Spatrick    # try:
188061da546Spatrick    #     (options, args) = parser.parse_args(command_args)
189061da546Spatrick    # except:
190061da546Spatrick    #     # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
191061da546Spatrick    #     # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
192061da546Spatrick    #     result.SetStatus (lldb.eReturnStatusFailed)
193061da546Spatrick    #     print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string
194061da546Spatrick    #     return
195061da546Spatrick    memfind(debugger.GetSelectedTarget(), options, args, result)
196061da546Spatrick
197061da546Spatrick
198061da546Spatrickdef print_error(str, show_usage, result):
199061da546Spatrick    print(str, file=result)
200061da546Spatrick    if show_usage:
201061da546Spatrick        print(create_memfind_options().format_help(), file=result)
202061da546Spatrick
203061da546Spatrick
204061da546Spatrickdef memfind(target, options, args, result):
205061da546Spatrick    num_args = len(args)
206061da546Spatrick    start_addr = 0
207061da546Spatrick    if num_args == 1:
208061da546Spatrick        if options.size > 0:
209061da546Spatrick            print_error(
210061da546Spatrick                "error: --size must be specified if there is no ENDADDR argument",
211061da546Spatrick                True,
212061da546Spatrick                result)
213061da546Spatrick            return
214061da546Spatrick        start_addr = int(args[0], 0)
215061da546Spatrick    elif num_args == 2:
216061da546Spatrick        if options.size != 0:
217061da546Spatrick            print_error(
218061da546Spatrick                "error: --size can't be specified with an ENDADDR argument",
219061da546Spatrick                True,
220061da546Spatrick                result)
221061da546Spatrick            return
222061da546Spatrick        start_addr = int(args[0], 0)
223061da546Spatrick        end_addr = int(args[1], 0)
224061da546Spatrick        if start_addr >= end_addr:
225061da546Spatrick            print_error(
226061da546Spatrick                "error: inavlid memory range [%#x - %#x)" %
227061da546Spatrick                (start_addr, end_addr), True, result)
228061da546Spatrick            return
229061da546Spatrick        options.size = end_addr - start_addr
230061da546Spatrick    else:
231061da546Spatrick        print_error("error: memfind takes 1 or 2 arguments", True, result)
232061da546Spatrick        return
233061da546Spatrick
234061da546Spatrick    if not options.data:
235061da546Spatrick        print('error: no data specified to search for', file=result)
236061da546Spatrick        return
237061da546Spatrick
238061da546Spatrick    if not target:
239061da546Spatrick        print('error: invalid target', file=result)
240061da546Spatrick        return
241061da546Spatrick    process = target.process
242061da546Spatrick    if not process:
243061da546Spatrick        print('error: invalid process', file=result)
244061da546Spatrick        return
245061da546Spatrick
246061da546Spatrick    error = lldb.SBError()
247061da546Spatrick    bytes = process.ReadMemory(start_addr, options.size, error)
248061da546Spatrick    if error.Success():
249061da546Spatrick        num_matches = 0
250061da546Spatrick        print("Searching memory range [%#x - %#x) for" % (
251061da546Spatrick            start_addr, end_addr), end=' ', file=result)
252061da546Spatrick        for byte in options.data:
253061da546Spatrick            print('%2.2x' % ord(byte), end=' ', file=result)
254061da546Spatrick        print(file=result)
255061da546Spatrick
256061da546Spatrick        match_index = string.find(bytes, options.data)
257061da546Spatrick        while match_index != -1:
258061da546Spatrick            num_matches = num_matches + 1
259061da546Spatrick            print('%#x: %#x + %u' % (start_addr +
260061da546Spatrick                                               match_index, start_addr, match_index), file=result)
261061da546Spatrick            match_index = string.find(bytes, options.data, match_index + 1)
262061da546Spatrick
263061da546Spatrick        if num_matches == 0:
264061da546Spatrick            print("error: no matches found", file=result)
265061da546Spatrick    else:
266061da546Spatrick        print('error: %s' % (error.GetCString()), file=result)
267061da546Spatrick
268061da546Spatrick
269061da546Spatrickif __name__ == '__main__':
270061da546Spatrick    print('error: this script is designed to be used within the embedded script interpreter in LLDB')
271*f6aab3d8Srobert
272*f6aab3d8Srobertdef __lldb_init_module(debugger, internal_dict):
273061da546Spatrick    memfind_command.__doc__ = create_memfind_options().format_help()
274*f6aab3d8Srobert    debugger.HandleCommand(
275*f6aab3d8Srobert        'command script add -o -f memory.memfind_command memfind')
276061da546Spatrick    print('"memfind" command installed, use the "--help" option for detailed help')
277