xref: /openbsd-src/gnu/llvm/lldb/examples/python/gdbremote.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick#!/usr/bin/env python
2061da546Spatrick
3061da546Spatrick#----------------------------------------------------------------------
4061da546Spatrick# This module will enable GDB remote packet logging when the
5061da546Spatrick# 'start_gdb_log' command is called with a filename to log to. When the
6061da546Spatrick# 'stop_gdb_log' command is called, it will disable the logging and
7061da546Spatrick# print out statistics about how long commands took to execute and also
8061da546Spatrick# will primnt ou
9061da546Spatrick# Be sure to add the python path that points to the LLDB shared library.
10061da546Spatrick#
11061da546Spatrick# To use this in the embedded python interpreter using "lldb" just
12061da546Spatrick# import it with the full path using the "command script import"
13061da546Spatrick# command. This can be done from the LLDB command line:
14061da546Spatrick#   (lldb) command script import /path/to/gdbremote.py
15061da546Spatrick# Or it can be added to your ~/.lldbinit file so this module is always
16061da546Spatrick# available.
17061da546Spatrick#----------------------------------------------------------------------
18061da546Spatrick
19061da546Spatrickimport binascii
20061da546Spatrickimport subprocess
21061da546Spatrickimport json
22061da546Spatrickimport math
23061da546Spatrickimport optparse
24061da546Spatrickimport os
25061da546Spatrickimport re
26061da546Spatrickimport shlex
27061da546Spatrickimport string
28061da546Spatrickimport sys
29061da546Spatrickimport tempfile
30061da546Spatrickimport xml.etree.ElementTree as ET
31061da546Spatrick
32061da546Spatrick#----------------------------------------------------------------------
33061da546Spatrick# Global variables
34061da546Spatrick#----------------------------------------------------------------------
35061da546Spatrickg_log_file = ''
36061da546Spatrickg_byte_order = 'little'
37061da546Spatrickg_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)')
38061da546Spatrickg_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)')
39061da546Spatrick
40061da546Spatrick
41061da546Spatrickclass TerminalColors:
42061da546Spatrick    '''Simple terminal colors class'''
43061da546Spatrick
44061da546Spatrick    def __init__(self, enabled=True):
45061da546Spatrick        # TODO: discover terminal type from "file" and disable if
46061da546Spatrick        # it can't handle the color codes
47061da546Spatrick        self.enabled = enabled
48061da546Spatrick
49061da546Spatrick    def reset(self):
50061da546Spatrick        '''Reset all terminal colors and formatting.'''
51061da546Spatrick        if self.enabled:
52061da546Spatrick            return "\x1b[0m"
53061da546Spatrick        return ''
54061da546Spatrick
55061da546Spatrick    def bold(self, on=True):
56061da546Spatrick        '''Enable or disable bold depending on the "on" parameter.'''
57061da546Spatrick        if self.enabled:
58061da546Spatrick            if on:
59061da546Spatrick                return "\x1b[1m"
60061da546Spatrick            else:
61061da546Spatrick                return "\x1b[22m"
62061da546Spatrick        return ''
63061da546Spatrick
64061da546Spatrick    def italics(self, on=True):
65061da546Spatrick        '''Enable or disable italics depending on the "on" parameter.'''
66061da546Spatrick        if self.enabled:
67061da546Spatrick            if on:
68061da546Spatrick                return "\x1b[3m"
69061da546Spatrick            else:
70061da546Spatrick                return "\x1b[23m"
71061da546Spatrick        return ''
72061da546Spatrick
73061da546Spatrick    def underline(self, on=True):
74061da546Spatrick        '''Enable or disable underline depending on the "on" parameter.'''
75061da546Spatrick        if self.enabled:
76061da546Spatrick            if on:
77061da546Spatrick                return "\x1b[4m"
78061da546Spatrick            else:
79061da546Spatrick                return "\x1b[24m"
80061da546Spatrick        return ''
81061da546Spatrick
82061da546Spatrick    def inverse(self, on=True):
83061da546Spatrick        '''Enable or disable inverse depending on the "on" parameter.'''
84061da546Spatrick        if self.enabled:
85061da546Spatrick            if on:
86061da546Spatrick                return "\x1b[7m"
87061da546Spatrick            else:
88061da546Spatrick                return "\x1b[27m"
89061da546Spatrick        return ''
90061da546Spatrick
91061da546Spatrick    def strike(self, on=True):
92061da546Spatrick        '''Enable or disable strike through depending on the "on" parameter.'''
93061da546Spatrick        if self.enabled:
94061da546Spatrick            if on:
95061da546Spatrick                return "\x1b[9m"
96061da546Spatrick            else:
97061da546Spatrick                return "\x1b[29m"
98061da546Spatrick        return ''
99061da546Spatrick
100061da546Spatrick    def black(self, fg=True):
101061da546Spatrick        '''Set the foreground or background color to black.
102061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
103061da546Spatrick        if self.enabled:
104061da546Spatrick            if fg:
105061da546Spatrick                return "\x1b[30m"
106061da546Spatrick            else:
107061da546Spatrick                return "\x1b[40m"
108061da546Spatrick        return ''
109061da546Spatrick
110061da546Spatrick    def red(self, fg=True):
111061da546Spatrick        '''Set the foreground or background color to red.
112061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
113061da546Spatrick        if self.enabled:
114061da546Spatrick            if fg:
115061da546Spatrick                return "\x1b[31m"
116061da546Spatrick            else:
117061da546Spatrick                return "\x1b[41m"
118061da546Spatrick        return ''
119061da546Spatrick
120061da546Spatrick    def green(self, fg=True):
121061da546Spatrick        '''Set the foreground or background color to green.
122061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
123061da546Spatrick        if self.enabled:
124061da546Spatrick            if fg:
125061da546Spatrick                return "\x1b[32m"
126061da546Spatrick            else:
127061da546Spatrick                return "\x1b[42m"
128061da546Spatrick        return ''
129061da546Spatrick
130061da546Spatrick    def yellow(self, fg=True):
131061da546Spatrick        '''Set the foreground or background color to yellow.
132061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
133061da546Spatrick        if self.enabled:
134061da546Spatrick            if fg:
135061da546Spatrick                return "\x1b[33m"
136061da546Spatrick            else:
137061da546Spatrick                return "\x1b[43m"
138061da546Spatrick        return ''
139061da546Spatrick
140061da546Spatrick    def blue(self, fg=True):
141061da546Spatrick        '''Set the foreground or background color to blue.
142061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
143061da546Spatrick        if self.enabled:
144061da546Spatrick            if fg:
145061da546Spatrick                return "\x1b[34m"
146061da546Spatrick            else:
147061da546Spatrick                return "\x1b[44m"
148061da546Spatrick        return ''
149061da546Spatrick
150061da546Spatrick    def magenta(self, fg=True):
151061da546Spatrick        '''Set the foreground or background color to magenta.
152061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
153061da546Spatrick        if self.enabled:
154061da546Spatrick            if fg:
155061da546Spatrick                return "\x1b[35m"
156061da546Spatrick            else:
157061da546Spatrick                return "\x1b[45m"
158061da546Spatrick        return ''
159061da546Spatrick
160061da546Spatrick    def cyan(self, fg=True):
161061da546Spatrick        '''Set the foreground or background color to cyan.
162061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
163061da546Spatrick        if self.enabled:
164061da546Spatrick            if fg:
165061da546Spatrick                return "\x1b[36m"
166061da546Spatrick            else:
167061da546Spatrick                return "\x1b[46m"
168061da546Spatrick        return ''
169061da546Spatrick
170061da546Spatrick    def white(self, fg=True):
171061da546Spatrick        '''Set the foreground or background color to white.
172061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
173061da546Spatrick        if self.enabled:
174061da546Spatrick            if fg:
175061da546Spatrick                return "\x1b[37m"
176061da546Spatrick            else:
177061da546Spatrick                return "\x1b[47m"
178061da546Spatrick        return ''
179061da546Spatrick
180061da546Spatrick    def default(self, fg=True):
181061da546Spatrick        '''Set the foreground or background color to the default.
182061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
183061da546Spatrick        if self.enabled:
184061da546Spatrick            if fg:
185061da546Spatrick                return "\x1b[39m"
186061da546Spatrick            else:
187061da546Spatrick                return "\x1b[49m"
188061da546Spatrick        return ''
189061da546Spatrick
190061da546Spatrick
191061da546Spatrickdef start_gdb_log(debugger, command, result, dict):
192061da546Spatrick    '''Start logging GDB remote packets by enabling logging with timestamps and
193061da546Spatrick    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
194061da546Spatrick    in order to dump out the commands.'''
195061da546Spatrick    global g_log_file
196061da546Spatrick    command_args = shlex.split(command)
197061da546Spatrick    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
198061da546Spatrick    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
199061da546Spatrick    be aggregated and displayed.'''
200061da546Spatrick    parser = optparse.OptionParser(
201061da546Spatrick        description=description,
202061da546Spatrick        prog='start_gdb_log',
203061da546Spatrick        usage=usage)
204061da546Spatrick    parser.add_option(
205061da546Spatrick        '-v',
206061da546Spatrick        '--verbose',
207061da546Spatrick        action='store_true',
208061da546Spatrick        dest='verbose',
209061da546Spatrick        help='display verbose debug info',
210061da546Spatrick        default=False)
211061da546Spatrick    try:
212061da546Spatrick        (options, args) = parser.parse_args(command_args)
213061da546Spatrick    except:
214061da546Spatrick        return
215061da546Spatrick
216061da546Spatrick    if g_log_file:
217061da546Spatrick        result.PutCString(
218061da546Spatrick            'error: logging is already in progress with file "%s"' %
219061da546Spatrick            g_log_file)
220061da546Spatrick    else:
221061da546Spatrick        args_len = len(args)
222061da546Spatrick        if args_len == 0:
223061da546Spatrick            g_log_file = tempfile.mktemp()
224061da546Spatrick        elif len(args) == 1:
225061da546Spatrick            g_log_file = args[0]
226061da546Spatrick
227061da546Spatrick        if g_log_file:
228061da546Spatrick            debugger.HandleCommand(
229061da546Spatrick                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
230061da546Spatrick                g_log_file)
231061da546Spatrick            result.PutCString(
232061da546Spatrick                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
233061da546Spatrick                g_log_file)
234061da546Spatrick            return
235061da546Spatrick
236061da546Spatrick        result.PutCString('error: invalid log file path')
237061da546Spatrick    result.PutCString(usage)
238061da546Spatrick
239061da546Spatrick
240061da546Spatrickdef stop_gdb_log(debugger, command, result, dict):
241061da546Spatrick    '''Stop logging GDB remote packets to the file that was specified in a call
242061da546Spatrick    to "start_gdb_log" and normalize the timestamps to be relative to the first
243061da546Spatrick    timestamp in the log file. Also print out statistics for how long each
244061da546Spatrick    command took to allow performance bottlenecks to be determined.'''
245061da546Spatrick    global g_log_file
246061da546Spatrick    # Any commands whose names might be followed by more valid C identifier
247061da546Spatrick    # characters must be listed here
248061da546Spatrick    command_args = shlex.split(command)
249061da546Spatrick    usage = "usage: stop_gdb_log [options]"
250061da546Spatrick    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.'''
251061da546Spatrick    parser = optparse.OptionParser(
252061da546Spatrick        description=description,
253061da546Spatrick        prog='stop_gdb_log',
254061da546Spatrick        usage=usage)
255061da546Spatrick    parser.add_option(
256061da546Spatrick        '-v',
257061da546Spatrick        '--verbose',
258061da546Spatrick        action='store_true',
259061da546Spatrick        dest='verbose',
260061da546Spatrick        help='display verbose debug info',
261061da546Spatrick        default=False)
262061da546Spatrick    parser.add_option(
263*f6aab3d8Srobert        '--plot',
264*f6aab3d8Srobert        action='store_true',
265*f6aab3d8Srobert        dest='plot',
266*f6aab3d8Srobert        help='plot packet latencies by packet type',
267*f6aab3d8Srobert        default=False)
268*f6aab3d8Srobert    parser.add_option(
269061da546Spatrick        '-q',
270061da546Spatrick        '--quiet',
271061da546Spatrick        action='store_true',
272061da546Spatrick        dest='quiet',
273061da546Spatrick        help='display verbose debug info',
274061da546Spatrick        default=False)
275061da546Spatrick    parser.add_option(
276061da546Spatrick        '-C',
277061da546Spatrick        '--color',
278061da546Spatrick        action='store_true',
279061da546Spatrick        dest='color',
280061da546Spatrick        help='add terminal colors',
281061da546Spatrick        default=False)
282061da546Spatrick    parser.add_option(
283061da546Spatrick        '-c',
284061da546Spatrick        '--sort-by-count',
285061da546Spatrick        action='store_true',
286061da546Spatrick        dest='sort_count',
287061da546Spatrick        help='display verbose debug info',
288061da546Spatrick        default=False)
289061da546Spatrick    parser.add_option(
290061da546Spatrick        '-s',
291061da546Spatrick        '--symbolicate',
292061da546Spatrick        action='store_true',
293061da546Spatrick        dest='symbolicate',
294061da546Spatrick        help='symbolicate addresses in log using current "lldb.target"',
295061da546Spatrick        default=False)
296061da546Spatrick    try:
297061da546Spatrick        (options, args) = parser.parse_args(command_args)
298061da546Spatrick    except:
299061da546Spatrick        return
300061da546Spatrick    options.colors = TerminalColors(options.color)
301061da546Spatrick    options.symbolicator = None
302061da546Spatrick    if options.symbolicate:
303061da546Spatrick        if lldb.target:
304061da546Spatrick            import lldb.utils.symbolication
305061da546Spatrick            options.symbolicator = lldb.utils.symbolication.Symbolicator()
306061da546Spatrick            options.symbolicator.target = lldb.target
307061da546Spatrick        else:
308061da546Spatrick            print("error: can't symbolicate without a target")
309061da546Spatrick
310061da546Spatrick    if not g_log_file:
311061da546Spatrick        result.PutCString(
312061da546Spatrick            'error: logging must have been previously enabled with a call to "stop_gdb_log"')
313061da546Spatrick    elif os.path.exists(g_log_file):
314061da546Spatrick        if len(args) == 0:
315061da546Spatrick            debugger.HandleCommand('log disable gdb-remote packets')
316061da546Spatrick            result.PutCString(
317061da546Spatrick                "GDB packet logging disabled. Logged packets are in '%s'" %
318061da546Spatrick                g_log_file)
319061da546Spatrick            parse_gdb_log_file(g_log_file, options)
320061da546Spatrick        else:
321061da546Spatrick            result.PutCString(usage)
322061da546Spatrick    else:
323061da546Spatrick        print('error: the GDB packet log file "%s" does not exist' % g_log_file)
324061da546Spatrick
325061da546Spatrick
326061da546Spatrickdef is_hex_byte(str):
327061da546Spatrick    if len(str) == 2:
328061da546Spatrick        return str[0] in string.hexdigits and str[1] in string.hexdigits
329061da546Spatrick    return False
330061da546Spatrick
331061da546Spatrickdef get_hex_string_if_all_printable(str):
332061da546Spatrick    try:
333dda28197Spatrick        s = binascii.unhexlify(str).decode()
334061da546Spatrick        if all(c in string.printable for c in s):
335061da546Spatrick            return s
336dda28197Spatrick    except (TypeError, binascii.Error, UnicodeDecodeError):
337061da546Spatrick        pass
338061da546Spatrick    return None
339061da546Spatrick
340061da546Spatrick# global register info list
341061da546Spatrickg_register_infos = list()
342061da546Spatrickg_max_register_info_name_len = 0
343061da546Spatrick
344061da546Spatrick
345061da546Spatrickclass RegisterInfo:
346061da546Spatrick    """Class that represents register information"""
347061da546Spatrick
348061da546Spatrick    def __init__(self, kvp):
349061da546Spatrick        self.info = dict()
350061da546Spatrick        for kv in kvp:
351061da546Spatrick            key = kv[0]
352061da546Spatrick            value = kv[1]
353061da546Spatrick            self.info[key] = value
354061da546Spatrick
355061da546Spatrick    def name(self):
356061da546Spatrick        '''Get the name of the register.'''
357061da546Spatrick        if self.info and 'name' in self.info:
358061da546Spatrick            return self.info['name']
359061da546Spatrick        return None
360061da546Spatrick
361061da546Spatrick    def bit_size(self):
362061da546Spatrick        '''Get the size in bits of the register.'''
363061da546Spatrick        if self.info and 'bitsize' in self.info:
364061da546Spatrick            return int(self.info['bitsize'])
365061da546Spatrick        return 0
366061da546Spatrick
367061da546Spatrick    def byte_size(self):
368061da546Spatrick        '''Get the size in bytes of the register.'''
369061da546Spatrick        return self.bit_size() / 8
370061da546Spatrick
371061da546Spatrick    def get_value_from_hex_string(self, hex_str):
372061da546Spatrick        '''Dump the register value given a native byte order encoded hex ASCII byte string.'''
373061da546Spatrick        encoding = self.info['encoding']
374061da546Spatrick        bit_size = self.bit_size()
375061da546Spatrick        packet = Packet(hex_str)
376061da546Spatrick        if encoding == 'uint':
377061da546Spatrick            uval = packet.get_hex_uint(g_byte_order)
378061da546Spatrick            if bit_size == 8:
379061da546Spatrick                return '0x%2.2x' % (uval)
380061da546Spatrick            elif bit_size == 16:
381061da546Spatrick                return '0x%4.4x' % (uval)
382061da546Spatrick            elif bit_size == 32:
383061da546Spatrick                return '0x%8.8x' % (uval)
384061da546Spatrick            elif bit_size == 64:
385061da546Spatrick                return '0x%16.16x' % (uval)
386061da546Spatrick        bytes = list()
387061da546Spatrick        uval = packet.get_hex_uint8()
388061da546Spatrick        while uval is not None:
389061da546Spatrick            bytes.append(uval)
390061da546Spatrick            uval = packet.get_hex_uint8()
391061da546Spatrick        value_str = '0x'
392061da546Spatrick        if g_byte_order == 'little':
393061da546Spatrick            bytes.reverse()
394061da546Spatrick        for byte in bytes:
395061da546Spatrick            value_str += '%2.2x' % byte
396061da546Spatrick        return '%s' % (value_str)
397061da546Spatrick
398061da546Spatrick    def __str__(self):
399061da546Spatrick        '''Dump the register info key/value pairs'''
400061da546Spatrick        s = ''
401061da546Spatrick        for key in self.info.keys():
402061da546Spatrick            if s:
403061da546Spatrick                s += ', '
404061da546Spatrick            s += "%s=%s " % (key, self.info[key])
405061da546Spatrick        return s
406061da546Spatrick
407061da546Spatrick
408061da546Spatrickclass Packet:
409061da546Spatrick    """Class that represents a packet that contains string data"""
410061da546Spatrick
411061da546Spatrick    def __init__(self, packet_str):
412061da546Spatrick        self.str = packet_str
413061da546Spatrick
414061da546Spatrick    def peek_char(self):
415061da546Spatrick        ch = 0
416061da546Spatrick        if self.str:
417061da546Spatrick            ch = self.str[0]
418061da546Spatrick        return ch
419061da546Spatrick
420061da546Spatrick    def get_char(self):
421061da546Spatrick        ch = 0
422061da546Spatrick        if self.str:
423061da546Spatrick            ch = self.str[0]
424061da546Spatrick            self.str = self.str[1:]
425061da546Spatrick        return ch
426061da546Spatrick
427061da546Spatrick    def skip_exact_string(self, s):
428061da546Spatrick        if self.str and self.str.startswith(s):
429061da546Spatrick            self.str = self.str[len(s):]
430061da546Spatrick            return True
431061da546Spatrick        else:
432061da546Spatrick            return False
433061da546Spatrick
434061da546Spatrick    def get_thread_id(self, fail_value=-1):
435061da546Spatrick        match = g_number_regex.match(self.str)
436061da546Spatrick        if match:
437061da546Spatrick            number_str = match.group(1)
438061da546Spatrick            self.str = self.str[len(number_str):]
439061da546Spatrick            return int(number_str, 0)
440061da546Spatrick        else:
441061da546Spatrick            return fail_value
442061da546Spatrick
443061da546Spatrick    def get_hex_uint8(self):
444061da546Spatrick        if self.str and len(self.str) >= 2 and self.str[
445061da546Spatrick                0] in string.hexdigits and self.str[1] in string.hexdigits:
446061da546Spatrick            uval = int(self.str[0:2], 16)
447061da546Spatrick            self.str = self.str[2:]
448061da546Spatrick            return uval
449061da546Spatrick        return None
450061da546Spatrick
451061da546Spatrick    def get_hex_uint16(self, byte_order):
452061da546Spatrick        uval = 0
453061da546Spatrick        if byte_order == 'big':
454061da546Spatrick            uval |= self.get_hex_uint8() << 8
455061da546Spatrick            uval |= self.get_hex_uint8()
456061da546Spatrick        else:
457061da546Spatrick            uval |= self.get_hex_uint8()
458061da546Spatrick            uval |= self.get_hex_uint8() << 8
459061da546Spatrick        return uval
460061da546Spatrick
461061da546Spatrick    def get_hex_uint32(self, byte_order):
462061da546Spatrick        uval = 0
463061da546Spatrick        if byte_order == 'big':
464061da546Spatrick            uval |= self.get_hex_uint8() << 24
465061da546Spatrick            uval |= self.get_hex_uint8() << 16
466061da546Spatrick            uval |= self.get_hex_uint8() << 8
467061da546Spatrick            uval |= self.get_hex_uint8()
468061da546Spatrick        else:
469061da546Spatrick            uval |= self.get_hex_uint8()
470061da546Spatrick            uval |= self.get_hex_uint8() << 8
471061da546Spatrick            uval |= self.get_hex_uint8() << 16
472061da546Spatrick            uval |= self.get_hex_uint8() << 24
473061da546Spatrick        return uval
474061da546Spatrick
475061da546Spatrick    def get_hex_uint64(self, byte_order):
476061da546Spatrick        uval = 0
477061da546Spatrick        if byte_order == 'big':
478061da546Spatrick            uval |= self.get_hex_uint8() << 56
479061da546Spatrick            uval |= self.get_hex_uint8() << 48
480061da546Spatrick            uval |= self.get_hex_uint8() << 40
481061da546Spatrick            uval |= self.get_hex_uint8() << 32
482061da546Spatrick            uval |= self.get_hex_uint8() << 24
483061da546Spatrick            uval |= self.get_hex_uint8() << 16
484061da546Spatrick            uval |= self.get_hex_uint8() << 8
485061da546Spatrick            uval |= self.get_hex_uint8()
486061da546Spatrick        else:
487061da546Spatrick            uval |= self.get_hex_uint8()
488061da546Spatrick            uval |= self.get_hex_uint8() << 8
489061da546Spatrick            uval |= self.get_hex_uint8() << 16
490061da546Spatrick            uval |= self.get_hex_uint8() << 24
491061da546Spatrick            uval |= self.get_hex_uint8() << 32
492061da546Spatrick            uval |= self.get_hex_uint8() << 40
493061da546Spatrick            uval |= self.get_hex_uint8() << 48
494061da546Spatrick            uval |= self.get_hex_uint8() << 56
495061da546Spatrick        return uval
496061da546Spatrick
497061da546Spatrick    def get_number(self, fail_value=-1):
498061da546Spatrick        '''Get a number from the packet. The number must be in big endian format and should be parsed
499061da546Spatrick        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
500061da546Spatrick        [1-9] means decimal, etc)'''
501061da546Spatrick        match = g_number_regex.match(self.str)
502061da546Spatrick        if match:
503061da546Spatrick            number_str = match.group(1)
504061da546Spatrick            self.str = self.str[len(number_str):]
505061da546Spatrick            return int(number_str, 0)
506061da546Spatrick        else:
507061da546Spatrick            return fail_value
508061da546Spatrick
509061da546Spatrick    def get_hex_ascii_str(self, n=0):
510061da546Spatrick        hex_chars = self.get_hex_chars(n)
511061da546Spatrick        if hex_chars:
512061da546Spatrick            return binascii.unhexlify(hex_chars)
513061da546Spatrick        else:
514061da546Spatrick            return None
515061da546Spatrick
516061da546Spatrick    def get_hex_chars(self, n=0):
517061da546Spatrick        str_len = len(self.str)
518061da546Spatrick        if n == 0:
519061da546Spatrick            # n was zero, so we need to determine all hex chars and
520061da546Spatrick            # stop when we hit the end of the string of a non-hex character
521061da546Spatrick            while n < str_len and self.str[n] in string.hexdigits:
522061da546Spatrick                n = n + 1
523061da546Spatrick        else:
524061da546Spatrick            if n > str_len:
525061da546Spatrick                return None  # Not enough chars
526061da546Spatrick            # Verify all chars are hex if a length was specified
527061da546Spatrick            for i in range(n):
528061da546Spatrick                if self.str[i] not in string.hexdigits:
529061da546Spatrick                    return None  # Not all hex digits
530061da546Spatrick        if n == 0:
531061da546Spatrick            return None
532061da546Spatrick        hex_str = self.str[0:n]
533061da546Spatrick        self.str = self.str[n:]
534061da546Spatrick        return hex_str
535061da546Spatrick
536061da546Spatrick    def get_hex_uint(self, byte_order, n=0):
537061da546Spatrick        if byte_order == 'big':
538061da546Spatrick            hex_str = self.get_hex_chars(n)
539061da546Spatrick            if hex_str is None:
540061da546Spatrick                return None
541061da546Spatrick            return int(hex_str, 16)
542061da546Spatrick        else:
543061da546Spatrick            uval = self.get_hex_uint8()
544061da546Spatrick            if uval is None:
545061da546Spatrick                return None
546061da546Spatrick            uval_result = 0
547061da546Spatrick            shift = 0
548061da546Spatrick            while uval is not None:
549061da546Spatrick                uval_result |= (uval << shift)
550061da546Spatrick                shift += 8
551061da546Spatrick                uval = self.get_hex_uint8()
552061da546Spatrick            return uval_result
553061da546Spatrick
554061da546Spatrick    def get_key_value_pairs(self):
555061da546Spatrick        kvp = list()
556061da546Spatrick        if ';' in self.str:
557dda28197Spatrick            key_value_pairs = self.str.split(';')
558061da546Spatrick            for key_value_pair in key_value_pairs:
559061da546Spatrick                if len(key_value_pair):
560dda28197Spatrick                    kvp.append(key_value_pair.split(':', 1))
561061da546Spatrick        return kvp
562061da546Spatrick
563061da546Spatrick    def split(self, ch):
564*f6aab3d8Srobert        return self.str.split(ch)
565061da546Spatrick
566061da546Spatrick    def split_hex(self, ch, byte_order):
567061da546Spatrick        hex_values = list()
568*f6aab3d8Srobert        strings = self.str.split(ch)
569061da546Spatrick        for str in strings:
570061da546Spatrick            hex_values.append(Packet(str).get_hex_uint(byte_order))
571061da546Spatrick        return hex_values
572061da546Spatrick
573061da546Spatrick    def __str__(self):
574061da546Spatrick        return self.str
575061da546Spatrick
576061da546Spatrick    def __len__(self):
577061da546Spatrick        return len(self.str)
578061da546Spatrick
579061da546Spatrickg_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);')
580061da546Spatrick
581061da546Spatrick
582061da546Spatrickdef get_thread_from_thread_suffix(str):
583061da546Spatrick    if str:
584061da546Spatrick        match = g_thread_suffix_regex.match(str)
585061da546Spatrick        if match:
586061da546Spatrick            return int(match.group(1), 16)
587061da546Spatrick    return None
588061da546Spatrick
589061da546Spatrick
590061da546Spatrickdef cmd_qThreadStopInfo(options, cmd, args):
591061da546Spatrick    packet = Packet(args)
592061da546Spatrick    tid = packet.get_hex_uint('big')
593061da546Spatrick    print("get_thread_stop_info  (tid = 0x%x)" % (tid))
594061da546Spatrick
595061da546Spatrick
596061da546Spatrickdef cmd_stop_reply(options, cmd, args):
597061da546Spatrick    print("get_last_stop_info()")
598061da546Spatrick    return False
599061da546Spatrick
600061da546Spatrick
601061da546Spatrickdef rsp_stop_reply(options, cmd, cmd_args, rsp):
602061da546Spatrick    global g_byte_order
603061da546Spatrick    packet = Packet(rsp)
604061da546Spatrick    stop_type = packet.get_char()
605061da546Spatrick    if stop_type == 'T' or stop_type == 'S':
606061da546Spatrick        signo = packet.get_hex_uint8()
607061da546Spatrick        key_value_pairs = packet.get_key_value_pairs()
608061da546Spatrick        for key_value_pair in key_value_pairs:
609061da546Spatrick            key = key_value_pair[0]
610061da546Spatrick            if is_hex_byte(key):
611061da546Spatrick                reg_num = Packet(key).get_hex_uint8()
612061da546Spatrick                if reg_num < len(g_register_infos):
613061da546Spatrick                    reg_info = g_register_infos[reg_num]
614061da546Spatrick                    key_value_pair[0] = reg_info.name()
615061da546Spatrick                    key_value_pair[1] = reg_info.get_value_from_hex_string(
616061da546Spatrick                        key_value_pair[1])
617061da546Spatrick            elif key == 'jthreads' or key == 'jstopinfo':
618061da546Spatrick                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
619061da546Spatrick        key_value_pairs.insert(0, ['signal', signo])
620061da546Spatrick        print('stop_reply():')
621061da546Spatrick        dump_key_value_pairs(key_value_pairs)
622061da546Spatrick    elif stop_type == 'W':
623061da546Spatrick        exit_status = packet.get_hex_uint8()
624061da546Spatrick        print('stop_reply(): exit (status=%i)' % exit_status)
625061da546Spatrick    elif stop_type == 'O':
626061da546Spatrick        print('stop_reply(): stdout = "%s"' % packet.str)
627061da546Spatrick
628061da546Spatrick
629061da546Spatrickdef cmd_unknown_packet(options, cmd, args):
630061da546Spatrick    if args:
631061da546Spatrick        print("cmd: %s, args: %s", cmd, args)
632061da546Spatrick    else:
633061da546Spatrick        print("cmd: %s", cmd)
634061da546Spatrick    return False
635061da546Spatrick
636061da546Spatrick
637061da546Spatrickdef cmd_qSymbol(options, cmd, args):
638061da546Spatrick    if args == ':':
639061da546Spatrick        print('ready to serve symbols')
640061da546Spatrick    else:
641061da546Spatrick        packet = Packet(args)
642061da546Spatrick        symbol_addr = packet.get_hex_uint('big')
643061da546Spatrick        if symbol_addr is None:
644061da546Spatrick            if packet.skip_exact_string(':'):
645061da546Spatrick                symbol_name = packet.get_hex_ascii_str()
646061da546Spatrick                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))
647061da546Spatrick            else:
648061da546Spatrick                print('error: bad command format')
649061da546Spatrick        else:
650061da546Spatrick            if packet.skip_exact_string(':'):
651061da546Spatrick                symbol_name = packet.get_hex_ascii_str()
652061da546Spatrick                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))
653061da546Spatrick            else:
654061da546Spatrick                print('error: bad command format')
655061da546Spatrick
656061da546Spatrickdef cmd_QSetWithHexString(options, cmd, args):
657061da546Spatrick    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))
658061da546Spatrick
659061da546Spatrickdef cmd_QSetWithString(options, cmd, args):
660061da546Spatrick    print('%s("%s")' % (cmd[:-1], args))
661061da546Spatrick
662061da546Spatrickdef cmd_QSetWithUnsigned(options, cmd, args):
663061da546Spatrick    print('%s(%i)' % (cmd[:-1], int(args)))
664061da546Spatrick
665061da546Spatrickdef rsp_qSymbol(options, cmd, cmd_args, rsp):
666061da546Spatrick    if len(rsp) == 0:
667061da546Spatrick        print("Unsupported")
668061da546Spatrick    else:
669061da546Spatrick        if rsp == "OK":
670061da546Spatrick            print("No more symbols to lookup")
671061da546Spatrick        else:
672061da546Spatrick            packet = Packet(rsp)
673061da546Spatrick            if packet.skip_exact_string("qSymbol:"):
674061da546Spatrick                symbol_name = packet.get_hex_ascii_str()
675061da546Spatrick                print('lookup_symbol("%s")' % (symbol_name))
676061da546Spatrick            else:
677061da546Spatrick                print('error: response string should start with "qSymbol:": respnse is "%s"' % (rsp))
678061da546Spatrick
679061da546Spatrick
680061da546Spatrickdef cmd_qXfer(options, cmd, args):
681061da546Spatrick    # $qXfer:features:read:target.xml:0,1ffff#14
682061da546Spatrick    print("read target special data %s" % (args))
683061da546Spatrick    return True
684061da546Spatrick
685061da546Spatrick
686061da546Spatrickdef rsp_qXfer(options, cmd, cmd_args, rsp):
687dda28197Spatrick    data = cmd_args.split(':')
688061da546Spatrick    if data[0] == 'features':
689061da546Spatrick        if data[1] == 'read':
690061da546Spatrick            filename, extension = os.path.splitext(data[2])
691061da546Spatrick            if extension == '.xml':
692061da546Spatrick                response = Packet(rsp)
693061da546Spatrick                xml_string = response.get_hex_ascii_str()
694061da546Spatrick                if xml_string:
695061da546Spatrick                    ch = xml_string[0]
696061da546Spatrick                    if ch == 'l':
697061da546Spatrick                        xml_string = xml_string[1:]
698061da546Spatrick                        xml_root = ET.fromstring(xml_string)
699061da546Spatrick                        for reg_element in xml_root.findall("./feature/reg"):
700061da546Spatrick                            if not 'value_regnums' in reg_element.attrib:
701061da546Spatrick                                reg_info = RegisterInfo([])
702061da546Spatrick                                if 'name' in reg_element.attrib:
703061da546Spatrick                                    reg_info.info[
704061da546Spatrick                                        'name'] = reg_element.attrib['name']
705061da546Spatrick                                else:
706061da546Spatrick                                    reg_info.info['name'] = 'unspecified'
707061da546Spatrick                                if 'encoding' in reg_element.attrib:
708061da546Spatrick                                    reg_info.info['encoding'] = reg_element.attrib[
709061da546Spatrick                                        'encoding']
710061da546Spatrick                                else:
711061da546Spatrick                                    reg_info.info['encoding'] = 'uint'
712061da546Spatrick                                if 'offset' in reg_element.attrib:
713061da546Spatrick                                    reg_info.info[
714061da546Spatrick                                        'offset'] = reg_element.attrib['offset']
715061da546Spatrick                                if 'bitsize' in reg_element.attrib:
716061da546Spatrick                                    reg_info.info[
717061da546Spatrick                                        'bitsize'] = reg_element.attrib['bitsize']
718061da546Spatrick                                g_register_infos.append(reg_info)
719061da546Spatrick                        print('XML for "%s":' % (data[2]))
720061da546Spatrick                        ET.dump(xml_root)
721061da546Spatrick
722061da546Spatrick
723061da546Spatrickdef cmd_A(options, cmd, args):
724061da546Spatrick    print('launch process:')
725061da546Spatrick    packet = Packet(args)
726061da546Spatrick    while True:
727061da546Spatrick        arg_len = packet.get_number()
728061da546Spatrick        if arg_len == -1:
729061da546Spatrick            break
730061da546Spatrick        if not packet.skip_exact_string(','):
731061da546Spatrick            break
732061da546Spatrick        arg_idx = packet.get_number()
733061da546Spatrick        if arg_idx == -1:
734061da546Spatrick            break
735061da546Spatrick        if not packet.skip_exact_string(','):
736061da546Spatrick            break
737061da546Spatrick        arg_value = packet.get_hex_ascii_str(arg_len)
738061da546Spatrick        print('argv[%u] = "%s"' % (arg_idx, arg_value))
739061da546Spatrick
740061da546Spatrick
741061da546Spatrickdef cmd_qC(options, cmd, args):
742061da546Spatrick    print("query_current_thread_id()")
743061da546Spatrick
744061da546Spatrick
745061da546Spatrickdef rsp_qC(options, cmd, cmd_args, rsp):
746061da546Spatrick    packet = Packet(rsp)
747061da546Spatrick    if packet.skip_exact_string("QC"):
748061da546Spatrick        tid = packet.get_thread_id()
749061da546Spatrick        print("current_thread_id = %#x" % (tid))
750061da546Spatrick    else:
751061da546Spatrick        print("current_thread_id = old thread ID")
752061da546Spatrick
753061da546Spatrick
754061da546Spatrickdef cmd_query_packet(options, cmd, args):
755061da546Spatrick    if args:
756061da546Spatrick        print("%s%s" % (cmd, args))
757061da546Spatrick    else:
758061da546Spatrick        print("%s" % (cmd))
759061da546Spatrick    return False
760061da546Spatrick
761061da546Spatrick
762061da546Spatrickdef rsp_ok_error(rsp):
763061da546Spatrick    print("rsp: ", rsp)
764061da546Spatrick
765061da546Spatrick
766061da546Spatrickdef rsp_ok_means_supported(options, cmd, cmd_args, rsp):
767061da546Spatrick    if rsp == 'OK':
768061da546Spatrick        print("%s%s is supported" % (cmd, cmd_args))
769061da546Spatrick    elif rsp == '':
770061da546Spatrick        print("%s%s is not supported" % (cmd, cmd_args))
771061da546Spatrick    else:
772061da546Spatrick        print("%s%s -> %s" % (cmd, cmd_args, rsp))
773061da546Spatrick
774061da546Spatrick
775061da546Spatrickdef rsp_ok_means_success(options, cmd, cmd_args, rsp):
776061da546Spatrick    if rsp == 'OK':
777061da546Spatrick        print("success")
778061da546Spatrick    elif rsp == '':
779061da546Spatrick        print("%s%s is not supported" % (cmd, cmd_args))
780061da546Spatrick    else:
781061da546Spatrick        print("%s%s -> %s" % (cmd, cmd_args, rsp))
782061da546Spatrick
783061da546Spatrick
784061da546Spatrickdef dump_key_value_pairs(key_value_pairs):
785061da546Spatrick    max_key_len = 0
786061da546Spatrick    for key_value_pair in key_value_pairs:
787061da546Spatrick        key_len = len(key_value_pair[0])
788061da546Spatrick        if max_key_len < key_len:
789061da546Spatrick            max_key_len = key_len
790061da546Spatrick    for key_value_pair in key_value_pairs:
791061da546Spatrick        key = key_value_pair[0]
792061da546Spatrick        value = key_value_pair[1]
793061da546Spatrick        unhex_value = get_hex_string_if_all_printable(value)
794061da546Spatrick        if unhex_value:
795061da546Spatrick            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))
796061da546Spatrick        else:
797061da546Spatrick            print("%*s = %s" % (max_key_len, key, value))
798061da546Spatrick
799061da546Spatrick
800061da546Spatrickdef rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
801061da546Spatrick    if rsp:
802061da546Spatrick        print('%s response:' % (cmd))
803061da546Spatrick        packet = Packet(rsp)
804061da546Spatrick        key_value_pairs = packet.get_key_value_pairs()
805061da546Spatrick        dump_key_value_pairs(key_value_pairs)
806061da546Spatrick    else:
807061da546Spatrick        print("not supported")
808061da546Spatrick
809061da546Spatrick
810061da546Spatrickdef cmd_c(options, cmd, args):
811061da546Spatrick    print("continue()")
812061da546Spatrick    return False
813061da546Spatrick
814061da546Spatrick
815061da546Spatrickdef cmd_s(options, cmd, args):
816061da546Spatrick    print("step()")
817061da546Spatrick    return False
818061da546Spatrick
819061da546Spatrick
820061da546Spatrickdef cmd_qSpeedTest(options, cmd, args):
821061da546Spatrick    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))
822061da546Spatrick
823061da546Spatrick
824061da546Spatrickdef rsp_qSpeedTest(options, cmd, cmd_args, rsp):
825061da546Spatrick    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))
826061da546Spatrick
827061da546Spatrick
828061da546Spatrickdef cmd_vCont(options, cmd, args):
829061da546Spatrick    if args == '?':
830061da546Spatrick        print("%s: get supported extended continue modes" % (cmd))
831061da546Spatrick    else:
832061da546Spatrick        got_other_threads = 0
833061da546Spatrick        s = ''
834dda28197Spatrick        for thread_action in args[1:].split(';'):
835dda28197Spatrick            (short_action, thread) = thread_action.split(':', 1)
836061da546Spatrick            tid = int(thread, 16)
837061da546Spatrick            if short_action == 'c':
838061da546Spatrick                action = 'continue'
839061da546Spatrick            elif short_action == 's':
840061da546Spatrick                action = 'step'
841061da546Spatrick            elif short_action[0] == 'C':
842061da546Spatrick                action = 'continue with signal 0x%s' % (short_action[1:])
843061da546Spatrick            elif short_action == 'S':
844061da546Spatrick                action = 'step with signal 0x%s' % (short_action[1:])
845061da546Spatrick            else:
846061da546Spatrick                action = short_action
847061da546Spatrick            if s:
848061da546Spatrick                s += ', '
849061da546Spatrick            if tid == -1:
850061da546Spatrick                got_other_threads = 1
851061da546Spatrick                s += 'other-threads:'
852061da546Spatrick            else:
853061da546Spatrick                s += 'thread 0x%4.4x: %s' % (tid, action)
854061da546Spatrick        if got_other_threads:
855061da546Spatrick            print("extended_continue (%s)" % (s))
856061da546Spatrick        else:
857061da546Spatrick            print("extended_continue (%s, other-threads: suspend)" % (s))
858061da546Spatrick    return False
859061da546Spatrick
860061da546Spatrick
861061da546Spatrickdef rsp_vCont(options, cmd, cmd_args, rsp):
862061da546Spatrick    if cmd_args == '?':
863061da546Spatrick        # Skip the leading 'vCont;'
864061da546Spatrick        rsp = rsp[6:]
865dda28197Spatrick        modes = rsp.split(';')
866061da546Spatrick        s = "%s: supported extended continue modes include: " % (cmd)
867061da546Spatrick
868061da546Spatrick        for i, mode in enumerate(modes):
869061da546Spatrick            if i:
870061da546Spatrick                s += ', '
871061da546Spatrick            if mode == 'c':
872061da546Spatrick                s += 'continue'
873061da546Spatrick            elif mode == 'C':
874061da546Spatrick                s += 'continue with signal'
875061da546Spatrick            elif mode == 's':
876061da546Spatrick                s += 'step'
877061da546Spatrick            elif mode == 'S':
878061da546Spatrick                s += 'step with signal'
879061da546Spatrick            elif mode == 't':
880061da546Spatrick                s += 'stop'
881061da546Spatrick            # else:
882061da546Spatrick            #     s += 'unrecognized vCont mode: ', str(mode)
883061da546Spatrick        print(s)
884061da546Spatrick    elif rsp:
885061da546Spatrick        if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
886061da546Spatrick            rsp_stop_reply(options, cmd, cmd_args, rsp)
887061da546Spatrick            return
888061da546Spatrick        if rsp[0] == 'O':
889061da546Spatrick            print("stdout: %s" % (rsp))
890061da546Spatrick            return
891061da546Spatrick    else:
892061da546Spatrick        print("not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp))
893061da546Spatrick
894061da546Spatrick
895061da546Spatrickdef cmd_vAttach(options, cmd, args):
896*f6aab3d8Srobert    (extra_command, args) = args.split(';')
897061da546Spatrick    if extra_command:
898061da546Spatrick        print("%s%s(%s)" % (cmd, extra_command, args))
899061da546Spatrick    else:
900061da546Spatrick        print("attach(pid = %u)" % int(args, 16))
901061da546Spatrick    return False
902061da546Spatrick
903061da546Spatrick
904061da546Spatrickdef cmd_qRegisterInfo(options, cmd, args):
905061da546Spatrick    print('query_register_info(reg_num=%i)' % (int(args, 16)))
906061da546Spatrick    return False
907061da546Spatrick
908061da546Spatrick
909061da546Spatrickdef rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
910061da546Spatrick    global g_max_register_info_name_len
911061da546Spatrick    print('query_register_info(reg_num=%i):' % (int(cmd_args, 16)), end=' ')
912061da546Spatrick    if len(rsp) == 3 and rsp[0] == 'E':
913061da546Spatrick        g_max_register_info_name_len = 0
914061da546Spatrick        for reg_info in g_register_infos:
915061da546Spatrick            name_len = len(reg_info.name())
916061da546Spatrick            if g_max_register_info_name_len < name_len:
917061da546Spatrick                g_max_register_info_name_len = name_len
918061da546Spatrick        print(' DONE')
919061da546Spatrick    else:
920061da546Spatrick        packet = Packet(rsp)
921061da546Spatrick        reg_info = RegisterInfo(packet.get_key_value_pairs())
922061da546Spatrick        g_register_infos.append(reg_info)
923061da546Spatrick        print(reg_info)
924061da546Spatrick    return False
925061da546Spatrick
926061da546Spatrick
927061da546Spatrickdef cmd_qThreadInfo(options, cmd, args):
928061da546Spatrick    if cmd == 'qfThreadInfo':
929061da546Spatrick        query_type = 'first'
930061da546Spatrick    else:
931061da546Spatrick        query_type = 'subsequent'
932061da546Spatrick    print('get_current_thread_list(type=%s)' % (query_type))
933061da546Spatrick    return False
934061da546Spatrick
935061da546Spatrick
936061da546Spatrickdef rsp_qThreadInfo(options, cmd, cmd_args, rsp):
937061da546Spatrick    packet = Packet(rsp)
938061da546Spatrick    response_type = packet.get_char()
939061da546Spatrick    if response_type == 'm':
940061da546Spatrick        tids = packet.split_hex(';', 'big')
941061da546Spatrick        for i, tid in enumerate(tids):
942061da546Spatrick            if i:
943061da546Spatrick                print(',', end=' ')
944061da546Spatrick            print('0x%x' % (tid), end=' ')
945061da546Spatrick        print()
946061da546Spatrick    elif response_type == 'l':
947061da546Spatrick        print('END')
948061da546Spatrick
949061da546Spatrick
950061da546Spatrickdef rsp_hex_big_endian(options, cmd, cmd_args, rsp):
951061da546Spatrick    if rsp == '':
952061da546Spatrick        print("%s%s is not supported" % (cmd, cmd_args))
953061da546Spatrick    else:
954061da546Spatrick        packet = Packet(rsp)
955061da546Spatrick        uval = packet.get_hex_uint('big')
956061da546Spatrick        print('%s: 0x%x' % (cmd, uval))
957061da546Spatrick
958061da546Spatrick
959061da546Spatrickdef cmd_read_mem_bin(options, cmd, args):
960061da546Spatrick    # x0x7fff5fc39200,0x200
961061da546Spatrick    packet = Packet(args)
962061da546Spatrick    addr = packet.get_hex_uint('big')
963061da546Spatrick    comma = packet.get_char()
964061da546Spatrick    size = packet.get_hex_uint('big')
965061da546Spatrick    print('binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
966061da546Spatrick    return False
967061da546Spatrick
968061da546Spatrick
969061da546Spatrickdef rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
970061da546Spatrick    packet = Packet(cmd_args)
971061da546Spatrick    addr = packet.get_hex_uint('big')
972061da546Spatrick    comma = packet.get_char()
973061da546Spatrick    size = packet.get_hex_uint('big')
974061da546Spatrick    print('memory:')
975061da546Spatrick    if size > 0:
976061da546Spatrick        dump_hex_memory_buffer(addr, rsp)
977061da546Spatrick
978061da546Spatrick
979061da546Spatrickdef cmd_read_memory(options, cmd, args):
980061da546Spatrick    packet = Packet(args)
981061da546Spatrick    addr = packet.get_hex_uint('big')
982061da546Spatrick    comma = packet.get_char()
983061da546Spatrick    size = packet.get_hex_uint('big')
984061da546Spatrick    print('read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
985061da546Spatrick    return False
986061da546Spatrick
987061da546Spatrick
988061da546Spatrickdef dump_hex_memory_buffer(addr, hex_byte_str):
989061da546Spatrick    packet = Packet(hex_byte_str)
990061da546Spatrick    idx = 0
991061da546Spatrick    ascii = ''
992061da546Spatrick    uval = packet.get_hex_uint8()
993061da546Spatrick    while uval is not None:
994061da546Spatrick        if ((idx % 16) == 0):
995061da546Spatrick            if ascii:
996061da546Spatrick                print('  ', ascii)
997061da546Spatrick                ascii = ''
998061da546Spatrick            print('0x%x:' % (addr + idx), end=' ')
999061da546Spatrick        print('%2.2x' % (uval), end=' ')
1000061da546Spatrick        if 0x20 <= uval and uval < 0x7f:
1001061da546Spatrick            ascii += '%c' % uval
1002061da546Spatrick        else:
1003061da546Spatrick            ascii += '.'
1004061da546Spatrick        uval = packet.get_hex_uint8()
1005061da546Spatrick        idx = idx + 1
1006061da546Spatrick    if ascii:
1007061da546Spatrick        print('  ', ascii)
1008061da546Spatrick        ascii = ''
1009061da546Spatrick
1010061da546Spatrick
1011061da546Spatrickdef cmd_write_memory(options, cmd, args):
1012061da546Spatrick    packet = Packet(args)
1013061da546Spatrick    addr = packet.get_hex_uint('big')
1014061da546Spatrick    if packet.get_char() != ',':
1015061da546Spatrick        print('error: invalid write memory command (missing comma after address)')
1016061da546Spatrick        return
1017061da546Spatrick    size = packet.get_hex_uint('big')
1018061da546Spatrick    if packet.get_char() != ':':
1019061da546Spatrick        print('error: invalid write memory command (missing colon after size)')
1020061da546Spatrick        return
1021061da546Spatrick    print('write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size))
1022061da546Spatrick    dump_hex_memory_buffer(addr, packet.str)
1023061da546Spatrick    return False
1024061da546Spatrick
1025061da546Spatrick
1026061da546Spatrickdef cmd_alloc_memory(options, cmd, args):
1027061da546Spatrick    packet = Packet(args)
1028061da546Spatrick    byte_size = packet.get_hex_uint('big')
1029061da546Spatrick    if packet.get_char() != ',':
1030061da546Spatrick        print('error: invalid allocate memory command (missing comma after address)')
1031061da546Spatrick        return
1032061da546Spatrick    print('allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str))
1033061da546Spatrick    return False
1034061da546Spatrick
1035061da546Spatrick
1036061da546Spatrickdef rsp_alloc_memory(options, cmd, cmd_args, rsp):
1037061da546Spatrick    packet = Packet(rsp)
1038061da546Spatrick    addr = packet.get_hex_uint('big')
1039061da546Spatrick    print('addr = 0x%x' % addr)
1040061da546Spatrick
1041061da546Spatrick
1042061da546Spatrickdef cmd_dealloc_memory(options, cmd, args):
1043061da546Spatrick    packet = Packet(args)
1044061da546Spatrick    addr = packet.get_hex_uint('big')
1045061da546Spatrick    if packet.get_char() != ',':
1046061da546Spatrick        print('error: invalid allocate memory command (missing comma after address)')
1047061da546Spatrick    else:
1048061da546Spatrick        print('deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str))
1049061da546Spatrick    return False
1050061da546Spatrick
1051061da546Spatrick
1052061da546Spatrickdef rsp_memory_bytes(options, cmd, cmd_args, rsp):
1053061da546Spatrick    addr = Packet(cmd_args).get_hex_uint('big')
1054061da546Spatrick    dump_hex_memory_buffer(addr, rsp)
1055061da546Spatrick
1056061da546Spatrick
1057061da546Spatrickdef get_register_name_equal_value(options, reg_num, hex_value_str):
1058061da546Spatrick    if reg_num < len(g_register_infos):
1059061da546Spatrick        reg_info = g_register_infos[reg_num]
1060061da546Spatrick        value_str = reg_info.get_value_from_hex_string(hex_value_str)
1061061da546Spatrick        s = reg_info.name() + ' = '
1062061da546Spatrick        if options.symbolicator:
1063061da546Spatrick            symbolicated_addresses = options.symbolicator.symbolicate(
1064061da546Spatrick                int(value_str, 0))
1065061da546Spatrick            if symbolicated_addresses:
1066061da546Spatrick                s += options.colors.magenta()
1067061da546Spatrick                s += '%s' % symbolicated_addresses[0]
1068061da546Spatrick                s += options.colors.reset()
1069061da546Spatrick                return s
1070061da546Spatrick        s += value_str
1071061da546Spatrick        return s
1072061da546Spatrick    else:
1073061da546Spatrick        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
1074061da546Spatrick        return 'reg(%u) = 0x%x' % (reg_num, reg_value)
1075061da546Spatrick
1076061da546Spatrick
1077061da546Spatrickdef cmd_read_one_reg(options, cmd, args):
1078061da546Spatrick    packet = Packet(args)
1079061da546Spatrick    reg_num = packet.get_hex_uint('big')
1080061da546Spatrick    tid = get_thread_from_thread_suffix(packet.str)
1081061da546Spatrick    name = None
1082061da546Spatrick    if reg_num < len(g_register_infos):
1083061da546Spatrick        name = g_register_infos[reg_num].name()
1084061da546Spatrick    if packet.str:
1085061da546Spatrick        packet.get_char()  # skip ;
1086061da546Spatrick        thread_info = packet.get_key_value_pairs()
1087061da546Spatrick        tid = int(thread_info[0][1], 16)
1088061da546Spatrick    s = 'read_register (reg_num=%u' % reg_num
1089061da546Spatrick    if name:
1090061da546Spatrick        s += ' (%s)' % (name)
1091061da546Spatrick    if tid is not None:
1092061da546Spatrick        s += ', tid = 0x%4.4x' % (tid)
1093061da546Spatrick    s += ')'
1094061da546Spatrick    print(s)
1095061da546Spatrick    return False
1096061da546Spatrick
1097061da546Spatrick
1098061da546Spatrickdef rsp_read_one_reg(options, cmd, cmd_args, rsp):
1099061da546Spatrick    packet = Packet(cmd_args)
1100061da546Spatrick    reg_num = packet.get_hex_uint('big')
1101061da546Spatrick    print(get_register_name_equal_value(options, reg_num, rsp))
1102061da546Spatrick
1103061da546Spatrick
1104061da546Spatrickdef cmd_write_one_reg(options, cmd, args):
1105061da546Spatrick    packet = Packet(args)
1106061da546Spatrick    reg_num = packet.get_hex_uint('big')
1107061da546Spatrick    if packet.get_char() != '=':
1108061da546Spatrick        print('error: invalid register write packet')
1109061da546Spatrick    else:
1110061da546Spatrick        name = None
1111061da546Spatrick        hex_value_str = packet.get_hex_chars()
1112061da546Spatrick        tid = get_thread_from_thread_suffix(packet.str)
1113061da546Spatrick        s = 'write_register (reg_num=%u' % reg_num
1114061da546Spatrick        if name:
1115061da546Spatrick            s += ' (%s)' % (name)
1116061da546Spatrick        s += ', value = '
1117061da546Spatrick        s += get_register_name_equal_value(options, reg_num, hex_value_str)
1118061da546Spatrick        if tid is not None:
1119061da546Spatrick            s += ', tid = 0x%4.4x' % (tid)
1120061da546Spatrick        s += ')'
1121061da546Spatrick        print(s)
1122061da546Spatrick    return False
1123061da546Spatrick
1124061da546Spatrick
1125061da546Spatrickdef dump_all_regs(packet):
1126061da546Spatrick    for reg_info in g_register_infos:
1127061da546Spatrick        nibble_size = reg_info.bit_size() / 4
1128061da546Spatrick        hex_value_str = packet.get_hex_chars(nibble_size)
1129061da546Spatrick        if hex_value_str is not None:
1130061da546Spatrick            value = reg_info.get_value_from_hex_string(hex_value_str)
1131061da546Spatrick            print('%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value))
1132061da546Spatrick        else:
1133061da546Spatrick            return
1134061da546Spatrick
1135061da546Spatrick
1136061da546Spatrickdef cmd_read_all_regs(cmd, cmd_args):
1137061da546Spatrick    packet = Packet(cmd_args)
1138061da546Spatrick    packet.get_char()  # toss the 'g' command character
1139061da546Spatrick    tid = get_thread_from_thread_suffix(packet.str)
1140061da546Spatrick    if tid is not None:
1141061da546Spatrick        print('read_all_register(thread = 0x%4.4x)' % tid)
1142061da546Spatrick    else:
1143061da546Spatrick        print('read_all_register()')
1144061da546Spatrick    return False
1145061da546Spatrick
1146061da546Spatrick
1147061da546Spatrickdef rsp_read_all_regs(options, cmd, cmd_args, rsp):
1148061da546Spatrick    packet = Packet(rsp)
1149061da546Spatrick    dump_all_regs(packet)
1150061da546Spatrick
1151061da546Spatrick
1152061da546Spatrickdef cmd_write_all_regs(options, cmd, args):
1153061da546Spatrick    packet = Packet(args)
1154061da546Spatrick    print('write_all_registers()')
1155061da546Spatrick    dump_all_regs(packet)
1156061da546Spatrick    return False
1157061da546Spatrick
1158061da546Spatrickg_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]
1159061da546Spatrick
1160061da546Spatrick
1161061da546Spatrickdef cmd_bp(options, cmd, args):
1162061da546Spatrick    if cmd == 'Z':
1163061da546Spatrick        s = 'set_'
1164061da546Spatrick    else:
1165061da546Spatrick        s = 'clear_'
1166061da546Spatrick    packet = Packet(args)
1167061da546Spatrick    bp_type = packet.get_hex_uint('big')
1168061da546Spatrick    packet.get_char()  # Skip ,
1169061da546Spatrick    bp_addr = packet.get_hex_uint('big')
1170061da546Spatrick    packet.get_char()  # Skip ,
1171061da546Spatrick    bp_size = packet.get_hex_uint('big')
1172061da546Spatrick    s += g_bp_types[bp_type]
1173061da546Spatrick    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
1174061da546Spatrick    print(s)
1175061da546Spatrick    return False
1176061da546Spatrick
1177061da546Spatrick
1178061da546Spatrickdef cmd_mem_rgn_info(options, cmd, args):
1179061da546Spatrick    packet = Packet(args)
1180061da546Spatrick    packet.get_char()  # skip ':' character
1181061da546Spatrick    addr = packet.get_hex_uint('big')
1182061da546Spatrick    print('get_memory_region_info (addr=0x%x)' % (addr))
1183061da546Spatrick    return False
1184061da546Spatrick
1185061da546Spatrick
1186061da546Spatrickdef cmd_kill(options, cmd, args):
1187061da546Spatrick    print('kill_process()')
1188061da546Spatrick    return False
1189061da546Spatrick
1190061da546Spatrick
1191061da546Spatrickdef cmd_jThreadsInfo(options, cmd, args):
1192061da546Spatrick    print('jThreadsInfo()')
1193061da546Spatrick    return False
1194061da546Spatrick
1195061da546Spatrick
1196061da546Spatrickdef cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
1197061da546Spatrick    print('jGetLoadedDynamicLibrariesInfos()')
1198061da546Spatrick    return False
1199061da546Spatrick
1200061da546Spatrick
1201061da546Spatrickdef decode_packet(s, start_index=0):
1202061da546Spatrick    # print '\ndecode_packet("%s")' % (s[start_index:])
1203061da546Spatrick    index = s.find('}', start_index)
1204061da546Spatrick    have_escapes = index != -1
1205061da546Spatrick    if have_escapes:
1206061da546Spatrick        normal_s = s[start_index:index]
1207061da546Spatrick    else:
1208061da546Spatrick        normal_s = s[start_index:]
1209061da546Spatrick    # print 'normal_s = "%s"' % (normal_s)
1210061da546Spatrick    if have_escapes:
1211061da546Spatrick        escape_char = '%c' % (ord(s[index + 1]) ^ 0x20)
1212061da546Spatrick        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
1213061da546Spatrick        return normal_s + escape_char + decode_packet(s, index + 2)
1214061da546Spatrick    else:
1215061da546Spatrick        return normal_s
1216061da546Spatrick
1217061da546Spatrick
1218061da546Spatrickdef rsp_json(options, cmd, cmd_args, rsp):
1219061da546Spatrick    print('%s() reply:' % (cmd))
1220*f6aab3d8Srobert    if not rsp:
1221*f6aab3d8Srobert        return
1222*f6aab3d8Srobert    try:
1223061da546Spatrick        json_tree = json.loads(rsp)
1224061da546Spatrick        print(json.dumps(json_tree, indent=4, separators=(',', ': ')))
1225*f6aab3d8Srobert    except json.JSONDecodeError:
1226*f6aab3d8Srobert        return
1227061da546Spatrick
1228061da546Spatrickdef rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
1229061da546Spatrick    if cmd_args:
1230061da546Spatrick        rsp_json(options, cmd, cmd_args, rsp)
1231061da546Spatrick    else:
1232061da546Spatrick        rsp_ok_means_supported(options, cmd, cmd_args, rsp)
1233061da546Spatrick
1234061da546Spatrickgdb_remote_commands = {
1235061da546Spatrick    '\\?': {'cmd': cmd_stop_reply, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
1236061da546Spatrick    'qThreadStopInfo': {'cmd': cmd_qThreadStopInfo, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
1237061da546Spatrick    'QStartNoAckMode': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if no ack mode is supported"},
1238061da546Spatrick    'QThreadSuffixSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if thread suffix is supported"},
1239061da546Spatrick    'QListThreadsInStopReply': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if threads in stop reply packets are supported"},
1240061da546Spatrick    'QSetDetachOnError:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should detach on error"},
1241061da546Spatrick    'QSetDisableASLR:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should disable ASLR"},
1242061da546Spatrick    'qLaunchSuccess': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_success, 'name': "check on launch success for the A packet"},
1243061da546Spatrick    'A': {'cmd': cmd_A, 'rsp': rsp_ok_means_success, 'name': "launch process"},
1244061da546Spatrick    'QLaunchArch:': {'cmd': cmd_QSetWithString, 'rsp': rsp_ok_means_supported, 'name': "set the arch to launch in case the file contains multiple architectures"},
1245061da546Spatrick    'qVAttachOrWaitSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "set the launch architecture"},
1246061da546Spatrick    'qHostInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get host information"},
1247061da546Spatrick    'qC': {'cmd': cmd_qC, 'rsp': rsp_qC, 'name': "return the current thread ID"},
1248061da546Spatrick    'vCont': {'cmd': cmd_vCont, 'rsp': rsp_vCont, 'name': "extended continue command"},
1249061da546Spatrick    'qSpeedTest': {'cmd':cmd_qSpeedTest, 'rsp': rsp_qSpeedTest, 'name': 'speed test packdet'},
1250061da546Spatrick    'vAttach': {'cmd': cmd_vAttach, 'rsp': rsp_stop_reply, 'name': "attach to process"},
1251061da546Spatrick    'c': {'cmd': cmd_c, 'rsp': rsp_stop_reply, 'name': "continue"},
1252061da546Spatrick    's': {'cmd': cmd_s, 'rsp': rsp_stop_reply, 'name': "step"},
1253061da546Spatrick    'qRegisterInfo': {'cmd': cmd_qRegisterInfo, 'rsp': rsp_qRegisterInfo, 'name': "query register info"},
1254061da546Spatrick    'qfThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
1255061da546Spatrick    'qsThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
1256061da546Spatrick    'qShlibInfoAddr': {'cmd': cmd_query_packet, 'rsp': rsp_hex_big_endian, 'name': "get shared library info address"},
1257061da546Spatrick    'qMemoryRegionInfo': {'cmd': cmd_mem_rgn_info, 'rsp': rsp_dump_key_value_pairs, 'name': "get memory region information"},
1258061da546Spatrick    'qProcessInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get process info"},
1259061da546Spatrick    'qSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query supported"},
1260061da546Spatrick    'qXfer:': {'cmd': cmd_qXfer, 'rsp': rsp_qXfer, 'name': "qXfer"},
1261061da546Spatrick    'qSymbol:': {'cmd': cmd_qSymbol, 'rsp': rsp_qSymbol, 'name': "qSymbol"},
1262061da546Spatrick    'QSetSTDIN:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDIN prior to launching with A packet"},
1263061da546Spatrick    'QSetSTDOUT:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDOUT prior to launching with A packet"},
1264061da546Spatrick    'QSetSTDERR:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDERR prior to launching with A packet"},
1265061da546Spatrick    'QEnvironment:' : {'cmd' : cmd_QSetWithString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
1266061da546Spatrick    'QEnvironmentHexEncoded:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
1267061da546Spatrick    'x': {'cmd': cmd_read_mem_bin, 'rsp': rsp_mem_bin_bytes, 'name': "read memory binary"},
1268061da546Spatrick    'X': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory binary"},
1269061da546Spatrick    'm': {'cmd': cmd_read_memory, 'rsp': rsp_memory_bytes, 'name': "read memory"},
1270061da546Spatrick    'M': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory"},
1271061da546Spatrick    '_M': {'cmd': cmd_alloc_memory, 'rsp': rsp_alloc_memory, 'name': "allocate memory"},
1272061da546Spatrick    '_m': {'cmd': cmd_dealloc_memory, 'rsp': rsp_ok_means_success, 'name': "deallocate memory"},
1273061da546Spatrick    'p': {'cmd': cmd_read_one_reg, 'rsp': rsp_read_one_reg, 'name': "read single register"},
1274061da546Spatrick    'P': {'cmd': cmd_write_one_reg, 'rsp': rsp_ok_means_success, 'name': "write single register"},
1275061da546Spatrick    'g': {'cmd': cmd_read_all_regs, 'rsp': rsp_read_all_regs, 'name': "read all registers"},
1276061da546Spatrick    'G': {'cmd': cmd_write_all_regs, 'rsp': rsp_ok_means_success, 'name': "write all registers"},
1277061da546Spatrick    'z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "clear breakpoint or watchpoint"},
1278061da546Spatrick    'Z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "set breakpoint or watchpoint"},
1279061da546Spatrick    'k': {'cmd': cmd_kill, 'rsp': rsp_stop_reply, 'name': "kill process"},
1280061da546Spatrick    'jThreadsInfo': {'cmd': cmd_jThreadsInfo, 'rsp': rsp_json, 'name': "JSON get all threads info"},
1281061da546Spatrick    'jGetLoadedDynamicLibrariesInfos:': {'cmd': cmd_jGetLoadedDynamicLibrariesInfos, 'rsp': rsp_jGetLoadedDynamicLibrariesInfos, 'name': 'JSON get loaded dynamic libraries'},
1282061da546Spatrick}
1283061da546Spatrick
1284061da546Spatrick
1285061da546Spatrickdef calculate_mean_and_standard_deviation(floats):
1286061da546Spatrick    sum = 0.0
1287061da546Spatrick    count = len(floats)
1288061da546Spatrick    if count == 0:
1289061da546Spatrick        return (0.0, 0.0)
1290061da546Spatrick    for f in floats:
1291061da546Spatrick        sum += f
1292061da546Spatrick    mean = sum / count
1293061da546Spatrick    accum = 0.0
1294061da546Spatrick    for f in floats:
1295061da546Spatrick        delta = f - mean
1296061da546Spatrick        accum += delta * delta
1297061da546Spatrick
1298061da546Spatrick    std_dev = math.sqrt(accum / (count - 1))
1299061da546Spatrick    return (mean, std_dev)
1300061da546Spatrick
1301061da546Spatrick
1302061da546Spatrickdef parse_gdb_log_file(path, options):
1303061da546Spatrick    f = open(path)
1304061da546Spatrick    parse_gdb_log(f, options)
1305061da546Spatrick    f.close()
1306061da546Spatrick
1307061da546Spatrick
1308061da546Spatrickdef round_up(n, incr):
1309061da546Spatrick    return float(((int(n) + incr) / incr) * incr)
1310061da546Spatrick
1311061da546Spatrick
1312061da546Spatrickdef plot_latencies(sec_times):
1313061da546Spatrick    # import numpy as np
1314061da546Spatrick    import matplotlib.pyplot as plt
1315061da546Spatrick
1316061da546Spatrick    for (i, name) in enumerate(sec_times.keys()):
1317061da546Spatrick        times = sec_times[name]
1318061da546Spatrick        if len(times) <= 1:
1319061da546Spatrick            continue
1320061da546Spatrick        plt.subplot(2, 1, 1)
1321061da546Spatrick        plt.title('Packet "%s" Times' % (name))
1322061da546Spatrick        plt.xlabel('Packet')
1323061da546Spatrick        units = 'ms'
1324061da546Spatrick        adj_times = []
1325061da546Spatrick        max_time = 0.0
1326061da546Spatrick        for time in times:
1327061da546Spatrick            time = time * 1000.0
1328061da546Spatrick            adj_times.append(time)
1329061da546Spatrick            if time > max_time:
1330061da546Spatrick                max_time = time
1331061da546Spatrick        if max_time < 1.0:
1332061da546Spatrick            units = 'us'
1333061da546Spatrick            max_time = 0.0
1334061da546Spatrick            for i in range(len(adj_times)):
1335061da546Spatrick                adj_times[i] *= 1000.0
1336061da546Spatrick                if adj_times[i] > max_time:
1337061da546Spatrick                    max_time = adj_times[i]
1338061da546Spatrick        plt.ylabel('Time (%s)' % (units))
1339061da546Spatrick        max_y = None
1340061da546Spatrick        for i in [5.0, 10.0, 25.0, 50.0]:
1341061da546Spatrick            if max_time < i:
1342061da546Spatrick                max_y = round_up(max_time, i)
1343061da546Spatrick                break
1344061da546Spatrick        if max_y is None:
1345061da546Spatrick            max_y = round_up(max_time, 100.0)
1346061da546Spatrick        plt.ylim(0.0, max_y)
1347061da546Spatrick        plt.plot(adj_times, 'o-')
1348061da546Spatrick        plt.show()
1349061da546Spatrick
1350061da546Spatrick
1351061da546Spatrickdef parse_gdb_log(file, options):
1352061da546Spatrick    '''Parse a GDB log file that was generated by enabling logging with:
1353061da546Spatrick    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
1354061da546Spatrick    This log file will contain timestamps and this function will then normalize
1355061da546Spatrick    those packets to be relative to the first value timestamp that is found and
1356061da546Spatrick    show delta times between log lines and also keep track of how long it takes
1357061da546Spatrick    for GDB remote commands to make a send/receive round trip. This can be
1358061da546Spatrick    handy when trying to figure out why some operation in the debugger is taking
1359061da546Spatrick    a long time during a preset set of debugger commands.'''
1360061da546Spatrick
1361061da546Spatrick    tricky_commands = ['qRegisterInfo']
1362061da546Spatrick    timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
1363061da546Spatrick    packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]')
1364061da546Spatrick    packet_transmit_name_regex = re.compile(
1365061da546Spatrick        '(?P<direction>send|read) packet: (?P<packet>.*)')
1366061da546Spatrick    packet_contents_name_regex = re.compile('\$([^#]*)#[0-9a-fA-F]{2}')
1367061da546Spatrick    packet_checksum_regex = re.compile('.*#[0-9a-fA-F]{2}$')
1368061da546Spatrick    packet_names_regex_str = '(' + \
1369061da546Spatrick        '|'.join(gdb_remote_commands.keys()) + ')(.*)'
1370061da546Spatrick    packet_names_regex = re.compile(packet_names_regex_str)
1371061da546Spatrick
1372061da546Spatrick    base_time = 0.0
1373061da546Spatrick    last_time = 0.0
1374061da546Spatrick    min_time = 100000000.0
1375061da546Spatrick    packet_total_times = {}
1376061da546Spatrick    all_packet_times = []
1377061da546Spatrick    packet_times = {}
1378061da546Spatrick    packet_counts = {}
1379061da546Spatrick    lines = file.read().splitlines()
1380061da546Spatrick    last_command = None
1381061da546Spatrick    last_command_args = None
1382061da546Spatrick    last_command_packet = None
1383061da546Spatrick    hide_next_response = False
1384061da546Spatrick    num_lines = len(lines)
1385061da546Spatrick    skip_count = 0
1386061da546Spatrick    for (line_index, line) in enumerate(lines):
1387061da546Spatrick        # See if we need to skip any lines
1388061da546Spatrick        if skip_count > 0:
1389061da546Spatrick            skip_count -= 1
1390061da546Spatrick            continue
1391061da546Spatrick        m = packet_transmit_name_regex.search(line)
1392061da546Spatrick        is_command = False
1393061da546Spatrick        direction = None
1394061da546Spatrick        if m:
1395061da546Spatrick            direction = m.group('direction')
1396061da546Spatrick            is_command = direction == 'send'
1397061da546Spatrick            packet = m.group('packet')
1398061da546Spatrick            sys.stdout.write(options.colors.green())
1399061da546Spatrick            if not options.quiet and not hide_next_response:
1400061da546Spatrick                print('#  ', line)
1401061da546Spatrick            sys.stdout.write(options.colors.reset())
1402061da546Spatrick
1403061da546Spatrick            # print 'direction = "%s", packet = "%s"' % (direction, packet)
1404061da546Spatrick
1405061da546Spatrick            if packet[0] == '+':
1406061da546Spatrick                if is_command:
1407061da546Spatrick                    print('-->', end=' ')
1408061da546Spatrick                else:
1409061da546Spatrick                    print('<--', end=' ')
1410061da546Spatrick                if not options.quiet:
1411061da546Spatrick                    print('ACK')
1412061da546Spatrick                continue
1413061da546Spatrick            elif packet[0] == '-':
1414061da546Spatrick                if is_command:
1415061da546Spatrick                    print('-->', end=' ')
1416061da546Spatrick                else:
1417061da546Spatrick                    print('<--', end=' ')
1418061da546Spatrick                if not options.quiet:
1419061da546Spatrick                    print('NACK')
1420061da546Spatrick                continue
1421061da546Spatrick            elif packet[0] == '$':
1422061da546Spatrick                m = packet_contents_name_regex.match(packet)
1423061da546Spatrick                if not m and packet[0] == '$':
1424061da546Spatrick                    multiline_packet = packet
1425061da546Spatrick                    idx = line_index + 1
1426061da546Spatrick                    while idx < num_lines:
1427061da546Spatrick                        if not options.quiet and not hide_next_response:
1428061da546Spatrick                            print('#  ', lines[idx])
1429061da546Spatrick                        multiline_packet += lines[idx]
1430061da546Spatrick                        m = packet_contents_name_regex.match(multiline_packet)
1431061da546Spatrick                        if m:
1432061da546Spatrick                            packet = multiline_packet
1433061da546Spatrick                            skip_count = idx - line_index
1434061da546Spatrick                            break
1435061da546Spatrick                        else:
1436061da546Spatrick                            idx += 1
1437061da546Spatrick                if m:
1438061da546Spatrick                    if is_command:
1439061da546Spatrick                        print('-->', end=' ')
1440061da546Spatrick                    else:
1441061da546Spatrick                        print('<--', end=' ')
1442061da546Spatrick                    contents = decode_packet(m.group(1))
1443061da546Spatrick                    if is_command:
1444061da546Spatrick                        hide_next_response = False
1445061da546Spatrick                        m = packet_names_regex.match(contents)
1446061da546Spatrick                        if m:
1447061da546Spatrick                            last_command = m.group(1)
1448061da546Spatrick                            if last_command == '?':
1449061da546Spatrick                                last_command = '\\?'
1450061da546Spatrick                            packet_name = last_command
1451061da546Spatrick                            last_command_args = m.group(2)
1452061da546Spatrick                            last_command_packet = contents
1453061da546Spatrick                            hide_next_response = gdb_remote_commands[last_command][
1454061da546Spatrick                                'cmd'](options, last_command, last_command_args)
1455061da546Spatrick                        else:
1456061da546Spatrick                            packet_match = packet_name_regex.match(contents)
1457061da546Spatrick                            if packet_match:
1458061da546Spatrick                                packet_name = packet_match.group(1)
1459061da546Spatrick                                for tricky_cmd in tricky_commands:
1460061da546Spatrick                                    if packet_name.find(tricky_cmd) == 0:
1461061da546Spatrick                                        packet_name = tricky_cmd
1462061da546Spatrick                            else:
1463061da546Spatrick                                packet_name = contents
1464061da546Spatrick                            last_command = None
1465061da546Spatrick                            last_command_args = None
1466061da546Spatrick                            last_command_packet = None
1467061da546Spatrick                    elif last_command:
1468061da546Spatrick                        gdb_remote_commands[last_command]['rsp'](
1469061da546Spatrick                            options, last_command, last_command_args, contents)
1470061da546Spatrick                else:
1471061da546Spatrick                    print('error: invalid packet: "', packet, '"')
1472061da546Spatrick            else:
1473061da546Spatrick                print('???')
1474061da546Spatrick        else:
1475061da546Spatrick            print('## ', line)
1476061da546Spatrick        match = timestamp_regex.match(line)
1477061da546Spatrick        if match:
1478061da546Spatrick            curr_time = float(match.group(2))
1479061da546Spatrick            if last_time and not is_command:
1480061da546Spatrick                delta = curr_time - last_time
1481061da546Spatrick                all_packet_times.append(delta)
1482061da546Spatrick            delta = 0.0
1483061da546Spatrick            if base_time:
1484061da546Spatrick                delta = curr_time - last_time
1485061da546Spatrick            else:
1486061da546Spatrick                base_time = curr_time
1487061da546Spatrick
1488061da546Spatrick            if not is_command:
1489061da546Spatrick                if line.find('read packet: $') >= 0 and packet_name:
1490061da546Spatrick                    if packet_name in packet_total_times:
1491061da546Spatrick                        packet_total_times[packet_name] += delta
1492061da546Spatrick                        packet_counts[packet_name] += 1
1493061da546Spatrick                    else:
1494061da546Spatrick                        packet_total_times[packet_name] = delta
1495061da546Spatrick                        packet_counts[packet_name] = 1
1496061da546Spatrick                    if packet_name not in packet_times:
1497061da546Spatrick                        packet_times[packet_name] = []
1498061da546Spatrick                    packet_times[packet_name].append(delta)
1499061da546Spatrick                    packet_name = None
1500061da546Spatrick                if min_time > delta:
1501061da546Spatrick                    min_time = delta
1502061da546Spatrick
1503061da546Spatrick            if not options or not options.quiet:
1504061da546Spatrick                print('%s%.6f %+.6f%s' % (match.group(1),
1505061da546Spatrick                                          curr_time - base_time,
1506061da546Spatrick                                          delta,
1507061da546Spatrick                                          match.group(3)))
1508061da546Spatrick            last_time = curr_time
1509061da546Spatrick        # else:
1510061da546Spatrick        #     print line
1511061da546Spatrick    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)
1512061da546Spatrick    if average and std_dev:
1513061da546Spatrick        print('%u packets with average packet time of %f and standard deviation of %f' % (len(all_packet_times), average, std_dev))
1514061da546Spatrick    if packet_total_times:
1515061da546Spatrick        total_packet_time = 0.0
1516061da546Spatrick        total_packet_count = 0
1517061da546Spatrick        for key, vvv in packet_total_times.items():
1518061da546Spatrick            # print '  key = (%s) "%s"' % (type(key), key)
1519061da546Spatrick            # print 'value = (%s) %s' % (type(vvv), vvv)
1520061da546Spatrick            # if type(vvv) == 'float':
1521061da546Spatrick            total_packet_time += vvv
1522061da546Spatrick        for key, vvv in packet_counts.items():
1523061da546Spatrick            total_packet_count += vvv
1524061da546Spatrick
1525061da546Spatrick        print('#------------------------------------------------------------')
1526061da546Spatrick        print('# Packet timing summary:')
1527061da546Spatrick        print('# Totals: time = %6f, count = %6d' % (total_packet_time,
1528061da546Spatrick                                                     total_packet_count))
1529061da546Spatrick        print('# Min packet time: time = %6f' % (min_time))
1530061da546Spatrick        print('#------------------------------------------------------------')
1531061da546Spatrick        print('# Packet                   Time (sec)  Percent Count  Latency')
1532061da546Spatrick        print('#------------------------- ----------- ------- ------ -------')
1533061da546Spatrick        if options and options.sort_count:
1534061da546Spatrick            res = sorted(
1535061da546Spatrick                packet_counts,
1536061da546Spatrick                key=packet_counts.__getitem__,
1537061da546Spatrick                reverse=True)
1538061da546Spatrick        else:
1539061da546Spatrick            res = sorted(
1540061da546Spatrick                packet_total_times,
1541061da546Spatrick                key=packet_total_times.__getitem__,
1542061da546Spatrick                reverse=True)
1543061da546Spatrick
1544061da546Spatrick        if last_time > 0.0:
1545061da546Spatrick            for item in res:
1546061da546Spatrick                packet_total_time = packet_total_times[item]
1547061da546Spatrick                packet_percent = (
1548061da546Spatrick                    packet_total_time / total_packet_time) * 100.0
1549061da546Spatrick                packet_count = packet_counts[item]
1550061da546Spatrick                print("  %24s %11.6f  %5.2f%% %6d %9.6f" % (
1551061da546Spatrick                        item, packet_total_time, packet_percent, packet_count,
1552061da546Spatrick                        float(packet_total_time) / float(packet_count)))
1553*f6aab3d8Srobert        if options and options.plot:
1554061da546Spatrick            plot_latencies(packet_times)
1555061da546Spatrick
1556061da546Spatrickif __name__ == '__main__':
1557061da546Spatrick    usage = "usage: gdbremote [options]"
1558061da546Spatrick    description = '''The command disassembles a GDB remote packet log.'''
1559061da546Spatrick    parser = optparse.OptionParser(
1560061da546Spatrick        description=description,
1561061da546Spatrick        prog='gdbremote',
1562061da546Spatrick        usage=usage)
1563061da546Spatrick    parser.add_option(
1564061da546Spatrick        '-v',
1565061da546Spatrick        '--verbose',
1566061da546Spatrick        action='store_true',
1567061da546Spatrick        dest='verbose',
1568061da546Spatrick        help='display verbose debug info',
1569061da546Spatrick        default=False)
1570061da546Spatrick    parser.add_option(
1571061da546Spatrick        '-q',
1572061da546Spatrick        '--quiet',
1573061da546Spatrick        action='store_true',
1574061da546Spatrick        dest='quiet',
1575061da546Spatrick        help='display verbose debug info',
1576061da546Spatrick        default=False)
1577061da546Spatrick    parser.add_option(
1578061da546Spatrick        '-C',
1579061da546Spatrick        '--color',
1580061da546Spatrick        action='store_true',
1581061da546Spatrick        dest='color',
1582061da546Spatrick        help='add terminal colors',
1583061da546Spatrick        default=False)
1584061da546Spatrick    parser.add_option(
1585061da546Spatrick        '-c',
1586061da546Spatrick        '--sort-by-count',
1587061da546Spatrick        action='store_true',
1588061da546Spatrick        dest='sort_count',
1589061da546Spatrick        help='display verbose debug info',
1590061da546Spatrick        default=False)
1591061da546Spatrick    parser.add_option(
1592061da546Spatrick        '--crashlog',
1593061da546Spatrick        type='string',
1594061da546Spatrick        dest='crashlog',
1595061da546Spatrick        help='symbolicate using a darwin crash log file',
1596061da546Spatrick        default=False)
1597061da546Spatrick    try:
1598061da546Spatrick        (options, args) = parser.parse_args(sys.argv[1:])
1599061da546Spatrick    except:
1600061da546Spatrick        print('error: argument error')
1601061da546Spatrick        sys.exit(1)
1602061da546Spatrick
1603061da546Spatrick    options.colors = TerminalColors(options.color)
1604061da546Spatrick    options.symbolicator = None
1605061da546Spatrick    if options.crashlog:
1606061da546Spatrick        import lldb
1607061da546Spatrick        lldb.debugger = lldb.SBDebugger.Create()
1608061da546Spatrick        import lldb.macosx.crashlog
1609061da546Spatrick        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
1610061da546Spatrick        print('%s' % (options.symbolicator))
1611061da546Spatrick
1612061da546Spatrick    # This script is being run from the command line, create a debugger in case we are
1613061da546Spatrick    # going to use any debugger functions in our function.
1614061da546Spatrick    if len(args):
1615061da546Spatrick        for file in args:
1616061da546Spatrick            print('#----------------------------------------------------------------------')
1617061da546Spatrick            print("# GDB remote log file: '%s'" % file)
1618061da546Spatrick            print('#----------------------------------------------------------------------')
1619061da546Spatrick            parse_gdb_log_file(file, options)
1620061da546Spatrick        if options.symbolicator:
1621061da546Spatrick            print('%s' % (options.symbolicator))
1622061da546Spatrick    else:
1623061da546Spatrick        parse_gdb_log(sys.stdin, options)
1624061da546Spatrick
1625*f6aab3d8Srobertdef __lldb_init_module(debugger, internal_dict):
1626061da546Spatrick    # This initializer is being run from LLDB in the embedded command interpreter
1627061da546Spatrick    # Add any commands contained in this module to LLDB
1628*f6aab3d8Srobert    debugger.HandleCommand(
1629*f6aab3d8Srobert        'command script add -o -f gdbremote.start_gdb_log start_gdb_log')
1630*f6aab3d8Srobert    debugger.HandleCommand(
1631*f6aab3d8Srobert        'command script add -o -f gdbremote.stop_gdb_log stop_gdb_log')
1632061da546Spatrick    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')
1633