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