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