1515bc8c1Sserge-sans-paille#!/usr/bin/env python
2e2841639SGreg Clayton
3e2841639SGreg Clayton#----------------------------------------------------------------------
4e2841639SGreg Clayton# This module will enable GDB remote packet logging when the
5e2841639SGreg Clayton# 'start_gdb_log' command is called with a filename to log to. When the
6e2841639SGreg Clayton# 'stop_gdb_log' command is called, it will disable the logging and
7e2841639SGreg Clayton# print out statistics about how long commands took to execute and also
8e2841639SGreg Clayton# will primnt ou
9e2841639SGreg Clayton# Be sure to add the python path that points to the LLDB shared library.
10e2841639SGreg Clayton#
11e2841639SGreg Clayton# To use this in the embedded python interpreter using "lldb" just
12e2841639SGreg Clayton# import it with the full path using the "command script import"
13e2841639SGreg Clayton# command. This can be done from the LLDB command line:
14e2841639SGreg Clayton#   (lldb) command script import /path/to/gdbremote.py
15e2841639SGreg Clayton# Or it can be added to your ~/.lldbinit file so this module is always
16e2841639SGreg Clayton# available.
17e2841639SGreg Clayton#----------------------------------------------------------------------
18e2841639SGreg Clayton
19cb6c9f73SPavel Labathfrom __future__ import print_function
20374b6714SGreg Claytonimport binascii
211a12dd70SSerge Gueltonimport subprocess
228c2afa0cSGreg Claytonimport json
2325f82aaeSGreg Claytonimport math
24e2841639SGreg Claytonimport optparse
25e2841639SGreg Claytonimport os
26e2841639SGreg Claytonimport re
278ebb9a85SGreg Claytonimport shlex
288ebb9a85SGreg Claytonimport string
298ebb9a85SGreg Claytonimport sys
30e2841639SGreg Claytonimport tempfile
31374b6714SGreg Claytonimport xml.etree.ElementTree as ET
32e2841639SGreg Clayton
33f51a23fbSGreg Clayton#----------------------------------------------------------------------
34f51a23fbSGreg Clayton# Global variables
35f51a23fbSGreg Clayton#----------------------------------------------------------------------
36f51a23fbSGreg Claytong_log_file = ''
37f51a23fbSGreg Claytong_byte_order = 'little'
38205d6189SGreg Claytong_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)')
39a7a5e5a6SGreg Claytong_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)')
40f51a23fbSGreg Clayton
41b9c1b51eSKate Stone
428ebb9a85SGreg Claytonclass TerminalColors:
438ebb9a85SGreg Clayton    '''Simple terminal colors class'''
44b9c1b51eSKate Stone
45f51a23fbSGreg Clayton    def __init__(self, enabled=True):
468ebb9a85SGreg Clayton        # TODO: discover terminal type from "file" and disable if
478ebb9a85SGreg Clayton        # it can't handle the color codes
488ebb9a85SGreg Clayton        self.enabled = enabled
498ebb9a85SGreg Clayton
508ebb9a85SGreg Clayton    def reset(self):
518ebb9a85SGreg Clayton        '''Reset all terminal colors and formatting.'''
528ebb9a85SGreg Clayton        if self.enabled:
53b9c1b51eSKate Stone            return "\x1b[0m"
54f51a23fbSGreg Clayton        return ''
558ebb9a85SGreg Clayton
568ebb9a85SGreg Clayton    def bold(self, on=True):
57d93c4a33SBruce Mitchener        '''Enable or disable bold depending on the "on" parameter.'''
588ebb9a85SGreg Clayton        if self.enabled:
598ebb9a85SGreg Clayton            if on:
60b9c1b51eSKate Stone                return "\x1b[1m"
618ebb9a85SGreg Clayton            else:
62b9c1b51eSKate Stone                return "\x1b[22m"
63f51a23fbSGreg Clayton        return ''
648ebb9a85SGreg Clayton
658ebb9a85SGreg Clayton    def italics(self, on=True):
66d93c4a33SBruce Mitchener        '''Enable or disable italics depending on the "on" parameter.'''
678ebb9a85SGreg Clayton        if self.enabled:
688ebb9a85SGreg Clayton            if on:
69b9c1b51eSKate Stone                return "\x1b[3m"
708ebb9a85SGreg Clayton            else:
71b9c1b51eSKate Stone                return "\x1b[23m"
72f51a23fbSGreg Clayton        return ''
738ebb9a85SGreg Clayton
748ebb9a85SGreg Clayton    def underline(self, on=True):
75d93c4a33SBruce Mitchener        '''Enable or disable underline depending on the "on" parameter.'''
768ebb9a85SGreg Clayton        if self.enabled:
778ebb9a85SGreg Clayton            if on:
78b9c1b51eSKate Stone                return "\x1b[4m"
798ebb9a85SGreg Clayton            else:
80b9c1b51eSKate Stone                return "\x1b[24m"
81f51a23fbSGreg Clayton        return ''
82f51a23fbSGreg Clayton
838ebb9a85SGreg Clayton    def inverse(self, on=True):
84d93c4a33SBruce Mitchener        '''Enable or disable inverse depending on the "on" parameter.'''
858ebb9a85SGreg Clayton        if self.enabled:
868ebb9a85SGreg Clayton            if on:
87b9c1b51eSKate Stone                return "\x1b[7m"
888ebb9a85SGreg Clayton            else:
89b9c1b51eSKate Stone                return "\x1b[27m"
90f51a23fbSGreg Clayton        return ''
918ebb9a85SGreg Clayton
928ebb9a85SGreg Clayton    def strike(self, on=True):
93d93c4a33SBruce Mitchener        '''Enable or disable strike through depending on the "on" parameter.'''
948ebb9a85SGreg Clayton        if self.enabled:
958ebb9a85SGreg Clayton            if on:
96b9c1b51eSKate Stone                return "\x1b[9m"
978ebb9a85SGreg Clayton            else:
98b9c1b51eSKate Stone                return "\x1b[29m"
99f51a23fbSGreg Clayton        return ''
1008ebb9a85SGreg Clayton
1018ebb9a85SGreg Clayton    def black(self, fg=True):
1028ebb9a85SGreg Clayton        '''Set the foreground or background color to black.
1038ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1048ebb9a85SGreg Clayton        if self.enabled:
1058ebb9a85SGreg Clayton            if fg:
106b9c1b51eSKate Stone                return "\x1b[30m"
1078ebb9a85SGreg Clayton            else:
108b9c1b51eSKate Stone                return "\x1b[40m"
109f51a23fbSGreg Clayton        return ''
1108ebb9a85SGreg Clayton
1118ebb9a85SGreg Clayton    def red(self, fg=True):
1128ebb9a85SGreg Clayton        '''Set the foreground or background color to red.
1138ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1148ebb9a85SGreg Clayton        if self.enabled:
1158ebb9a85SGreg Clayton            if fg:
116b9c1b51eSKate Stone                return "\x1b[31m"
1178ebb9a85SGreg Clayton            else:
118b9c1b51eSKate Stone                return "\x1b[41m"
119f51a23fbSGreg Clayton        return ''
1208ebb9a85SGreg Clayton
1218ebb9a85SGreg Clayton    def green(self, fg=True):
1228ebb9a85SGreg Clayton        '''Set the foreground or background color to green.
1238ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1248ebb9a85SGreg Clayton        if self.enabled:
1258ebb9a85SGreg Clayton            if fg:
126b9c1b51eSKate Stone                return "\x1b[32m"
1278ebb9a85SGreg Clayton            else:
128b9c1b51eSKate Stone                return "\x1b[42m"
129f51a23fbSGreg Clayton        return ''
1308ebb9a85SGreg Clayton
1318ebb9a85SGreg Clayton    def yellow(self, fg=True):
1328ebb9a85SGreg Clayton        '''Set the foreground or background color to yellow.
1338ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1348ebb9a85SGreg Clayton        if self.enabled:
1358ebb9a85SGreg Clayton            if fg:
136b9c1b51eSKate Stone                return "\x1b[33m"
137a542e08cSGreg Clayton            else:
138b9c1b51eSKate Stone                return "\x1b[43m"
139f51a23fbSGreg Clayton        return ''
1408ebb9a85SGreg Clayton
1418ebb9a85SGreg Clayton    def blue(self, fg=True):
1428ebb9a85SGreg Clayton        '''Set the foreground or background color to blue.
1438ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1448ebb9a85SGreg Clayton        if self.enabled:
1458ebb9a85SGreg Clayton            if fg:
146b9c1b51eSKate Stone                return "\x1b[34m"
1478ebb9a85SGreg Clayton            else:
148b9c1b51eSKate Stone                return "\x1b[44m"
149f51a23fbSGreg Clayton        return ''
1508ebb9a85SGreg Clayton
1518ebb9a85SGreg Clayton    def magenta(self, fg=True):
1528ebb9a85SGreg Clayton        '''Set the foreground or background color to magenta.
1538ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1548ebb9a85SGreg Clayton        if self.enabled:
1558ebb9a85SGreg Clayton            if fg:
156b9c1b51eSKate Stone                return "\x1b[35m"
1578ebb9a85SGreg Clayton            else:
158b9c1b51eSKate Stone                return "\x1b[45m"
159f51a23fbSGreg Clayton        return ''
1608ebb9a85SGreg Clayton
1618ebb9a85SGreg Clayton    def cyan(self, fg=True):
1628ebb9a85SGreg Clayton        '''Set the foreground or background color to cyan.
1638ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1648ebb9a85SGreg Clayton        if self.enabled:
1658ebb9a85SGreg Clayton            if fg:
166b9c1b51eSKate Stone                return "\x1b[36m"
1678ebb9a85SGreg Clayton            else:
168b9c1b51eSKate Stone                return "\x1b[46m"
169f51a23fbSGreg Clayton        return ''
1708ebb9a85SGreg Clayton
1718ebb9a85SGreg Clayton    def white(self, fg=True):
1728ebb9a85SGreg Clayton        '''Set the foreground or background color to white.
1738ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1748ebb9a85SGreg Clayton        if self.enabled:
1758ebb9a85SGreg Clayton            if fg:
176b9c1b51eSKate Stone                return "\x1b[37m"
1778ebb9a85SGreg Clayton            else:
178b9c1b51eSKate Stone                return "\x1b[47m"
179f51a23fbSGreg Clayton        return ''
1808ebb9a85SGreg Clayton
1818ebb9a85SGreg Clayton    def default(self, fg=True):
1828ebb9a85SGreg Clayton        '''Set the foreground or background color to the default.
1838ebb9a85SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
1848ebb9a85SGreg Clayton        if self.enabled:
1858ebb9a85SGreg Clayton            if fg:
186b9c1b51eSKate Stone                return "\x1b[39m"
1878ebb9a85SGreg Clayton            else:
188b9c1b51eSKate Stone                return "\x1b[49m"
189f51a23fbSGreg Clayton        return ''
1908ebb9a85SGreg Clayton
191e2841639SGreg Clayton
192e2841639SGreg Claytondef start_gdb_log(debugger, command, result, dict):
193e2841639SGreg Clayton    '''Start logging GDB remote packets by enabling logging with timestamps and
194e2841639SGreg Clayton    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
195e2841639SGreg Clayton    in order to dump out the commands.'''
1968ebb9a85SGreg Clayton    global g_log_file
197e2841639SGreg Clayton    command_args = shlex.split(command)
198e2841639SGreg Clayton    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
199e2841639SGreg Clayton    description = '''The command enables GDB remote packet logging with timestamps. The packets will be logged to <LOGFILEPATH> if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will
200e2841639SGreg Clayton    be aggregated and displayed.'''
201b9c1b51eSKate Stone    parser = optparse.OptionParser(
202b9c1b51eSKate Stone        description=description,
203b9c1b51eSKate Stone        prog='start_gdb_log',
204b9c1b51eSKate Stone        usage=usage)
205b9c1b51eSKate Stone    parser.add_option(
206b9c1b51eSKate Stone        '-v',
207b9c1b51eSKate Stone        '--verbose',
208b9c1b51eSKate Stone        action='store_true',
209b9c1b51eSKate Stone        dest='verbose',
210b9c1b51eSKate Stone        help='display verbose debug info',
211b9c1b51eSKate Stone        default=False)
212e2841639SGreg Clayton    try:
213e2841639SGreg Clayton        (options, args) = parser.parse_args(command_args)
214e2841639SGreg Clayton    except:
215e2841639SGreg Clayton        return
216e2841639SGreg Clayton
2178ebb9a85SGreg Clayton    if g_log_file:
218b9c1b51eSKate Stone        result.PutCString(
219b9c1b51eSKate Stone            'error: logging is already in progress with file "%s"' %
220b9c1b51eSKate Stone            g_log_file)
221e2841639SGreg Clayton    else:
222e2841639SGreg Clayton        args_len = len(args)
223e2841639SGreg Clayton        if args_len == 0:
2248ebb9a85SGreg Clayton            g_log_file = tempfile.mktemp()
225e2841639SGreg Clayton        elif len(args) == 1:
2268ebb9a85SGreg Clayton            g_log_file = args[0]
227e2841639SGreg Clayton
2288ebb9a85SGreg Clayton        if g_log_file:
229b9c1b51eSKate Stone            debugger.HandleCommand(
230b9c1b51eSKate Stone                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
231b9c1b51eSKate Stone                g_log_file)
232b9c1b51eSKate Stone            result.PutCString(
233b9c1b51eSKate Stone                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
234b9c1b51eSKate Stone                g_log_file)
235e2841639SGreg Clayton            return
236e2841639SGreg Clayton
237e2841639SGreg Clayton        result.PutCString('error: invalid log file path')
238e2841639SGreg Clayton    result.PutCString(usage)
239e2841639SGreg Clayton
240b9c1b51eSKate Stone
241e2841639SGreg Claytondef stop_gdb_log(debugger, command, result, dict):
242e2841639SGreg Clayton    '''Stop logging GDB remote packets to the file that was specified in a call
243e2841639SGreg Clayton    to "start_gdb_log" and normalize the timestamps to be relative to the first
244e2841639SGreg Clayton    timestamp in the log file. Also print out statistics for how long each
245e2841639SGreg Clayton    command took to allow performance bottlenecks to be determined.'''
2468ebb9a85SGreg Clayton    global g_log_file
247e2841639SGreg Clayton    # Any commands whose names might be followed by more valid C identifier
248e2841639SGreg Clayton    # characters must be listed here
249e2841639SGreg Clayton    command_args = shlex.split(command)
250e2841639SGreg Clayton    usage = "usage: stop_gdb_log [options]"
251e2841639SGreg Clayton    description = '''The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log.'''
252b9c1b51eSKate Stone    parser = optparse.OptionParser(
253b9c1b51eSKate Stone        description=description,
254b9c1b51eSKate Stone        prog='stop_gdb_log',
255b9c1b51eSKate Stone        usage=usage)
256b9c1b51eSKate Stone    parser.add_option(
257b9c1b51eSKate Stone        '-v',
258b9c1b51eSKate Stone        '--verbose',
259b9c1b51eSKate Stone        action='store_true',
260b9c1b51eSKate Stone        dest='verbose',
261b9c1b51eSKate Stone        help='display verbose debug info',
262b9c1b51eSKate Stone        default=False)
263b9c1b51eSKate Stone    parser.add_option(
264*cd89f94aSDominic Chen        '--plot',
265*cd89f94aSDominic Chen        action='store_true',
266*cd89f94aSDominic Chen        dest='plot',
267*cd89f94aSDominic Chen        help='plot packet latencies by packet type',
268*cd89f94aSDominic Chen        default=False)
269*cd89f94aSDominic Chen    parser.add_option(
270b9c1b51eSKate Stone        '-q',
271b9c1b51eSKate Stone        '--quiet',
272b9c1b51eSKate Stone        action='store_true',
273b9c1b51eSKate Stone        dest='quiet',
274b9c1b51eSKate Stone        help='display verbose debug info',
275b9c1b51eSKate Stone        default=False)
276b9c1b51eSKate Stone    parser.add_option(
277b9c1b51eSKate Stone        '-C',
278b9c1b51eSKate Stone        '--color',
279b9c1b51eSKate Stone        action='store_true',
280b9c1b51eSKate Stone        dest='color',
281b9c1b51eSKate Stone        help='add terminal colors',
282b9c1b51eSKate Stone        default=False)
283b9c1b51eSKate Stone    parser.add_option(
284b9c1b51eSKate Stone        '-c',
285b9c1b51eSKate Stone        '--sort-by-count',
286b9c1b51eSKate Stone        action='store_true',
287b9c1b51eSKate Stone        dest='sort_count',
288b9c1b51eSKate Stone        help='display verbose debug info',
289b9c1b51eSKate Stone        default=False)
290b9c1b51eSKate Stone    parser.add_option(
291b9c1b51eSKate Stone        '-s',
292b9c1b51eSKate Stone        '--symbolicate',
293b9c1b51eSKate Stone        action='store_true',
294b9c1b51eSKate Stone        dest='symbolicate',
295b9c1b51eSKate Stone        help='symbolicate addresses in log using current "lldb.target"',
296b9c1b51eSKate Stone        default=False)
297e2841639SGreg Clayton    try:
298e2841639SGreg Clayton        (options, args) = parser.parse_args(command_args)
299e2841639SGreg Clayton    except:
300e2841639SGreg Clayton        return
301f51a23fbSGreg Clayton    options.colors = TerminalColors(options.color)
302f51a23fbSGreg Clayton    options.symbolicator = None
303f51a23fbSGreg Clayton    if options.symbolicate:
304f51a23fbSGreg Clayton        if lldb.target:
305f51a23fbSGreg Clayton            import lldb.utils.symbolication
306f51a23fbSGreg Clayton            options.symbolicator = lldb.utils.symbolication.Symbolicator()
307f51a23fbSGreg Clayton            options.symbolicator.target = lldb.target
308f51a23fbSGreg Clayton        else:
309525cd59fSSerge Guelton            print("error: can't symbolicate without a target")
310e2841639SGreg Clayton
3118ebb9a85SGreg Clayton    if not g_log_file:
312b9c1b51eSKate Stone        result.PutCString(
313b9c1b51eSKate Stone            'error: logging must have been previously enabled with a call to "stop_gdb_log"')
3148ebb9a85SGreg Clayton    elif os.path.exists(g_log_file):
315e2841639SGreg Clayton        if len(args) == 0:
316b9c1b51eSKate Stone            debugger.HandleCommand('log disable gdb-remote packets')
317b9c1b51eSKate Stone            result.PutCString(
318b9c1b51eSKate Stone                "GDB packet logging disabled. Logged packets are in '%s'" %
319b9c1b51eSKate Stone                g_log_file)
3208ebb9a85SGreg Clayton            parse_gdb_log_file(g_log_file, options)
321e2841639SGreg Clayton        else:
322e2841639SGreg Clayton            result.PutCString(usage)
323e2841639SGreg Clayton    else:
324525cd59fSSerge Guelton        print('error: the GDB packet log file "%s" does not exist' % g_log_file)
325e2841639SGreg Clayton
326b9c1b51eSKate Stone
3278ebb9a85SGreg Claytondef is_hex_byte(str):
3288ebb9a85SGreg Clayton    if len(str) == 2:
329b9c1b51eSKate Stone        return str[0] in string.hexdigits and str[1] in string.hexdigits
3308ebb9a85SGreg Clayton    return False
3318ebb9a85SGreg Clayton
332db1550abSGreg Claytondef get_hex_string_if_all_printable(str):
333db1550abSGreg Clayton    try:
334cb6c9f73SPavel Labath        s = binascii.unhexlify(str).decode()
335db1550abSGreg Clayton        if all(c in string.printable for c in s):
336db1550abSGreg Clayton            return s
337cb6c9f73SPavel Labath    except (TypeError, binascii.Error, UnicodeDecodeError):
338db1550abSGreg Clayton        pass
339db1550abSGreg Clayton    return None
340db1550abSGreg Clayton
3418ebb9a85SGreg Clayton# global register info list
3428ebb9a85SGreg Claytong_register_infos = list()
3438ebb9a85SGreg Claytong_max_register_info_name_len = 0
3448ebb9a85SGreg Clayton
345b9c1b51eSKate Stone
3468ebb9a85SGreg Claytonclass RegisterInfo:
3478ebb9a85SGreg Clayton    """Class that represents register information"""
348b9c1b51eSKate Stone
3498ebb9a85SGreg Clayton    def __init__(self, kvp):
3508ebb9a85SGreg Clayton        self.info = dict()
3518ebb9a85SGreg Clayton        for kv in kvp:
3528ebb9a85SGreg Clayton            key = kv[0]
3538ebb9a85SGreg Clayton            value = kv[1]
3548ebb9a85SGreg Clayton            self.info[key] = value
355b9c1b51eSKate Stone
3568ebb9a85SGreg Clayton    def name(self):
3578ebb9a85SGreg Clayton        '''Get the name of the register.'''
3588ebb9a85SGreg Clayton        if self.info and 'name' in self.info:
3598ebb9a85SGreg Clayton            return self.info['name']
3608ebb9a85SGreg Clayton        return None
3618ebb9a85SGreg Clayton
3628ebb9a85SGreg Clayton    def bit_size(self):
3638ebb9a85SGreg Clayton        '''Get the size in bits of the register.'''
3648ebb9a85SGreg Clayton        if self.info and 'bitsize' in self.info:
3658ebb9a85SGreg Clayton            return int(self.info['bitsize'])
3668ebb9a85SGreg Clayton        return 0
3678ebb9a85SGreg Clayton
3688ebb9a85SGreg Clayton    def byte_size(self):
3698ebb9a85SGreg Clayton        '''Get the size in bytes of the register.'''
3708ebb9a85SGreg Clayton        return self.bit_size() / 8
3718ebb9a85SGreg Clayton
3728ebb9a85SGreg Clayton    def get_value_from_hex_string(self, hex_str):
3738ebb9a85SGreg Clayton        '''Dump the register value given a native byte order encoded hex ASCII byte string.'''
3748ebb9a85SGreg Clayton        encoding = self.info['encoding']
3758ebb9a85SGreg Clayton        bit_size = self.bit_size()
3768ebb9a85SGreg Clayton        packet = Packet(hex_str)
3778ebb9a85SGreg Clayton        if encoding == 'uint':
3788ebb9a85SGreg Clayton            uval = packet.get_hex_uint(g_byte_order)
3798ebb9a85SGreg Clayton            if bit_size == 8:
3808ebb9a85SGreg Clayton                return '0x%2.2x' % (uval)
3818ebb9a85SGreg Clayton            elif bit_size == 16:
3828ebb9a85SGreg Clayton                return '0x%4.4x' % (uval)
3838ebb9a85SGreg Clayton            elif bit_size == 32:
3848ebb9a85SGreg Clayton                return '0x%8.8x' % (uval)
3858ebb9a85SGreg Clayton            elif bit_size == 64:
3868ebb9a85SGreg Clayton                return '0x%16.16x' % (uval)
387b9c1b51eSKate Stone        bytes = list()
3888ebb9a85SGreg Clayton        uval = packet.get_hex_uint8()
389b9c1b51eSKate Stone        while uval is not None:
3908ebb9a85SGreg Clayton            bytes.append(uval)
3918ebb9a85SGreg Clayton            uval = packet.get_hex_uint8()
3928ebb9a85SGreg Clayton        value_str = '0x'
3938ebb9a85SGreg Clayton        if g_byte_order == 'little':
3948ebb9a85SGreg Clayton            bytes.reverse()
3958ebb9a85SGreg Clayton        for byte in bytes:
3968ebb9a85SGreg Clayton            value_str += '%2.2x' % byte
3978ebb9a85SGreg Clayton        return '%s' % (value_str)
3988ebb9a85SGreg Clayton
3998ebb9a85SGreg Clayton    def __str__(self):
4008ebb9a85SGreg Clayton        '''Dump the register info key/value pairs'''
4018ebb9a85SGreg Clayton        s = ''
4028ebb9a85SGreg Clayton        for key in self.info.keys():
4038ebb9a85SGreg Clayton            if s:
4048ebb9a85SGreg Clayton                s += ', '
4058ebb9a85SGreg Clayton            s += "%s=%s " % (key, self.info[key])
4068ebb9a85SGreg Clayton        return s
4078ebb9a85SGreg Clayton
408b9c1b51eSKate Stone
4098ebb9a85SGreg Claytonclass Packet:
4108ebb9a85SGreg Clayton    """Class that represents a packet that contains string data"""
411b9c1b51eSKate Stone
4128ebb9a85SGreg Clayton    def __init__(self, packet_str):
4138ebb9a85SGreg Clayton        self.str = packet_str
4148ebb9a85SGreg Clayton
4158ebb9a85SGreg Clayton    def peek_char(self):
4168ebb9a85SGreg Clayton        ch = 0
4178ebb9a85SGreg Clayton        if self.str:
4188ebb9a85SGreg Clayton            ch = self.str[0]
4198ebb9a85SGreg Clayton        return ch
4208ebb9a85SGreg Clayton
4218ebb9a85SGreg Clayton    def get_char(self):
4228ebb9a85SGreg Clayton        ch = 0
4238ebb9a85SGreg Clayton        if self.str:
4248ebb9a85SGreg Clayton            ch = self.str[0]
4258ebb9a85SGreg Clayton            self.str = self.str[1:]
4268ebb9a85SGreg Clayton        return ch
4278ebb9a85SGreg Clayton
428205d6189SGreg Clayton    def skip_exact_string(self, s):
429205d6189SGreg Clayton        if self.str and self.str.startswith(s):
430205d6189SGreg Clayton            self.str = self.str[len(s):]
431205d6189SGreg Clayton            return True
432205d6189SGreg Clayton        else:
433205d6189SGreg Clayton            return False
434205d6189SGreg Clayton
435a7a5e5a6SGreg Clayton    def get_thread_id(self, fail_value=-1):
436a7a5e5a6SGreg Clayton        match = g_number_regex.match(self.str)
437a7a5e5a6SGreg Clayton        if match:
438a7a5e5a6SGreg Clayton            number_str = match.group(1)
439a7a5e5a6SGreg Clayton            self.str = self.str[len(number_str):]
440a7a5e5a6SGreg Clayton            return int(number_str, 0)
441a7a5e5a6SGreg Clayton        else:
442a7a5e5a6SGreg Clayton            return fail_value
443a7a5e5a6SGreg Clayton
4448ebb9a85SGreg Clayton    def get_hex_uint8(self):
445b9c1b51eSKate Stone        if self.str and len(self.str) >= 2 and self.str[
446b9c1b51eSKate Stone                0] in string.hexdigits and self.str[1] in string.hexdigits:
4478ebb9a85SGreg Clayton            uval = int(self.str[0:2], 16)
4488ebb9a85SGreg Clayton            self.str = self.str[2:]
4498ebb9a85SGreg Clayton            return uval
4508ebb9a85SGreg Clayton        return None
4518ebb9a85SGreg Clayton
4528ebb9a85SGreg Clayton    def get_hex_uint16(self, byte_order):
4538ebb9a85SGreg Clayton        uval = 0
4548ebb9a85SGreg Clayton        if byte_order == 'big':
4558ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4568ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4578ebb9a85SGreg Clayton        else:
4588ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4598ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4608ebb9a85SGreg Clayton        return uval
4618ebb9a85SGreg Clayton
4628ebb9a85SGreg Clayton    def get_hex_uint32(self, byte_order):
4638ebb9a85SGreg Clayton        uval = 0
4648ebb9a85SGreg Clayton        if byte_order == 'big':
4658ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 24
4668ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 16
4678ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4688ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4698ebb9a85SGreg Clayton        else:
4708ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4718ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4728ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 16
4738ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 24
4748ebb9a85SGreg Clayton        return uval
4758ebb9a85SGreg Clayton
4768ebb9a85SGreg Clayton    def get_hex_uint64(self, byte_order):
4778ebb9a85SGreg Clayton        uval = 0
4788ebb9a85SGreg Clayton        if byte_order == 'big':
4798ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 56
4808ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 48
4818ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 40
4828ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 32
4838ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 24
4848ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 16
4858ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4868ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4878ebb9a85SGreg Clayton        else:
4888ebb9a85SGreg Clayton            uval |= self.get_hex_uint8()
4898ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 8
4908ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 16
4918ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 24
4928ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 32
4938ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 40
4948ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 48
4958ebb9a85SGreg Clayton            uval |= self.get_hex_uint8() << 56
4968ebb9a85SGreg Clayton        return uval
4978ebb9a85SGreg Clayton
498205d6189SGreg Clayton    def get_number(self, fail_value=-1):
499205d6189SGreg Clayton        '''Get a number from the packet. The number must be in big endian format and should be parsed
500205d6189SGreg Clayton        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
501205d6189SGreg Clayton        [1-9] means decimal, etc)'''
502205d6189SGreg Clayton        match = g_number_regex.match(self.str)
503205d6189SGreg Clayton        if match:
504205d6189SGreg Clayton            number_str = match.group(1)
505205d6189SGreg Clayton            self.str = self.str[len(number_str):]
506205d6189SGreg Clayton            return int(number_str, 0)
507205d6189SGreg Clayton        else:
508205d6189SGreg Clayton            return fail_value
509205d6189SGreg Clayton
510374b6714SGreg Clayton    def get_hex_ascii_str(self, n=0):
511374b6714SGreg Clayton        hex_chars = self.get_hex_chars(n)
512374b6714SGreg Clayton        if hex_chars:
513374b6714SGreg Clayton            return binascii.unhexlify(hex_chars)
514374b6714SGreg Clayton        else:
515374b6714SGreg Clayton            return None
516374b6714SGreg Clayton
5178ebb9a85SGreg Clayton    def get_hex_chars(self, n=0):
5188ebb9a85SGreg Clayton        str_len = len(self.str)
5198ebb9a85SGreg Clayton        if n == 0:
5208ebb9a85SGreg Clayton            # n was zero, so we need to determine all hex chars and
5218ebb9a85SGreg Clayton            # stop when we hit the end of the string of a non-hex character
5228ebb9a85SGreg Clayton            while n < str_len and self.str[n] in string.hexdigits:
5238ebb9a85SGreg Clayton                n = n + 1
5248ebb9a85SGreg Clayton        else:
5258ebb9a85SGreg Clayton            if n > str_len:
5268ebb9a85SGreg Clayton                return None  # Not enough chars
5278ebb9a85SGreg Clayton            # Verify all chars are hex if a length was specified
5288ebb9a85SGreg Clayton            for i in range(n):
5298ebb9a85SGreg Clayton                if self.str[i] not in string.hexdigits:
5308ebb9a85SGreg Clayton                    return None  # Not all hex digits
5318ebb9a85SGreg Clayton        if n == 0:
5328ebb9a85SGreg Clayton            return None
5338ebb9a85SGreg Clayton        hex_str = self.str[0:n]
5348ebb9a85SGreg Clayton        self.str = self.str[n:]
5358ebb9a85SGreg Clayton        return hex_str
5368ebb9a85SGreg Clayton
5378ebb9a85SGreg Clayton    def get_hex_uint(self, byte_order, n=0):
5388ebb9a85SGreg Clayton        if byte_order == 'big':
5398ebb9a85SGreg Clayton            hex_str = self.get_hex_chars(n)
540b9c1b51eSKate Stone            if hex_str is None:
5418ebb9a85SGreg Clayton                return None
5428ebb9a85SGreg Clayton            return int(hex_str, 16)
5438ebb9a85SGreg Clayton        else:
5448ebb9a85SGreg Clayton            uval = self.get_hex_uint8()
545b9c1b51eSKate Stone            if uval is None:
5468ebb9a85SGreg Clayton                return None
5478ebb9a85SGreg Clayton            uval_result = 0
5488ebb9a85SGreg Clayton            shift = 0
549b9c1b51eSKate Stone            while uval is not None:
5508ebb9a85SGreg Clayton                uval_result |= (uval << shift)
5518ebb9a85SGreg Clayton                shift += 8
5528ebb9a85SGreg Clayton                uval = self.get_hex_uint8()
5538ebb9a85SGreg Clayton            return uval_result
5548ebb9a85SGreg Clayton
5558ebb9a85SGreg Clayton    def get_key_value_pairs(self):
5568ebb9a85SGreg Clayton        kvp = list()
55725f82aaeSGreg Clayton        if ';' in self.str:
558cb6c9f73SPavel Labath            key_value_pairs = self.str.split(';')
5598ebb9a85SGreg Clayton            for key_value_pair in key_value_pairs:
5608ebb9a85SGreg Clayton                if len(key_value_pair):
561cb6c9f73SPavel Labath                    kvp.append(key_value_pair.split(':', 1))
5628ebb9a85SGreg Clayton        return kvp
5638ebb9a85SGreg Clayton
5648ebb9a85SGreg Clayton    def split(self, ch):
565*cd89f94aSDominic Chen        return self.str.split(ch)
5668ebb9a85SGreg Clayton
5678ebb9a85SGreg Clayton    def split_hex(self, ch, byte_order):
5688ebb9a85SGreg Clayton        hex_values = list()
569*cd89f94aSDominic Chen        strings = self.str.split(ch)
5708ebb9a85SGreg Clayton        for str in strings:
5718ebb9a85SGreg Clayton            hex_values.append(Packet(str).get_hex_uint(byte_order))
5728ebb9a85SGreg Clayton        return hex_values
5738ebb9a85SGreg Clayton
5748ebb9a85SGreg Clayton    def __str__(self):
5758ebb9a85SGreg Clayton        return self.str
5768ebb9a85SGreg Clayton
5778ebb9a85SGreg Clayton    def __len__(self):
5788ebb9a85SGreg Clayton        return len(self.str)
5798ebb9a85SGreg Clayton
5808ebb9a85SGreg Claytong_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);')
581b9c1b51eSKate Stone
582b9c1b51eSKate Stone
5838ebb9a85SGreg Claytondef get_thread_from_thread_suffix(str):
5848ebb9a85SGreg Clayton    if str:
5858ebb9a85SGreg Clayton        match = g_thread_suffix_regex.match(str)
5868ebb9a85SGreg Clayton        if match:
5878ebb9a85SGreg Clayton            return int(match.group(1), 16)
5888ebb9a85SGreg Clayton    return None
5898ebb9a85SGreg Clayton
590b9c1b51eSKate Stone
591a7a5e5a6SGreg Claytondef cmd_qThreadStopInfo(options, cmd, args):
592a7a5e5a6SGreg Clayton    packet = Packet(args)
593a7a5e5a6SGreg Clayton    tid = packet.get_hex_uint('big')
594525cd59fSSerge Guelton    print("get_thread_stop_info  (tid = 0x%x)" % (tid))
595a7a5e5a6SGreg Clayton
596b9c1b51eSKate Stone
597f51a23fbSGreg Claytondef cmd_stop_reply(options, cmd, args):
598525cd59fSSerge Guelton    print("get_last_stop_info()")
599205d6189SGreg Clayton    return False
6008ebb9a85SGreg Clayton
601b9c1b51eSKate Stone
602f51a23fbSGreg Claytondef rsp_stop_reply(options, cmd, cmd_args, rsp):
6038ebb9a85SGreg Clayton    global g_byte_order
6048ebb9a85SGreg Clayton    packet = Packet(rsp)
6058ebb9a85SGreg Clayton    stop_type = packet.get_char()
6068ebb9a85SGreg Clayton    if stop_type == 'T' or stop_type == 'S':
6078ebb9a85SGreg Clayton        signo = packet.get_hex_uint8()
6088ebb9a85SGreg Clayton        key_value_pairs = packet.get_key_value_pairs()
6098ebb9a85SGreg Clayton        for key_value_pair in key_value_pairs:
6108ebb9a85SGreg Clayton            key = key_value_pair[0]
6118ebb9a85SGreg Clayton            if is_hex_byte(key):
6128ebb9a85SGreg Clayton                reg_num = Packet(key).get_hex_uint8()
613374b6714SGreg Clayton                if reg_num < len(g_register_infos):
614374b6714SGreg Clayton                    reg_info = g_register_infos[reg_num]
615374b6714SGreg Clayton                    key_value_pair[0] = reg_info.name()
616b9c1b51eSKate Stone                    key_value_pair[1] = reg_info.get_value_from_hex_string(
617b9c1b51eSKate Stone                        key_value_pair[1])
618b2273bd3SGreg Clayton            elif key == 'jthreads' or key == 'jstopinfo':
619b2273bd3SGreg Clayton                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
620374b6714SGreg Clayton        key_value_pairs.insert(0, ['signal', signo])
621525cd59fSSerge Guelton        print('stop_reply():')
622374b6714SGreg Clayton        dump_key_value_pairs(key_value_pairs)
6238ebb9a85SGreg Clayton    elif stop_type == 'W':
6248ebb9a85SGreg Clayton        exit_status = packet.get_hex_uint8()
625525cd59fSSerge Guelton        print('stop_reply(): exit (status=%i)' % exit_status)
6268ebb9a85SGreg Clayton    elif stop_type == 'O':
627525cd59fSSerge Guelton        print('stop_reply(): stdout = "%s"' % packet.str)
6288ebb9a85SGreg Clayton
6298ebb9a85SGreg Clayton
630f51a23fbSGreg Claytondef cmd_unknown_packet(options, cmd, args):
6318ebb9a85SGreg Clayton    if args:
632525cd59fSSerge Guelton        print("cmd: %s, args: %s", cmd, args)
6338ebb9a85SGreg Clayton    else:
634525cd59fSSerge Guelton        print("cmd: %s", cmd)
635205d6189SGreg Clayton    return False
636205d6189SGreg Clayton
637b9c1b51eSKate Stone
638205d6189SGreg Claytondef cmd_qSymbol(options, cmd, args):
639205d6189SGreg Clayton    if args == ':':
640525cd59fSSerge Guelton        print('ready to serve symbols')
641205d6189SGreg Clayton    else:
642205d6189SGreg Clayton        packet = Packet(args)
643205d6189SGreg Clayton        symbol_addr = packet.get_hex_uint('big')
644205d6189SGreg Clayton        if symbol_addr is None:
645205d6189SGreg Clayton            if packet.skip_exact_string(':'):
646205d6189SGreg Clayton                symbol_name = packet.get_hex_ascii_str()
647525cd59fSSerge Guelton                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))
648205d6189SGreg Clayton            else:
649525cd59fSSerge Guelton                print('error: bad command format')
650205d6189SGreg Clayton        else:
651205d6189SGreg Clayton            if packet.skip_exact_string(':'):
652205d6189SGreg Clayton                symbol_name = packet.get_hex_ascii_str()
653525cd59fSSerge Guelton                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))
654205d6189SGreg Clayton            else:
655525cd59fSSerge Guelton                print('error: bad command format')
656205d6189SGreg Clayton
657db1550abSGreg Claytondef cmd_QSetWithHexString(options, cmd, args):
658525cd59fSSerge Guelton    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))
659db1550abSGreg Clayton
660db1550abSGreg Claytondef cmd_QSetWithString(options, cmd, args):
661525cd59fSSerge Guelton    print('%s("%s")' % (cmd[:-1], args))
662db1550abSGreg Clayton
663db1550abSGreg Claytondef cmd_QSetWithUnsigned(options, cmd, args):
664525cd59fSSerge Guelton    print('%s(%i)' % (cmd[:-1], int(args)))
665b9c1b51eSKate Stone
666205d6189SGreg Claytondef rsp_qSymbol(options, cmd, cmd_args, rsp):
667205d6189SGreg Clayton    if len(rsp) == 0:
668525cd59fSSerge Guelton        print("Unsupported")
669205d6189SGreg Clayton    else:
670205d6189SGreg Clayton        if rsp == "OK":
671525cd59fSSerge Guelton            print("No more symbols to lookup")
672205d6189SGreg Clayton        else:
673205d6189SGreg Clayton            packet = Packet(rsp)
674205d6189SGreg Clayton            if packet.skip_exact_string("qSymbol:"):
675205d6189SGreg Clayton                symbol_name = packet.get_hex_ascii_str()
676525cd59fSSerge Guelton                print('lookup_symbol("%s")' % (symbol_name))
677205d6189SGreg Clayton            else:
678525cd59fSSerge Guelton                print('error: response string should start with "qSymbol:": respnse is "%s"' % (rsp))
6798ebb9a85SGreg Clayton
680b9c1b51eSKate Stone
681374b6714SGreg Claytondef cmd_qXfer(options, cmd, args):
682374b6714SGreg Clayton    # $qXfer:features:read:target.xml:0,1ffff#14
683525cd59fSSerge Guelton    print("read target special data %s" % (args))
684205d6189SGreg Clayton    return True
685374b6714SGreg Clayton
686b9c1b51eSKate Stone
687374b6714SGreg Claytondef rsp_qXfer(options, cmd, cmd_args, rsp):
688cb6c9f73SPavel Labath    data = cmd_args.split(':')
689374b6714SGreg Clayton    if data[0] == 'features':
690374b6714SGreg Clayton        if data[1] == 'read':
691374b6714SGreg Clayton            filename, extension = os.path.splitext(data[2])
692374b6714SGreg Clayton            if extension == '.xml':
693374b6714SGreg Clayton                response = Packet(rsp)
694374b6714SGreg Clayton                xml_string = response.get_hex_ascii_str()
695141f208eSGreg Clayton                if xml_string:
696374b6714SGreg Clayton                    ch = xml_string[0]
697374b6714SGreg Clayton                    if ch == 'l':
698374b6714SGreg Clayton                        xml_string = xml_string[1:]
699374b6714SGreg Clayton                        xml_root = ET.fromstring(xml_string)
700374b6714SGreg Clayton                        for reg_element in xml_root.findall("./feature/reg"):
701374b6714SGreg Clayton                            if not 'value_regnums' in reg_element.attrib:
702374b6714SGreg Clayton                                reg_info = RegisterInfo([])
703374b6714SGreg Clayton                                if 'name' in reg_element.attrib:
704b9c1b51eSKate Stone                                    reg_info.info[
705b9c1b51eSKate Stone                                        'name'] = reg_element.attrib['name']
706374b6714SGreg Clayton                                else:
707374b6714SGreg Clayton                                    reg_info.info['name'] = 'unspecified'
708374b6714SGreg Clayton                                if 'encoding' in reg_element.attrib:
709b9c1b51eSKate Stone                                    reg_info.info['encoding'] = reg_element.attrib[
710b9c1b51eSKate Stone                                        'encoding']
711374b6714SGreg Clayton                                else:
712374b6714SGreg Clayton                                    reg_info.info['encoding'] = 'uint'
713374b6714SGreg Clayton                                if 'offset' in reg_element.attrib:
714b9c1b51eSKate Stone                                    reg_info.info[
715b9c1b51eSKate Stone                                        'offset'] = reg_element.attrib['offset']
716374b6714SGreg Clayton                                if 'bitsize' in reg_element.attrib:
717b9c1b51eSKate Stone                                    reg_info.info[
718b9c1b51eSKate Stone                                        'bitsize'] = reg_element.attrib['bitsize']
719374b6714SGreg Clayton                                g_register_infos.append(reg_info)
720525cd59fSSerge Guelton                        print('XML for "%s":' % (data[2]))
721205d6189SGreg Clayton                        ET.dump(xml_root)
722374b6714SGreg Clayton
723b9c1b51eSKate Stone
724a7a5e5a6SGreg Claytondef cmd_A(options, cmd, args):
725525cd59fSSerge Guelton    print('launch process:')
726a7a5e5a6SGreg Clayton    packet = Packet(args)
727b9c1b51eSKate Stone    while True:
728a7a5e5a6SGreg Clayton        arg_len = packet.get_number()
729a542e08cSGreg Clayton        if arg_len == -1:
730a542e08cSGreg Clayton            break
731a7a5e5a6SGreg Clayton        if not packet.skip_exact_string(','):
732a7a5e5a6SGreg Clayton            break
733a7a5e5a6SGreg Clayton        arg_idx = packet.get_number()
734a542e08cSGreg Clayton        if arg_idx == -1:
735a542e08cSGreg Clayton            break
736a7a5e5a6SGreg Clayton        if not packet.skip_exact_string(','):
737b9c1b51eSKate Stone            break
738a7a5e5a6SGreg Clayton        arg_value = packet.get_hex_ascii_str(arg_len)
739525cd59fSSerge Guelton        print('argv[%u] = "%s"' % (arg_idx, arg_value))
740a7a5e5a6SGreg Clayton
741b9c1b51eSKate Stone
742a7a5e5a6SGreg Claytondef cmd_qC(options, cmd, args):
743525cd59fSSerge Guelton    print("query_current_thread_id()")
744a7a5e5a6SGreg Clayton
745b9c1b51eSKate Stone
746a7a5e5a6SGreg Claytondef rsp_qC(options, cmd, cmd_args, rsp):
747a7a5e5a6SGreg Clayton    packet = Packet(rsp)
748a7a5e5a6SGreg Clayton    if packet.skip_exact_string("QC"):
749a7a5e5a6SGreg Clayton        tid = packet.get_thread_id()
750525cd59fSSerge Guelton        print("current_thread_id = %#x" % (tid))
751a7a5e5a6SGreg Clayton    else:
752525cd59fSSerge Guelton        print("current_thread_id = old thread ID")
753a7a5e5a6SGreg Clayton
754b9c1b51eSKate Stone
755f51a23fbSGreg Claytondef cmd_query_packet(options, cmd, args):
7568ebb9a85SGreg Clayton    if args:
757525cd59fSSerge Guelton        print("%s%s" % (cmd, args))
7588ebb9a85SGreg Clayton    else:
759525cd59fSSerge Guelton        print("%s" % (cmd))
760205d6189SGreg Clayton    return False
7618ebb9a85SGreg Clayton
762b9c1b51eSKate Stone
7638ebb9a85SGreg Claytondef rsp_ok_error(rsp):
764525cd59fSSerge Guelton    print("rsp: ", rsp)
7658ebb9a85SGreg Clayton
766b9c1b51eSKate Stone
767f51a23fbSGreg Claytondef rsp_ok_means_supported(options, cmd, cmd_args, rsp):
7688ebb9a85SGreg Clayton    if rsp == 'OK':
769525cd59fSSerge Guelton        print("%s%s is supported" % (cmd, cmd_args))
7708ebb9a85SGreg Clayton    elif rsp == '':
771525cd59fSSerge Guelton        print("%s%s is not supported" % (cmd, cmd_args))
7728ebb9a85SGreg Clayton    else:
773525cd59fSSerge Guelton        print("%s%s -> %s" % (cmd, cmd_args, rsp))
7748ebb9a85SGreg Clayton
775b9c1b51eSKate Stone
776f51a23fbSGreg Claytondef rsp_ok_means_success(options, cmd, cmd_args, rsp):
7778ebb9a85SGreg Clayton    if rsp == 'OK':
778525cd59fSSerge Guelton        print("success")
7798ebb9a85SGreg Clayton    elif rsp == '':
780525cd59fSSerge Guelton        print("%s%s is not supported" % (cmd, cmd_args))
7818ebb9a85SGreg Clayton    else:
782525cd59fSSerge Guelton        print("%s%s -> %s" % (cmd, cmd_args, rsp))
7838ebb9a85SGreg Clayton
784b9c1b51eSKate Stone
785374b6714SGreg Claytondef dump_key_value_pairs(key_value_pairs):
786374b6714SGreg Clayton    max_key_len = 0
787374b6714SGreg Clayton    for key_value_pair in key_value_pairs:
788374b6714SGreg Clayton        key_len = len(key_value_pair[0])
789374b6714SGreg Clayton        if max_key_len < key_len:
790374b6714SGreg Clayton            max_key_len = key_len
791374b6714SGreg Clayton    for key_value_pair in key_value_pairs:
792374b6714SGreg Clayton        key = key_value_pair[0]
793374b6714SGreg Clayton        value = key_value_pair[1]
794db1550abSGreg Clayton        unhex_value = get_hex_string_if_all_printable(value)
795db1550abSGreg Clayton        if unhex_value:
796525cd59fSSerge Guelton            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))
797db1550abSGreg Clayton        else:
798525cd59fSSerge Guelton            print("%*s = %s" % (max_key_len, key, value))
799374b6714SGreg Clayton
800b9c1b51eSKate Stone
801f51a23fbSGreg Claytondef rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
8028ebb9a85SGreg Clayton    if rsp:
803525cd59fSSerge Guelton        print('%s response:' % (cmd))
8048ebb9a85SGreg Clayton        packet = Packet(rsp)
8058ebb9a85SGreg Clayton        key_value_pairs = packet.get_key_value_pairs()
806374b6714SGreg Clayton        dump_key_value_pairs(key_value_pairs)
8078ebb9a85SGreg Clayton    else:
808525cd59fSSerge Guelton        print("not supported")
8098ebb9a85SGreg Clayton
810b9c1b51eSKate Stone
811b2273bd3SGreg Claytondef cmd_c(options, cmd, args):
812525cd59fSSerge Guelton    print("continue()")
813205d6189SGreg Clayton    return False
814b2273bd3SGreg Clayton
815b9c1b51eSKate Stone
816b2273bd3SGreg Claytondef cmd_s(options, cmd, args):
817525cd59fSSerge Guelton    print("step()")
818205d6189SGreg Clayton    return False
819b2273bd3SGreg Clayton
820b9c1b51eSKate Stone
821141f208eSGreg Claytondef cmd_qSpeedTest(options, cmd, args):
822525cd59fSSerge Guelton    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))
823141f208eSGreg Clayton
824141f208eSGreg Clayton
825141f208eSGreg Claytondef rsp_qSpeedTest(options, cmd, cmd_args, rsp):
826525cd59fSSerge Guelton    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))
827141f208eSGreg Clayton
828141f208eSGreg Clayton
829f51a23fbSGreg Claytondef cmd_vCont(options, cmd, args):
8308ebb9a85SGreg Clayton    if args == '?':
831525cd59fSSerge Guelton        print("%s: get supported extended continue modes" % (cmd))
8328ebb9a85SGreg Clayton    else:
8338ebb9a85SGreg Clayton        got_other_threads = 0
8348ebb9a85SGreg Clayton        s = ''
835cb6c9f73SPavel Labath        for thread_action in args[1:].split(';'):
836cb6c9f73SPavel Labath            (short_action, thread) = thread_action.split(':', 1)
8378ebb9a85SGreg Clayton            tid = int(thread, 16)
8388ebb9a85SGreg Clayton            if short_action == 'c':
8398ebb9a85SGreg Clayton                action = 'continue'
8408ebb9a85SGreg Clayton            elif short_action == 's':
8418ebb9a85SGreg Clayton                action = 'step'
8428ebb9a85SGreg Clayton            elif short_action[0] == 'C':
8438ebb9a85SGreg Clayton                action = 'continue with signal 0x%s' % (short_action[1:])
8448ebb9a85SGreg Clayton            elif short_action == 'S':
8458ebb9a85SGreg Clayton                action = 'step with signal 0x%s' % (short_action[1:])
8468ebb9a85SGreg Clayton            else:
8478ebb9a85SGreg Clayton                action = short_action
8488ebb9a85SGreg Clayton            if s:
8498ebb9a85SGreg Clayton                s += ', '
8508ebb9a85SGreg Clayton            if tid == -1:
8518ebb9a85SGreg Clayton                got_other_threads = 1
8528ebb9a85SGreg Clayton                s += 'other-threads:'
8538ebb9a85SGreg Clayton            else:
8548ebb9a85SGreg Clayton                s += 'thread 0x%4.4x: %s' % (tid, action)
8558ebb9a85SGreg Clayton        if got_other_threads:
856525cd59fSSerge Guelton            print("extended_continue (%s)" % (s))
8578ebb9a85SGreg Clayton        else:
858525cd59fSSerge Guelton            print("extended_continue (%s, other-threads: suspend)" % (s))
859205d6189SGreg Clayton    return False
8608ebb9a85SGreg Clayton
861b9c1b51eSKate Stone
862f51a23fbSGreg Claytondef rsp_vCont(options, cmd, cmd_args, rsp):
8638ebb9a85SGreg Clayton    if cmd_args == '?':
8648ebb9a85SGreg Clayton        # Skip the leading 'vCont;'
8658ebb9a85SGreg Clayton        rsp = rsp[6:]
866cb6c9f73SPavel Labath        modes = rsp.split(';')
8678ebb9a85SGreg Clayton        s = "%s: supported extended continue modes include: " % (cmd)
8688ebb9a85SGreg Clayton
8698ebb9a85SGreg Clayton        for i, mode in enumerate(modes):
8708ebb9a85SGreg Clayton            if i:
8718ebb9a85SGreg Clayton                s += ', '
8728ebb9a85SGreg Clayton            if mode == 'c':
8738ebb9a85SGreg Clayton                s += 'continue'
8748ebb9a85SGreg Clayton            elif mode == 'C':
8758ebb9a85SGreg Clayton                s += 'continue with signal'
8768ebb9a85SGreg Clayton            elif mode == 's':
8778ebb9a85SGreg Clayton                s += 'step'
8788ebb9a85SGreg Clayton            elif mode == 'S':
8798ebb9a85SGreg Clayton                s += 'step with signal'
880141f208eSGreg Clayton            elif mode == 't':
881141f208eSGreg Clayton                s += 'stop'
882141f208eSGreg Clayton            # else:
883141f208eSGreg Clayton            #     s += 'unrecognized vCont mode: ', str(mode)
884525cd59fSSerge Guelton        print(s)
8858ebb9a85SGreg Clayton    elif rsp:
8868ebb9a85SGreg Clayton        if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
887f51a23fbSGreg Clayton            rsp_stop_reply(options, cmd, cmd_args, rsp)
8888ebb9a85SGreg Clayton            return
8898ebb9a85SGreg Clayton        if rsp[0] == 'O':
890525cd59fSSerge Guelton            print("stdout: %s" % (rsp))
8918ebb9a85SGreg Clayton            return
8928ebb9a85SGreg Clayton    else:
893525cd59fSSerge Guelton        print("not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp))
8948ebb9a85SGreg Clayton
895b9c1b51eSKate Stone
896f51a23fbSGreg Claytondef cmd_vAttach(options, cmd, args):
897*cd89f94aSDominic Chen    (extra_command, args) = args.split(';')
8988ebb9a85SGreg Clayton    if extra_command:
899525cd59fSSerge Guelton        print("%s%s(%s)" % (cmd, extra_command, args))
9008ebb9a85SGreg Clayton    else:
901525cd59fSSerge Guelton        print("attach(pid = %u)" % int(args, 16))
902205d6189SGreg Clayton    return False
903205d6189SGreg Clayton
9048ebb9a85SGreg Clayton
905f51a23fbSGreg Claytondef cmd_qRegisterInfo(options, cmd, args):
906525cd59fSSerge Guelton    print('query_register_info(reg_num=%i)' % (int(args, 16)))
907205d6189SGreg Clayton    return False
9088ebb9a85SGreg Clayton
909b9c1b51eSKate Stone
910f51a23fbSGreg Claytondef rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
9118ebb9a85SGreg Clayton    global g_max_register_info_name_len
912525cd59fSSerge Guelton    print('query_register_info(reg_num=%i):' % (int(cmd_args, 16)), end=' ')
9138ebb9a85SGreg Clayton    if len(rsp) == 3 and rsp[0] == 'E':
9148ebb9a85SGreg Clayton        g_max_register_info_name_len = 0
9158ebb9a85SGreg Clayton        for reg_info in g_register_infos:
9168ebb9a85SGreg Clayton            name_len = len(reg_info.name())
9178ebb9a85SGreg Clayton            if g_max_register_info_name_len < name_len:
9188ebb9a85SGreg Clayton                g_max_register_info_name_len = name_len
919525cd59fSSerge Guelton        print(' DONE')
9208ebb9a85SGreg Clayton    else:
9218ebb9a85SGreg Clayton        packet = Packet(rsp)
9228ebb9a85SGreg Clayton        reg_info = RegisterInfo(packet.get_key_value_pairs())
9238ebb9a85SGreg Clayton        g_register_infos.append(reg_info)
924525cd59fSSerge Guelton        print(reg_info)
925205d6189SGreg Clayton    return False
9268ebb9a85SGreg Clayton
927b9c1b51eSKate Stone
928f51a23fbSGreg Claytondef cmd_qThreadInfo(options, cmd, args):
9298ebb9a85SGreg Clayton    if cmd == 'qfThreadInfo':
9308ebb9a85SGreg Clayton        query_type = 'first'
9318ebb9a85SGreg Clayton    else:
9328ebb9a85SGreg Clayton        query_type = 'subsequent'
933525cd59fSSerge Guelton    print('get_current_thread_list(type=%s)' % (query_type))
934205d6189SGreg Clayton    return False
9358ebb9a85SGreg Clayton
936b9c1b51eSKate Stone
937f51a23fbSGreg Claytondef rsp_qThreadInfo(options, cmd, cmd_args, rsp):
9388ebb9a85SGreg Clayton    packet = Packet(rsp)
9398ebb9a85SGreg Clayton    response_type = packet.get_char()
9408ebb9a85SGreg Clayton    if response_type == 'm':
9418ebb9a85SGreg Clayton        tids = packet.split_hex(';', 'big')
9428ebb9a85SGreg Clayton        for i, tid in enumerate(tids):
9438ebb9a85SGreg Clayton            if i:
944525cd59fSSerge Guelton                print(',', end=' ')
945525cd59fSSerge Guelton            print('0x%x' % (tid), end=' ')
946525cd59fSSerge Guelton        print()
9478ebb9a85SGreg Clayton    elif response_type == 'l':
948525cd59fSSerge Guelton        print('END')
9498ebb9a85SGreg Clayton
950b9c1b51eSKate Stone
951f51a23fbSGreg Claytondef rsp_hex_big_endian(options, cmd, cmd_args, rsp):
952db1550abSGreg Clayton    if rsp == '':
953525cd59fSSerge Guelton        print("%s%s is not supported" % (cmd, cmd_args))
954db1550abSGreg Clayton    else:
9558ebb9a85SGreg Clayton        packet = Packet(rsp)
9568ebb9a85SGreg Clayton        uval = packet.get_hex_uint('big')
957525cd59fSSerge Guelton        print('%s: 0x%x' % (cmd, uval))
9588ebb9a85SGreg Clayton
959b9c1b51eSKate Stone
960205d6189SGreg Claytondef cmd_read_mem_bin(options, cmd, args):
961205d6189SGreg Clayton    # x0x7fff5fc39200,0x200
962205d6189SGreg Clayton    packet = Packet(args)
963db1550abSGreg Clayton    addr = packet.get_hex_uint('big')
964205d6189SGreg Clayton    comma = packet.get_char()
965db1550abSGreg Clayton    size = packet.get_hex_uint('big')
966525cd59fSSerge Guelton    print('binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
967205d6189SGreg Clayton    return False
968205d6189SGreg Clayton
969b9c1b51eSKate Stone
970205d6189SGreg Claytondef rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
971205d6189SGreg Clayton    packet = Packet(cmd_args)
972db1550abSGreg Clayton    addr = packet.get_hex_uint('big')
973205d6189SGreg Clayton    comma = packet.get_char()
974db1550abSGreg Clayton    size = packet.get_hex_uint('big')
975525cd59fSSerge Guelton    print('memory:')
976205d6189SGreg Clayton    if size > 0:
977205d6189SGreg Clayton        dump_hex_memory_buffer(addr, rsp)
978205d6189SGreg Clayton
979b9c1b51eSKate Stone
980f51a23fbSGreg Claytondef cmd_read_memory(options, cmd, args):
9818ebb9a85SGreg Clayton    packet = Packet(args)
9828ebb9a85SGreg Clayton    addr = packet.get_hex_uint('big')
9838ebb9a85SGreg Clayton    comma = packet.get_char()
9848ebb9a85SGreg Clayton    size = packet.get_hex_uint('big')
985525cd59fSSerge Guelton    print('read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
986205d6189SGreg Clayton    return False
9878ebb9a85SGreg Clayton
988b9c1b51eSKate Stone
9898ebb9a85SGreg Claytondef dump_hex_memory_buffer(addr, hex_byte_str):
9908ebb9a85SGreg Clayton    packet = Packet(hex_byte_str)
9918ebb9a85SGreg Clayton    idx = 0
9928ebb9a85SGreg Clayton    ascii = ''
9938ebb9a85SGreg Clayton    uval = packet.get_hex_uint8()
994b9c1b51eSKate Stone    while uval is not None:
9958ebb9a85SGreg Clayton        if ((idx % 16) == 0):
9968ebb9a85SGreg Clayton            if ascii:
997525cd59fSSerge Guelton                print('  ', ascii)
9988ebb9a85SGreg Clayton                ascii = ''
999525cd59fSSerge Guelton            print('0x%x:' % (addr + idx), end=' ')
1000525cd59fSSerge Guelton        print('%2.2x' % (uval), end=' ')
10018ebb9a85SGreg Clayton        if 0x20 <= uval and uval < 0x7f:
10028ebb9a85SGreg Clayton            ascii += '%c' % uval
10038ebb9a85SGreg Clayton        else:
10048ebb9a85SGreg Clayton            ascii += '.'
10058ebb9a85SGreg Clayton        uval = packet.get_hex_uint8()
10068ebb9a85SGreg Clayton        idx = idx + 1
10078ebb9a85SGreg Clayton    if ascii:
1008525cd59fSSerge Guelton        print('  ', ascii)
10098ebb9a85SGreg Clayton        ascii = ''
10108ebb9a85SGreg Clayton
1011b9c1b51eSKate Stone
1012f51a23fbSGreg Claytondef cmd_write_memory(options, cmd, args):
10138ebb9a85SGreg Clayton    packet = Packet(args)
10148ebb9a85SGreg Clayton    addr = packet.get_hex_uint('big')
10158ebb9a85SGreg Clayton    if packet.get_char() != ',':
1016525cd59fSSerge Guelton        print('error: invalid write memory command (missing comma after address)')
10178ebb9a85SGreg Clayton        return
10188ebb9a85SGreg Clayton    size = packet.get_hex_uint('big')
10198ebb9a85SGreg Clayton    if packet.get_char() != ':':
1020525cd59fSSerge Guelton        print('error: invalid write memory command (missing colon after size)')
10218ebb9a85SGreg Clayton        return
1022525cd59fSSerge Guelton    print('write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size))
10238ebb9a85SGreg Clayton    dump_hex_memory_buffer(addr, packet.str)
1024205d6189SGreg Clayton    return False
10258ebb9a85SGreg Clayton
1026b9c1b51eSKate Stone
1027f51a23fbSGreg Claytondef cmd_alloc_memory(options, cmd, args):
10288ebb9a85SGreg Clayton    packet = Packet(args)
10298ebb9a85SGreg Clayton    byte_size = packet.get_hex_uint('big')
10308ebb9a85SGreg Clayton    if packet.get_char() != ',':
1031525cd59fSSerge Guelton        print('error: invalid allocate memory command (missing comma after address)')
10328ebb9a85SGreg Clayton        return
1033525cd59fSSerge Guelton    print('allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str))
1034205d6189SGreg Clayton    return False
10358ebb9a85SGreg Clayton
1036b9c1b51eSKate Stone
1037f51a23fbSGreg Claytondef rsp_alloc_memory(options, cmd, cmd_args, rsp):
10388ebb9a85SGreg Clayton    packet = Packet(rsp)
10398ebb9a85SGreg Clayton    addr = packet.get_hex_uint('big')
1040525cd59fSSerge Guelton    print('addr = 0x%x' % addr)
10418ebb9a85SGreg Clayton
1042b9c1b51eSKate Stone
1043f51a23fbSGreg Claytondef cmd_dealloc_memory(options, cmd, args):
10448ebb9a85SGreg Clayton    packet = Packet(args)
10458ebb9a85SGreg Clayton    addr = packet.get_hex_uint('big')
10468ebb9a85SGreg Clayton    if packet.get_char() != ',':
1047525cd59fSSerge Guelton        print('error: invalid allocate memory command (missing comma after address)')
1048205d6189SGreg Clayton    else:
1049525cd59fSSerge Guelton        print('deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str))
1050205d6189SGreg Clayton    return False
1051b9c1b51eSKate Stone
1052b9c1b51eSKate Stone
1053f51a23fbSGreg Claytondef rsp_memory_bytes(options, cmd, cmd_args, rsp):
10548ebb9a85SGreg Clayton    addr = Packet(cmd_args).get_hex_uint('big')
10558ebb9a85SGreg Clayton    dump_hex_memory_buffer(addr, rsp)
10568ebb9a85SGreg Clayton
1057b9c1b51eSKate Stone
1058f51a23fbSGreg Claytondef get_register_name_equal_value(options, reg_num, hex_value_str):
10598ebb9a85SGreg Clayton    if reg_num < len(g_register_infos):
10608ebb9a85SGreg Clayton        reg_info = g_register_infos[reg_num]
1061f51a23fbSGreg Clayton        value_str = reg_info.get_value_from_hex_string(hex_value_str)
1062f51a23fbSGreg Clayton        s = reg_info.name() + ' = '
1063f51a23fbSGreg Clayton        if options.symbolicator:
1064b9c1b51eSKate Stone            symbolicated_addresses = options.symbolicator.symbolicate(
1065b9c1b51eSKate Stone                int(value_str, 0))
1066f51a23fbSGreg Clayton            if symbolicated_addresses:
1067f51a23fbSGreg Clayton                s += options.colors.magenta()
1068f51a23fbSGreg Clayton                s += '%s' % symbolicated_addresses[0]
1069f51a23fbSGreg Clayton                s += options.colors.reset()
1070f51a23fbSGreg Clayton                return s
1071f51a23fbSGreg Clayton        s += value_str
1072f51a23fbSGreg Clayton        return s
10738ebb9a85SGreg Clayton    else:
10748ebb9a85SGreg Clayton        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
10758ebb9a85SGreg Clayton        return 'reg(%u) = 0x%x' % (reg_num, reg_value)
10768ebb9a85SGreg Clayton
1077b9c1b51eSKate Stone
1078f51a23fbSGreg Claytondef cmd_read_one_reg(options, cmd, args):
10798ebb9a85SGreg Clayton    packet = Packet(args)
10808ebb9a85SGreg Clayton    reg_num = packet.get_hex_uint('big')
10818ebb9a85SGreg Clayton    tid = get_thread_from_thread_suffix(packet.str)
10828ebb9a85SGreg Clayton    name = None
10838ebb9a85SGreg Clayton    if reg_num < len(g_register_infos):
10848ebb9a85SGreg Clayton        name = g_register_infos[reg_num].name()
10858ebb9a85SGreg Clayton    if packet.str:
10868ebb9a85SGreg Clayton        packet.get_char()  # skip ;
10878ebb9a85SGreg Clayton        thread_info = packet.get_key_value_pairs()
10888ebb9a85SGreg Clayton        tid = int(thread_info[0][1], 16)
10898ebb9a85SGreg Clayton    s = 'read_register (reg_num=%u' % reg_num
10908ebb9a85SGreg Clayton    if name:
10918ebb9a85SGreg Clayton        s += ' (%s)' % (name)
1092b9c1b51eSKate Stone    if tid is not None:
10938ebb9a85SGreg Clayton        s += ', tid = 0x%4.4x' % (tid)
10948ebb9a85SGreg Clayton    s += ')'
1095525cd59fSSerge Guelton    print(s)
1096205d6189SGreg Clayton    return False
10978ebb9a85SGreg Clayton
1098b9c1b51eSKate Stone
1099f51a23fbSGreg Claytondef rsp_read_one_reg(options, cmd, cmd_args, rsp):
11008ebb9a85SGreg Clayton    packet = Packet(cmd_args)
11018ebb9a85SGreg Clayton    reg_num = packet.get_hex_uint('big')
1102525cd59fSSerge Guelton    print(get_register_name_equal_value(options, reg_num, rsp))
11038ebb9a85SGreg Clayton
1104b9c1b51eSKate Stone
1105f51a23fbSGreg Claytondef cmd_write_one_reg(options, cmd, args):
11068ebb9a85SGreg Clayton    packet = Packet(args)
11078ebb9a85SGreg Clayton    reg_num = packet.get_hex_uint('big')
11088ebb9a85SGreg Clayton    if packet.get_char() != '=':
1109525cd59fSSerge Guelton        print('error: invalid register write packet')
11108ebb9a85SGreg Clayton    else:
11118ebb9a85SGreg Clayton        name = None
11128ebb9a85SGreg Clayton        hex_value_str = packet.get_hex_chars()
11138ebb9a85SGreg Clayton        tid = get_thread_from_thread_suffix(packet.str)
11148ebb9a85SGreg Clayton        s = 'write_register (reg_num=%u' % reg_num
11158ebb9a85SGreg Clayton        if name:
11168ebb9a85SGreg Clayton            s += ' (%s)' % (name)
11178ebb9a85SGreg Clayton        s += ', value = '
1118f51a23fbSGreg Clayton        s += get_register_name_equal_value(options, reg_num, hex_value_str)
1119b9c1b51eSKate Stone        if tid is not None:
11208ebb9a85SGreg Clayton            s += ', tid = 0x%4.4x' % (tid)
11218ebb9a85SGreg Clayton        s += ')'
1122525cd59fSSerge Guelton        print(s)
1123205d6189SGreg Clayton    return False
11248ebb9a85SGreg Clayton
1125b9c1b51eSKate Stone
11268ebb9a85SGreg Claytondef dump_all_regs(packet):
11278ebb9a85SGreg Clayton    for reg_info in g_register_infos:
11288ebb9a85SGreg Clayton        nibble_size = reg_info.bit_size() / 4
11298ebb9a85SGreg Clayton        hex_value_str = packet.get_hex_chars(nibble_size)
1130b9c1b51eSKate Stone        if hex_value_str is not None:
11318ebb9a85SGreg Clayton            value = reg_info.get_value_from_hex_string(hex_value_str)
1132525cd59fSSerge Guelton            print('%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value))
11338ebb9a85SGreg Clayton        else:
11348ebb9a85SGreg Clayton            return
11358ebb9a85SGreg Clayton
1136b9c1b51eSKate Stone
11378ebb9a85SGreg Claytondef cmd_read_all_regs(cmd, cmd_args):
11388ebb9a85SGreg Clayton    packet = Packet(cmd_args)
11398ebb9a85SGreg Clayton    packet.get_char()  # toss the 'g' command character
11408ebb9a85SGreg Clayton    tid = get_thread_from_thread_suffix(packet.str)
1141b9c1b51eSKate Stone    if tid is not None:
1142525cd59fSSerge Guelton        print('read_all_register(thread = 0x%4.4x)' % tid)
11438ebb9a85SGreg Clayton    else:
1144525cd59fSSerge Guelton        print('read_all_register()')
1145205d6189SGreg Clayton    return False
11468ebb9a85SGreg Clayton
1147b9c1b51eSKate Stone
1148f51a23fbSGreg Claytondef rsp_read_all_regs(options, cmd, cmd_args, rsp):
11498ebb9a85SGreg Clayton    packet = Packet(rsp)
11508ebb9a85SGreg Clayton    dump_all_regs(packet)
11518ebb9a85SGreg Clayton
1152b9c1b51eSKate Stone
1153f51a23fbSGreg Claytondef cmd_write_all_regs(options, cmd, args):
11548ebb9a85SGreg Clayton    packet = Packet(args)
1155525cd59fSSerge Guelton    print('write_all_registers()')
11568ebb9a85SGreg Clayton    dump_all_regs(packet)
1157205d6189SGreg Clayton    return False
11588ebb9a85SGreg Clayton
11598ebb9a85SGreg Claytong_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]
11608ebb9a85SGreg Clayton
1161b9c1b51eSKate Stone
1162f51a23fbSGreg Claytondef cmd_bp(options, cmd, args):
11638ebb9a85SGreg Clayton    if cmd == 'Z':
11648ebb9a85SGreg Clayton        s = 'set_'
11658ebb9a85SGreg Clayton    else:
11668ebb9a85SGreg Clayton        s = 'clear_'
11678ebb9a85SGreg Clayton    packet = Packet(args)
11688ebb9a85SGreg Clayton    bp_type = packet.get_hex_uint('big')
11698ebb9a85SGreg Clayton    packet.get_char()  # Skip ,
11708ebb9a85SGreg Clayton    bp_addr = packet.get_hex_uint('big')
11718ebb9a85SGreg Clayton    packet.get_char()  # Skip ,
11728ebb9a85SGreg Clayton    bp_size = packet.get_hex_uint('big')
11738ebb9a85SGreg Clayton    s += g_bp_types[bp_type]
11748ebb9a85SGreg Clayton    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
1175525cd59fSSerge Guelton    print(s)
1176205d6189SGreg Clayton    return False
11778ebb9a85SGreg Clayton
1178b9c1b51eSKate Stone
1179f51a23fbSGreg Claytondef cmd_mem_rgn_info(options, cmd, args):
11808ebb9a85SGreg Clayton    packet = Packet(args)
11818ebb9a85SGreg Clayton    packet.get_char()  # skip ':' character
11828ebb9a85SGreg Clayton    addr = packet.get_hex_uint('big')
1183525cd59fSSerge Guelton    print('get_memory_region_info (addr=0x%x)' % (addr))
1184205d6189SGreg Clayton    return False
11858ebb9a85SGreg Clayton
1186b9c1b51eSKate Stone
1187f51a23fbSGreg Claytondef cmd_kill(options, cmd, args):
1188525cd59fSSerge Guelton    print('kill_process()')
1189205d6189SGreg Clayton    return False
11908ebb9a85SGreg Clayton
1191b9c1b51eSKate Stone
11928c2afa0cSGreg Claytondef cmd_jThreadsInfo(options, cmd, args):
1193525cd59fSSerge Guelton    print('jThreadsInfo()')
11948c2afa0cSGreg Clayton    return False
11958c2afa0cSGreg Clayton
1196b9c1b51eSKate Stone
11978c2afa0cSGreg Claytondef cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
1198525cd59fSSerge Guelton    print('jGetLoadedDynamicLibrariesInfos()')
11998c2afa0cSGreg Clayton    return False
12008c2afa0cSGreg Clayton
1201b9c1b51eSKate Stone
12028c2afa0cSGreg Claytondef decode_packet(s, start_index=0):
12038c2afa0cSGreg Clayton    # print '\ndecode_packet("%s")' % (s[start_index:])
12048c2afa0cSGreg Clayton    index = s.find('}', start_index)
12058c2afa0cSGreg Clayton    have_escapes = index != -1
12068c2afa0cSGreg Clayton    if have_escapes:
12078c2afa0cSGreg Clayton        normal_s = s[start_index:index]
12088c2afa0cSGreg Clayton    else:
12098c2afa0cSGreg Clayton        normal_s = s[start_index:]
12108c2afa0cSGreg Clayton    # print 'normal_s = "%s"' % (normal_s)
12118c2afa0cSGreg Clayton    if have_escapes:
12128c2afa0cSGreg Clayton        escape_char = '%c' % (ord(s[index + 1]) ^ 0x20)
12138c2afa0cSGreg Clayton        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
12148c2afa0cSGreg Clayton        return normal_s + escape_char + decode_packet(s, index + 2)
12158c2afa0cSGreg Clayton    else:
12168c2afa0cSGreg Clayton        return normal_s
12178c2afa0cSGreg Clayton
1218b9c1b51eSKate Stone
12198c2afa0cSGreg Claytondef rsp_json(options, cmd, cmd_args, rsp):
1220525cd59fSSerge Guelton    print('%s() reply:' % (cmd))
1221*cd89f94aSDominic Chen    if not rsp:
1222*cd89f94aSDominic Chen        return
1223*cd89f94aSDominic Chen    try:
12248c2afa0cSGreg Clayton        json_tree = json.loads(rsp)
1225525cd59fSSerge Guelton        print(json.dumps(json_tree, indent=4, separators=(',', ': ')))
1226*cd89f94aSDominic Chen    except json.JSONDecodeError:
1227*cd89f94aSDominic Chen        return
12288c2afa0cSGreg Clayton
12298c2afa0cSGreg Claytondef rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
12308c2afa0cSGreg Clayton    if cmd_args:
12318c2afa0cSGreg Clayton        rsp_json(options, cmd, cmd_args, rsp)
12328c2afa0cSGreg Clayton    else:
12338c2afa0cSGreg Clayton        rsp_ok_means_supported(options, cmd, cmd_args, rsp)
12348c2afa0cSGreg Clayton
12358ebb9a85SGreg Claytongdb_remote_commands = {
12368ebb9a85SGreg Clayton    '\\?': {'cmd': cmd_stop_reply, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
1237a7a5e5a6SGreg Clayton    'qThreadStopInfo': {'cmd': cmd_qThreadStopInfo, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
12388ebb9a85SGreg Clayton    'QStartNoAckMode': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if no ack mode is supported"},
12398ebb9a85SGreg Clayton    'QThreadSuffixSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if thread suffix is supported"},
12408ebb9a85SGreg Clayton    'QListThreadsInStopReply': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if threads in stop reply packets are supported"},
1241db1550abSGreg Clayton    'QSetDetachOnError:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should detach on error"},
1242db1550abSGreg Clayton    'QSetDisableASLR:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should disable ASLR"},
1243a7a5e5a6SGreg Clayton    'qLaunchSuccess': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_success, 'name': "check on launch success for the A packet"},
1244a7a5e5a6SGreg Clayton    'A': {'cmd': cmd_A, 'rsp': rsp_ok_means_success, 'name': "launch process"},
1245db1550abSGreg Clayton    'QLaunchArch:': {'cmd': cmd_QSetWithString, 'rsp': rsp_ok_means_supported, 'name': "set the arch to launch in case the file contains multiple architectures"},
1246a7a5e5a6SGreg Clayton    'qVAttachOrWaitSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "set the launch architecture"},
12478ebb9a85SGreg Clayton    'qHostInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get host information"},
1248a7a5e5a6SGreg Clayton    'qC': {'cmd': cmd_qC, 'rsp': rsp_qC, 'name': "return the current thread ID"},
12498ebb9a85SGreg Clayton    'vCont': {'cmd': cmd_vCont, 'rsp': rsp_vCont, 'name': "extended continue command"},
1250141f208eSGreg Clayton    'qSpeedTest': {'cmd':cmd_qSpeedTest, 'rsp': rsp_qSpeedTest, 'name': 'speed test packdet'},
12518ebb9a85SGreg Clayton    'vAttach': {'cmd': cmd_vAttach, 'rsp': rsp_stop_reply, 'name': "attach to process"},
1252b2273bd3SGreg Clayton    'c': {'cmd': cmd_c, 'rsp': rsp_stop_reply, 'name': "continue"},
1253b2273bd3SGreg Clayton    's': {'cmd': cmd_s, 'rsp': rsp_stop_reply, 'name': "step"},
12548ebb9a85SGreg Clayton    'qRegisterInfo': {'cmd': cmd_qRegisterInfo, 'rsp': rsp_qRegisterInfo, 'name': "query register info"},
12558ebb9a85SGreg Clayton    'qfThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
12568ebb9a85SGreg Clayton    'qsThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
12578ebb9a85SGreg Clayton    'qShlibInfoAddr': {'cmd': cmd_query_packet, 'rsp': rsp_hex_big_endian, 'name': "get shared library info address"},
12588ebb9a85SGreg Clayton    'qMemoryRegionInfo': {'cmd': cmd_mem_rgn_info, 'rsp': rsp_dump_key_value_pairs, 'name': "get memory region information"},
125925f82aaeSGreg Clayton    'qProcessInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get process info"},
126025f82aaeSGreg Clayton    'qSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query supported"},
1261374b6714SGreg Clayton    'qXfer:': {'cmd': cmd_qXfer, 'rsp': rsp_qXfer, 'name': "qXfer"},
1262205d6189SGreg Clayton    'qSymbol:': {'cmd': cmd_qSymbol, 'rsp': rsp_qSymbol, 'name': "qSymbol"},
1263db1550abSGreg Clayton    'QSetSTDIN:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDIN prior to launching with A packet"},
1264db1550abSGreg Clayton    'QSetSTDOUT:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDOUT prior to launching with A packet"},
1265db1550abSGreg Clayton    'QSetSTDERR:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDERR prior to launching with A packet"},
1266db1550abSGreg Clayton    'QEnvironment:' : {'cmd' : cmd_QSetWithString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
1267db1550abSGreg Clayton    'QEnvironmentHexEncoded:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
1268205d6189SGreg Clayton    'x': {'cmd': cmd_read_mem_bin, 'rsp': rsp_mem_bin_bytes, 'name': "read memory binary"},
1269205d6189SGreg Clayton    'X': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory binary"},
12708ebb9a85SGreg Clayton    'm': {'cmd': cmd_read_memory, 'rsp': rsp_memory_bytes, 'name': "read memory"},
12718ebb9a85SGreg Clayton    'M': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory"},
12728ebb9a85SGreg Clayton    '_M': {'cmd': cmd_alloc_memory, 'rsp': rsp_alloc_memory, 'name': "allocate memory"},
12738ebb9a85SGreg Clayton    '_m': {'cmd': cmd_dealloc_memory, 'rsp': rsp_ok_means_success, 'name': "deallocate memory"},
12748ebb9a85SGreg Clayton    'p': {'cmd': cmd_read_one_reg, 'rsp': rsp_read_one_reg, 'name': "read single register"},
12758ebb9a85SGreg Clayton    'P': {'cmd': cmd_write_one_reg, 'rsp': rsp_ok_means_success, 'name': "write single register"},
12768ebb9a85SGreg Clayton    'g': {'cmd': cmd_read_all_regs, 'rsp': rsp_read_all_regs, 'name': "read all registers"},
12778ebb9a85SGreg Clayton    'G': {'cmd': cmd_write_all_regs, 'rsp': rsp_ok_means_success, 'name': "write all registers"},
12788ebb9a85SGreg Clayton    'z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "clear breakpoint or watchpoint"},
12798ebb9a85SGreg Clayton    'Z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "set breakpoint or watchpoint"},
12808ebb9a85SGreg Clayton    'k': {'cmd': cmd_kill, 'rsp': rsp_stop_reply, 'name': "kill process"},
12818c2afa0cSGreg Clayton    'jThreadsInfo': {'cmd': cmd_jThreadsInfo, 'rsp': rsp_json, 'name': "JSON get all threads info"},
12828c2afa0cSGreg Clayton    'jGetLoadedDynamicLibrariesInfos:': {'cmd': cmd_jGetLoadedDynamicLibrariesInfos, 'rsp': rsp_jGetLoadedDynamicLibrariesInfos, 'name': 'JSON get loaded dynamic libraries'},
12838ebb9a85SGreg Clayton}
128425f82aaeSGreg Clayton
1285b9c1b51eSKate Stone
128625f82aaeSGreg Claytondef calculate_mean_and_standard_deviation(floats):
128725f82aaeSGreg Clayton    sum = 0.0
128825f82aaeSGreg Clayton    count = len(floats)
1289b2273bd3SGreg Clayton    if count == 0:
1290b2273bd3SGreg Clayton        return (0.0, 0.0)
129125f82aaeSGreg Clayton    for f in floats:
129225f82aaeSGreg Clayton        sum += f
129325f82aaeSGreg Clayton    mean = sum / count
129425f82aaeSGreg Clayton    accum = 0.0
129525f82aaeSGreg Clayton    for f in floats:
129625f82aaeSGreg Clayton        delta = f - mean
129725f82aaeSGreg Clayton        accum += delta * delta
129825f82aaeSGreg Clayton
1299b9c1b51eSKate Stone    std_dev = math.sqrt(accum / (count - 1))
130025f82aaeSGreg Clayton    return (mean, std_dev)
130125f82aaeSGreg Clayton
1302b9c1b51eSKate Stone
1303b2273bd3SGreg Claytondef parse_gdb_log_file(path, options):
1304b2273bd3SGreg Clayton    f = open(path)
1305205d6189SGreg Clayton    parse_gdb_log(f, options)
1306b2273bd3SGreg Clayton    f.close()
1307b2273bd3SGreg Clayton
1308b9c1b51eSKate Stone
1309141f208eSGreg Claytondef round_up(n, incr):
1310141f208eSGreg Clayton    return float(((int(n) + incr) / incr) * incr)
1311141f208eSGreg Clayton
1312141f208eSGreg Clayton
1313141f208eSGreg Claytondef plot_latencies(sec_times):
1314141f208eSGreg Clayton    # import numpy as np
1315141f208eSGreg Clayton    import matplotlib.pyplot as plt
1316141f208eSGreg Clayton
1317141f208eSGreg Clayton    for (i, name) in enumerate(sec_times.keys()):
1318141f208eSGreg Clayton        times = sec_times[name]
1319141f208eSGreg Clayton        if len(times) <= 1:
1320141f208eSGreg Clayton            continue
1321141f208eSGreg Clayton        plt.subplot(2, 1, 1)
1322141f208eSGreg Clayton        plt.title('Packet "%s" Times' % (name))
1323141f208eSGreg Clayton        plt.xlabel('Packet')
1324141f208eSGreg Clayton        units = 'ms'
1325141f208eSGreg Clayton        adj_times = []
1326141f208eSGreg Clayton        max_time = 0.0
1327141f208eSGreg Clayton        for time in times:
1328141f208eSGreg Clayton            time = time * 1000.0
1329141f208eSGreg Clayton            adj_times.append(time)
1330141f208eSGreg Clayton            if time > max_time:
1331141f208eSGreg Clayton                max_time = time
1332141f208eSGreg Clayton        if max_time < 1.0:
1333141f208eSGreg Clayton            units = 'us'
1334141f208eSGreg Clayton            max_time = 0.0
1335141f208eSGreg Clayton            for i in range(len(adj_times)):
1336141f208eSGreg Clayton                adj_times[i] *= 1000.0
1337141f208eSGreg Clayton                if adj_times[i] > max_time:
1338141f208eSGreg Clayton                    max_time = adj_times[i]
1339141f208eSGreg Clayton        plt.ylabel('Time (%s)' % (units))
1340141f208eSGreg Clayton        max_y = None
1341141f208eSGreg Clayton        for i in [5.0, 10.0, 25.0, 50.0]:
1342141f208eSGreg Clayton            if max_time < i:
1343141f208eSGreg Clayton                max_y = round_up(max_time, i)
1344141f208eSGreg Clayton                break
1345141f208eSGreg Clayton        if max_y is None:
1346141f208eSGreg Clayton            max_y = round_up(max_time, 100.0)
1347141f208eSGreg Clayton        plt.ylim(0.0, max_y)
1348141f208eSGreg Clayton        plt.plot(adj_times, 'o-')
1349141f208eSGreg Clayton        plt.show()
1350141f208eSGreg Clayton
1351141f208eSGreg Clayton
1352b2273bd3SGreg Claytondef parse_gdb_log(file, options):
1353e2841639SGreg Clayton    '''Parse a GDB log file that was generated by enabling logging with:
1354e2841639SGreg Clayton    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
1355d93c4a33SBruce Mitchener    This log file will contain timestamps and this function will then normalize
1356e2841639SGreg Clayton    those packets to be relative to the first value timestamp that is found and
1357e2841639SGreg Clayton    show delta times between log lines and also keep track of how long it takes
1358e2841639SGreg Clayton    for GDB remote commands to make a send/receive round trip. This can be
1359e2841639SGreg Clayton    handy when trying to figure out why some operation in the debugger is taking
1360e2841639SGreg Clayton    a long time during a preset set of debugger commands.'''
1361e2841639SGreg Clayton
1362e2841639SGreg Clayton    tricky_commands = ['qRegisterInfo']
1363e2841639SGreg Clayton    timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
1364e2841639SGreg Clayton    packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]')
1365b9c1b51eSKate Stone    packet_transmit_name_regex = re.compile(
1366b9c1b51eSKate Stone        '(?P<direction>send|read) packet: (?P<packet>.*)')
1367db1550abSGreg Clayton    packet_contents_name_regex = re.compile('\$([^#]*)#[0-9a-fA-F]{2}')
13688c2afa0cSGreg Clayton    packet_checksum_regex = re.compile('.*#[0-9a-fA-F]{2}$')
1369b9c1b51eSKate Stone    packet_names_regex_str = '(' + \
1370b9c1b51eSKate Stone        '|'.join(gdb_remote_commands.keys()) + ')(.*)'
1371b9c1b51eSKate Stone    packet_names_regex = re.compile(packet_names_regex_str)
13728ebb9a85SGreg Clayton
1373e2841639SGreg Clayton    base_time = 0.0
1374e2841639SGreg Clayton    last_time = 0.0
1375141f208eSGreg Clayton    min_time = 100000000.0
1376e2841639SGreg Clayton    packet_total_times = {}
1377141f208eSGreg Clayton    all_packet_times = []
1378141f208eSGreg Clayton    packet_times = {}
1379141f208eSGreg Clayton    packet_counts = {}
1380e2841639SGreg Clayton    lines = file.read().splitlines()
13818ebb9a85SGreg Clayton    last_command = None
13828ebb9a85SGreg Clayton    last_command_args = None
13838ebb9a85SGreg Clayton    last_command_packet = None
1384205d6189SGreg Clayton    hide_next_response = False
13858c2afa0cSGreg Clayton    num_lines = len(lines)
13868c2afa0cSGreg Clayton    skip_count = 0
13878c2afa0cSGreg Clayton    for (line_index, line) in enumerate(lines):
13888c2afa0cSGreg Clayton        # See if we need to skip any lines
13898c2afa0cSGreg Clayton        if skip_count > 0:
13908c2afa0cSGreg Clayton            skip_count -= 1
13918c2afa0cSGreg Clayton            continue
13928ebb9a85SGreg Clayton        m = packet_transmit_name_regex.search(line)
1393f51a23fbSGreg Clayton        is_command = False
139425f82aaeSGreg Clayton        direction = None
13958ebb9a85SGreg Clayton        if m:
13968ebb9a85SGreg Clayton            direction = m.group('direction')
13978ebb9a85SGreg Clayton            is_command = direction == 'send'
13988ebb9a85SGreg Clayton            packet = m.group('packet')
1399f51a23fbSGreg Clayton            sys.stdout.write(options.colors.green())
1400205d6189SGreg Clayton            if not options.quiet and not hide_next_response:
1401525cd59fSSerge Guelton                print('#  ', line)
1402f51a23fbSGreg Clayton            sys.stdout.write(options.colors.reset())
14038ebb9a85SGreg Clayton
14048ebb9a85SGreg Clayton            # print 'direction = "%s", packet = "%s"' % (direction, packet)
14058ebb9a85SGreg Clayton
14068c2afa0cSGreg Clayton            if packet[0] == '+':
1407205d6189SGreg Clayton                if is_command:
1408525cd59fSSerge Guelton                    print('-->', end=' ')
1409205d6189SGreg Clayton                else:
1410525cd59fSSerge Guelton                    print('<--', end=' ')
1411b9c1b51eSKate Stone                if not options.quiet:
1412525cd59fSSerge Guelton                    print('ACK')
141325f82aaeSGreg Clayton                continue
14148ebb9a85SGreg Clayton            elif packet[0] == '-':
14158c2afa0cSGreg Clayton                if is_command:
1416525cd59fSSerge Guelton                    print('-->', end=' ')
14178c2afa0cSGreg Clayton                else:
1418525cd59fSSerge Guelton                    print('<--', end=' ')
1419b9c1b51eSKate Stone                if not options.quiet:
1420525cd59fSSerge Guelton                    print('NACK')
142125f82aaeSGreg Clayton                continue
14228ebb9a85SGreg Clayton            elif packet[0] == '$':
14238ebb9a85SGreg Clayton                m = packet_contents_name_regex.match(packet)
14248c2afa0cSGreg Clayton                if not m and packet[0] == '$':
14258c2afa0cSGreg Clayton                    multiline_packet = packet
14268c2afa0cSGreg Clayton                    idx = line_index + 1
14278c2afa0cSGreg Clayton                    while idx < num_lines:
14288c2afa0cSGreg Clayton                        if not options.quiet and not hide_next_response:
1429525cd59fSSerge Guelton                            print('#  ', lines[idx])
14308c2afa0cSGreg Clayton                        multiline_packet += lines[idx]
14318c2afa0cSGreg Clayton                        m = packet_contents_name_regex.match(multiline_packet)
14328ebb9a85SGreg Clayton                        if m:
14338c2afa0cSGreg Clayton                            packet = multiline_packet
14348c2afa0cSGreg Clayton                            skip_count = idx - line_index
14358c2afa0cSGreg Clayton                            break
14368c2afa0cSGreg Clayton                        else:
14378c2afa0cSGreg Clayton                            idx += 1
14388c2afa0cSGreg Clayton                if m:
14398c2afa0cSGreg Clayton                    if is_command:
1440525cd59fSSerge Guelton                        print('-->', end=' ')
14418c2afa0cSGreg Clayton                    else:
1442525cd59fSSerge Guelton                        print('<--', end=' ')
14438c2afa0cSGreg Clayton                    contents = decode_packet(m.group(1))
14448ebb9a85SGreg Clayton                    if is_command:
1445205d6189SGreg Clayton                        hide_next_response = False
14468ebb9a85SGreg Clayton                        m = packet_names_regex.match(contents)
14478ebb9a85SGreg Clayton                        if m:
14488ebb9a85SGreg Clayton                            last_command = m.group(1)
1449a7a5e5a6SGreg Clayton                            if last_command == '?':
1450a7a5e5a6SGreg Clayton                                last_command = '\\?'
1451f51a23fbSGreg Clayton                            packet_name = last_command
14528ebb9a85SGreg Clayton                            last_command_args = m.group(2)
14538ebb9a85SGreg Clayton                            last_command_packet = contents
1454b9c1b51eSKate Stone                            hide_next_response = gdb_remote_commands[last_command][
1455b9c1b51eSKate Stone                                'cmd'](options, last_command, last_command_args)
14568ebb9a85SGreg Clayton                        else:
145725f82aaeSGreg Clayton                            packet_match = packet_name_regex.match(contents)
1458f51a23fbSGreg Clayton                            if packet_match:
1459f51a23fbSGreg Clayton                                packet_name = packet_match.group(1)
1460f51a23fbSGreg Clayton                                for tricky_cmd in tricky_commands:
1461f51a23fbSGreg Clayton                                    if packet_name.find(tricky_cmd) == 0:
1462f51a23fbSGreg Clayton                                        packet_name = tricky_cmd
1463f51a23fbSGreg Clayton                            else:
1464f51a23fbSGreg Clayton                                packet_name = contents
14658ebb9a85SGreg Clayton                            last_command = None
14668ebb9a85SGreg Clayton                            last_command_args = None
14678ebb9a85SGreg Clayton                            last_command_packet = None
14688ebb9a85SGreg Clayton                    elif last_command:
1469b9c1b51eSKate Stone                        gdb_remote_commands[last_command]['rsp'](
1470b9c1b51eSKate Stone                            options, last_command, last_command_args, contents)
14718ebb9a85SGreg Clayton                else:
1472525cd59fSSerge Guelton                    print('error: invalid packet: "', packet, '"')
14738ebb9a85SGreg Clayton            else:
1474525cd59fSSerge Guelton                print('???')
14758ebb9a85SGreg Clayton        else:
1476525cd59fSSerge Guelton            print('## ', line)
1477e2841639SGreg Clayton        match = timestamp_regex.match(line)
1478e2841639SGreg Clayton        if match:
1479e2841639SGreg Clayton            curr_time = float(match.group(2))
148025f82aaeSGreg Clayton            if last_time and not is_command:
148125f82aaeSGreg Clayton                delta = curr_time - last_time
1482141f208eSGreg Clayton                all_packet_times.append(delta)
1483e2841639SGreg Clayton            delta = 0.0
1484e2841639SGreg Clayton            if base_time:
1485e2841639SGreg Clayton                delta = curr_time - last_time
1486e2841639SGreg Clayton            else:
1487e2841639SGreg Clayton                base_time = curr_time
1488f51a23fbSGreg Clayton
1489141f208eSGreg Clayton            if not is_command:
1490141f208eSGreg Clayton                if line.find('read packet: $') >= 0 and packet_name:
1491e2841639SGreg Clayton                    if packet_name in packet_total_times:
1492e2841639SGreg Clayton                        packet_total_times[packet_name] += delta
1493141f208eSGreg Clayton                        packet_counts[packet_name] += 1
1494e2841639SGreg Clayton                    else:
1495e2841639SGreg Clayton                        packet_total_times[packet_name] = delta
1496141f208eSGreg Clayton                        packet_counts[packet_name] = 1
1497141f208eSGreg Clayton                    if packet_name not in packet_times:
1498141f208eSGreg Clayton                        packet_times[packet_name] = []
1499141f208eSGreg Clayton                    packet_times[packet_name].append(delta)
1500e2841639SGreg Clayton                    packet_name = None
1501141f208eSGreg Clayton                if min_time > delta:
1502141f208eSGreg Clayton                    min_time = delta
1503e2841639SGreg Clayton
1504e2841639SGreg Clayton            if not options or not options.quiet:
1505525cd59fSSerge Guelton                print('%s%.6f %+.6f%s' % (match.group(1),
1506141f208eSGreg Clayton                                          curr_time - base_time,
1507141f208eSGreg Clayton                                          delta,
1508525cd59fSSerge Guelton                                          match.group(3)))
1509e2841639SGreg Clayton            last_time = curr_time
15108ebb9a85SGreg Clayton        # else:
15118ebb9a85SGreg Clayton        #     print line
1512141f208eSGreg Clayton    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)
1513205d6189SGreg Clayton    if average and std_dev:
1514525cd59fSSerge Guelton        print('%u packets with average packet time of %f and standard deviation of %f' % (len(all_packet_times), average, std_dev))
1515e2841639SGreg Clayton    if packet_total_times:
1516e2841639SGreg Clayton        total_packet_time = 0.0
1517d95752f2SJim Ingham        total_packet_count = 0
1518e2841639SGreg Clayton        for key, vvv in packet_total_times.items():
1519e2841639SGreg Clayton            # print '  key = (%s) "%s"' % (type(key), key)
1520e2841639SGreg Clayton            # print 'value = (%s) %s' % (type(vvv), vvv)
1521e2841639SGreg Clayton            # if type(vvv) == 'float':
1522e2841639SGreg Clayton            total_packet_time += vvv
1523141f208eSGreg Clayton        for key, vvv in packet_counts.items():
1524d95752f2SJim Ingham            total_packet_count += vvv
1525d95752f2SJim Ingham
1526525cd59fSSerge Guelton        print('#------------------------------------------------------------')
1527525cd59fSSerge Guelton        print('# Packet timing summary:')
1528525cd59fSSerge Guelton        print('# Totals: time = %6f, count = %6d' % (total_packet_time,
1529525cd59fSSerge Guelton                                                     total_packet_count))
1530525cd59fSSerge Guelton        print('# Min packet time: time = %6f' % (min_time))
1531525cd59fSSerge Guelton        print('#------------------------------------------------------------')
1532525cd59fSSerge Guelton        print('# Packet                   Time (sec)  Percent Count  Latency')
1533525cd59fSSerge Guelton        print('#------------------------- ----------- ------- ------ -------')
1534d95752f2SJim Ingham        if options and options.sort_count:
1535b9c1b51eSKate Stone            res = sorted(
1536141f208eSGreg Clayton                packet_counts,
1537141f208eSGreg Clayton                key=packet_counts.__getitem__,
1538b9c1b51eSKate Stone                reverse=True)
1539d95752f2SJim Ingham        else:
1540b9c1b51eSKate Stone            res = sorted(
1541b9c1b51eSKate Stone                packet_total_times,
1542b9c1b51eSKate Stone                key=packet_total_times.__getitem__,
1543b9c1b51eSKate Stone                reverse=True)
1544d95752f2SJim Ingham
1545e2841639SGreg Clayton        if last_time > 0.0:
1546e2841639SGreg Clayton            for item in res:
1547e2841639SGreg Clayton                packet_total_time = packet_total_times[item]
1548b9c1b51eSKate Stone                packet_percent = (
1549b9c1b51eSKate Stone                    packet_total_time / total_packet_time) * 100.0
1550141f208eSGreg Clayton                packet_count = packet_counts[item]
1551525cd59fSSerge Guelton                print("  %24s %11.6f  %5.2f%% %6d %9.6f" % (
1552141f208eSGreg Clayton                        item, packet_total_time, packet_percent, packet_count,
1553525cd59fSSerge Guelton                        float(packet_total_time) / float(packet_count)))
1554*cd89f94aSDominic Chen        if options and options.plot:
1555141f208eSGreg Clayton            plot_latencies(packet_times)
1556e2841639SGreg Clayton
1557e2841639SGreg Claytonif __name__ == '__main__':
15588ebb9a85SGreg Clayton    usage = "usage: gdbremote [options]"
15598ebb9a85SGreg Clayton    description = '''The command disassembles a GDB remote packet log.'''
1560b9c1b51eSKate Stone    parser = optparse.OptionParser(
1561b9c1b51eSKate Stone        description=description,
1562b9c1b51eSKate Stone        prog='gdbremote',
1563b9c1b51eSKate Stone        usage=usage)
1564b9c1b51eSKate Stone    parser.add_option(
1565b9c1b51eSKate Stone        '-v',
1566b9c1b51eSKate Stone        '--verbose',
1567b9c1b51eSKate Stone        action='store_true',
1568b9c1b51eSKate Stone        dest='verbose',
1569b9c1b51eSKate Stone        help='display verbose debug info',
1570b9c1b51eSKate Stone        default=False)
1571b9c1b51eSKate Stone    parser.add_option(
1572b9c1b51eSKate Stone        '-q',
1573b9c1b51eSKate Stone        '--quiet',
1574b9c1b51eSKate Stone        action='store_true',
1575b9c1b51eSKate Stone        dest='quiet',
1576b9c1b51eSKate Stone        help='display verbose debug info',
1577b9c1b51eSKate Stone        default=False)
1578b9c1b51eSKate Stone    parser.add_option(
1579b9c1b51eSKate Stone        '-C',
1580b9c1b51eSKate Stone        '--color',
1581b9c1b51eSKate Stone        action='store_true',
1582b9c1b51eSKate Stone        dest='color',
1583b9c1b51eSKate Stone        help='add terminal colors',
1584b9c1b51eSKate Stone        default=False)
1585b9c1b51eSKate Stone    parser.add_option(
1586b9c1b51eSKate Stone        '-c',
1587b9c1b51eSKate Stone        '--sort-by-count',
1588b9c1b51eSKate Stone        action='store_true',
1589b9c1b51eSKate Stone        dest='sort_count',
1590b9c1b51eSKate Stone        help='display verbose debug info',
1591b9c1b51eSKate Stone        default=False)
1592b9c1b51eSKate Stone    parser.add_option(
1593b9c1b51eSKate Stone        '--crashlog',
1594b9c1b51eSKate Stone        type='string',
1595b9c1b51eSKate Stone        dest='crashlog',
1596b9c1b51eSKate Stone        help='symbolicate using a darwin crash log file',
1597b9c1b51eSKate Stone        default=False)
15988ebb9a85SGreg Clayton    try:
15998ebb9a85SGreg Clayton        (options, args) = parser.parse_args(sys.argv[1:])
16008ebb9a85SGreg Clayton    except:
1601525cd59fSSerge Guelton        print('error: argument error')
16028ebb9a85SGreg Clayton        sys.exit(1)
16038ebb9a85SGreg Clayton
1604f51a23fbSGreg Clayton    options.colors = TerminalColors(options.color)
1605f51a23fbSGreg Clayton    options.symbolicator = None
1606f51a23fbSGreg Clayton    if options.crashlog:
1607f51a23fbSGreg Clayton        import lldb
1608f51a23fbSGreg Clayton        lldb.debugger = lldb.SBDebugger.Create()
1609f51a23fbSGreg Clayton        import lldb.macosx.crashlog
1610f51a23fbSGreg Clayton        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
1611525cd59fSSerge Guelton        print('%s' % (options.symbolicator))
16128ebb9a85SGreg Clayton
1613e2841639SGreg Clayton    # This script is being run from the command line, create a debugger in case we are
1614e2841639SGreg Clayton    # going to use any debugger functions in our function.
1615b2273bd3SGreg Clayton    if len(args):
16168ebb9a85SGreg Clayton        for file in args:
1617525cd59fSSerge Guelton            print('#----------------------------------------------------------------------')
1618525cd59fSSerge Guelton            print("# GDB remote log file: '%s'" % file)
1619525cd59fSSerge Guelton            print('#----------------------------------------------------------------------')
16208ebb9a85SGreg Clayton            parse_gdb_log_file(file, options)
1621f51a23fbSGreg Clayton        if options.symbolicator:
1622525cd59fSSerge Guelton            print('%s' % (options.symbolicator))
1623b2273bd3SGreg Clayton    else:
1624b2273bd3SGreg Clayton        parse_gdb_log(sys.stdin, options)
1625f51a23fbSGreg Clayton
16261441ffe6SDave Leedef __lldb_init_module(debugger, internal_dict):
1627e2841639SGreg Clayton    # This initializer is being run from LLDB in the embedded command interpreter
1628e2841639SGreg Clayton    # Add any commands contained in this module to LLDB
16291441ffe6SDave Lee    debugger.HandleCommand(
1630b9c1b51eSKate Stone        'command script add -f gdbremote.start_gdb_log start_gdb_log')
16311441ffe6SDave Lee    debugger.HandleCommand(
1632b9c1b51eSKate Stone        'command script add -f gdbremote.stop_gdb_log stop_gdb_log')
1633525cd59fSSerge Guelton    print('The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information')
1634