forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			1632 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			1632 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
#!/usr/bin/python
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# This module will enable GDB remote packet logging when the
 | 
						|
# 'start_gdb_log' command is called with a filename to log to. When the
 | 
						|
# 'stop_gdb_log' command is called, it will disable the logging and
 | 
						|
# print out statistics about how long commands took to execute and also
 | 
						|
# will primnt ou
 | 
						|
# Be sure to add the python path that points to the LLDB shared library.
 | 
						|
#
 | 
						|
# To use this in the embedded python interpreter using "lldb" just
 | 
						|
# import it with the full path using the "command script import"
 | 
						|
# command. This can be done from the LLDB command line:
 | 
						|
#   (lldb) command script import /path/to/gdbremote.py
 | 
						|
# Or it can be added to your ~/.lldbinit file so this module is always
 | 
						|
# available.
 | 
						|
#----------------------------------------------------------------------
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
import binascii
 | 
						|
import subprocess
 | 
						|
import json
 | 
						|
import math
 | 
						|
import optparse
 | 
						|
import os
 | 
						|
import re
 | 
						|
import shlex
 | 
						|
import string
 | 
						|
import sys
 | 
						|
import tempfile
 | 
						|
import xml.etree.ElementTree as ET
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
# Global variables
 | 
						|
#----------------------------------------------------------------------
 | 
						|
g_log_file = ''
 | 
						|
g_byte_order = 'little'
 | 
						|
g_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)')
 | 
						|
g_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)')
 | 
						|
 | 
						|
 | 
						|
class TerminalColors:
 | 
						|
    '''Simple terminal colors class'''
 | 
						|
 | 
						|
    def __init__(self, enabled=True):
 | 
						|
        # TODO: discover terminal type from "file" and disable if
 | 
						|
        # it can't handle the color codes
 | 
						|
        self.enabled = enabled
 | 
						|
 | 
						|
    def reset(self):
 | 
						|
        '''Reset all terminal colors and formatting.'''
 | 
						|
        if self.enabled:
 | 
						|
            return "\x1b[0m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def bold(self, on=True):
 | 
						|
        '''Enable or disable bold depending on the "on" parameter.'''
 | 
						|
        if self.enabled:
 | 
						|
            if on:
 | 
						|
                return "\x1b[1m"
 | 
						|
            else:
 | 
						|
                return "\x1b[22m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def italics(self, on=True):
 | 
						|
        '''Enable or disable italics depending on the "on" parameter.'''
 | 
						|
        if self.enabled:
 | 
						|
            if on:
 | 
						|
                return "\x1b[3m"
 | 
						|
            else:
 | 
						|
                return "\x1b[23m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def underline(self, on=True):
 | 
						|
        '''Enable or disable underline depending on the "on" parameter.'''
 | 
						|
        if self.enabled:
 | 
						|
            if on:
 | 
						|
                return "\x1b[4m"
 | 
						|
            else:
 | 
						|
                return "\x1b[24m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def inverse(self, on=True):
 | 
						|
        '''Enable or disable inverse depending on the "on" parameter.'''
 | 
						|
        if self.enabled:
 | 
						|
            if on:
 | 
						|
                return "\x1b[7m"
 | 
						|
            else:
 | 
						|
                return "\x1b[27m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def strike(self, on=True):
 | 
						|
        '''Enable or disable strike through depending on the "on" parameter.'''
 | 
						|
        if self.enabled:
 | 
						|
            if on:
 | 
						|
                return "\x1b[9m"
 | 
						|
            else:
 | 
						|
                return "\x1b[29m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def black(self, fg=True):
 | 
						|
        '''Set the foreground or background color to black.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[30m"
 | 
						|
            else:
 | 
						|
                return "\x1b[40m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def red(self, fg=True):
 | 
						|
        '''Set the foreground or background color to red.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[31m"
 | 
						|
            else:
 | 
						|
                return "\x1b[41m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def green(self, fg=True):
 | 
						|
        '''Set the foreground or background color to green.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[32m"
 | 
						|
            else:
 | 
						|
                return "\x1b[42m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def yellow(self, fg=True):
 | 
						|
        '''Set the foreground or background color to yellow.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[33m"
 | 
						|
            else:
 | 
						|
                return "\x1b[43m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def blue(self, fg=True):
 | 
						|
        '''Set the foreground or background color to blue.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[34m"
 | 
						|
            else:
 | 
						|
                return "\x1b[44m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def magenta(self, fg=True):
 | 
						|
        '''Set the foreground or background color to magenta.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[35m"
 | 
						|
            else:
 | 
						|
                return "\x1b[45m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def cyan(self, fg=True):
 | 
						|
        '''Set the foreground or background color to cyan.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[36m"
 | 
						|
            else:
 | 
						|
                return "\x1b[46m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def white(self, fg=True):
 | 
						|
        '''Set the foreground or background color to white.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[37m"
 | 
						|
            else:
 | 
						|
                return "\x1b[47m"
 | 
						|
        return ''
 | 
						|
 | 
						|
    def default(self, fg=True):
 | 
						|
        '''Set the foreground or background color to the default.
 | 
						|
        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
 | 
						|
        if self.enabled:
 | 
						|
            if fg:
 | 
						|
                return "\x1b[39m"
 | 
						|
            else:
 | 
						|
                return "\x1b[49m"
 | 
						|
        return ''
 | 
						|
 | 
						|
 | 
						|
def start_gdb_log(debugger, command, result, dict):
 | 
						|
    '''Start logging GDB remote packets by enabling logging with timestamps and
 | 
						|
    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
 | 
						|
    in order to dump out the commands.'''
 | 
						|
    global g_log_file
 | 
						|
    command_args = shlex.split(command)
 | 
						|
    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
 | 
						|
    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
 | 
						|
    be aggregated and displayed.'''
 | 
						|
    parser = optparse.OptionParser(
 | 
						|
        description=description,
 | 
						|
        prog='start_gdb_log',
 | 
						|
        usage=usage)
 | 
						|
    parser.add_option(
 | 
						|
        '-v',
 | 
						|
        '--verbose',
 | 
						|
        action='store_true',
 | 
						|
        dest='verbose',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    try:
 | 
						|
        (options, args) = parser.parse_args(command_args)
 | 
						|
    except:
 | 
						|
        return
 | 
						|
 | 
						|
    if g_log_file:
 | 
						|
        result.PutCString(
 | 
						|
            'error: logging is already in progress with file "%s"' %
 | 
						|
            g_log_file)
 | 
						|
    else:
 | 
						|
        args_len = len(args)
 | 
						|
        if args_len == 0:
 | 
						|
            g_log_file = tempfile.mktemp()
 | 
						|
        elif len(args) == 1:
 | 
						|
            g_log_file = args[0]
 | 
						|
 | 
						|
        if g_log_file:
 | 
						|
            debugger.HandleCommand(
 | 
						|
                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
 | 
						|
                g_log_file)
 | 
						|
            result.PutCString(
 | 
						|
                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
 | 
						|
                g_log_file)
 | 
						|
            return
 | 
						|
 | 
						|
        result.PutCString('error: invalid log file path')
 | 
						|
    result.PutCString(usage)
 | 
						|
 | 
						|
 | 
						|
def stop_gdb_log(debugger, command, result, dict):
 | 
						|
    '''Stop logging GDB remote packets to the file that was specified in a call
 | 
						|
    to "start_gdb_log" and normalize the timestamps to be relative to the first
 | 
						|
    timestamp in the log file. Also print out statistics for how long each
 | 
						|
    command took to allow performance bottlenecks to be determined.'''
 | 
						|
    global g_log_file
 | 
						|
    # Any commands whose names might be followed by more valid C identifier
 | 
						|
    # characters must be listed here
 | 
						|
    command_args = shlex.split(command)
 | 
						|
    usage = "usage: stop_gdb_log [options]"
 | 
						|
    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.'''
 | 
						|
    parser = optparse.OptionParser(
 | 
						|
        description=description,
 | 
						|
        prog='stop_gdb_log',
 | 
						|
        usage=usage)
 | 
						|
    parser.add_option(
 | 
						|
        '-v',
 | 
						|
        '--verbose',
 | 
						|
        action='store_true',
 | 
						|
        dest='verbose',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-q',
 | 
						|
        '--quiet',
 | 
						|
        action='store_true',
 | 
						|
        dest='quiet',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-C',
 | 
						|
        '--color',
 | 
						|
        action='store_true',
 | 
						|
        dest='color',
 | 
						|
        help='add terminal colors',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-c',
 | 
						|
        '--sort-by-count',
 | 
						|
        action='store_true',
 | 
						|
        dest='sort_count',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-s',
 | 
						|
        '--symbolicate',
 | 
						|
        action='store_true',
 | 
						|
        dest='symbolicate',
 | 
						|
        help='symbolicate addresses in log using current "lldb.target"',
 | 
						|
        default=False)
 | 
						|
    try:
 | 
						|
        (options, args) = parser.parse_args(command_args)
 | 
						|
    except:
 | 
						|
        return
 | 
						|
    options.colors = TerminalColors(options.color)
 | 
						|
    options.symbolicator = None
 | 
						|
    if options.symbolicate:
 | 
						|
        if lldb.target:
 | 
						|
            import lldb.utils.symbolication
 | 
						|
            options.symbolicator = lldb.utils.symbolication.Symbolicator()
 | 
						|
            options.symbolicator.target = lldb.target
 | 
						|
        else:
 | 
						|
            print("error: can't symbolicate without a target")
 | 
						|
 | 
						|
    if not g_log_file:
 | 
						|
        result.PutCString(
 | 
						|
            'error: logging must have been previously enabled with a call to "stop_gdb_log"')
 | 
						|
    elif os.path.exists(g_log_file):
 | 
						|
        if len(args) == 0:
 | 
						|
            debugger.HandleCommand('log disable gdb-remote packets')
 | 
						|
            result.PutCString(
 | 
						|
                "GDB packet logging disabled. Logged packets are in '%s'" %
 | 
						|
                g_log_file)
 | 
						|
            parse_gdb_log_file(g_log_file, options)
 | 
						|
        else:
 | 
						|
            result.PutCString(usage)
 | 
						|
    else:
 | 
						|
        print('error: the GDB packet log file "%s" does not exist' % g_log_file)
 | 
						|
 | 
						|
 | 
						|
def is_hex_byte(str):
 | 
						|
    if len(str) == 2:
 | 
						|
        return str[0] in string.hexdigits and str[1] in string.hexdigits
 | 
						|
    return False
 | 
						|
 | 
						|
def get_hex_string_if_all_printable(str):
 | 
						|
    try:
 | 
						|
        s = binascii.unhexlify(str).decode()
 | 
						|
        if all(c in string.printable for c in s):
 | 
						|
            return s
 | 
						|
    except (TypeError, binascii.Error, UnicodeDecodeError):
 | 
						|
        pass
 | 
						|
    return None
 | 
						|
 | 
						|
# global register info list
 | 
						|
g_register_infos = list()
 | 
						|
g_max_register_info_name_len = 0
 | 
						|
 | 
						|
 | 
						|
class RegisterInfo:
 | 
						|
    """Class that represents register information"""
 | 
						|
 | 
						|
    def __init__(self, kvp):
 | 
						|
        self.info = dict()
 | 
						|
        for kv in kvp:
 | 
						|
            key = kv[0]
 | 
						|
            value = kv[1]
 | 
						|
            self.info[key] = value
 | 
						|
 | 
						|
    def name(self):
 | 
						|
        '''Get the name of the register.'''
 | 
						|
        if self.info and 'name' in self.info:
 | 
						|
            return self.info['name']
 | 
						|
        return None
 | 
						|
 | 
						|
    def bit_size(self):
 | 
						|
        '''Get the size in bits of the register.'''
 | 
						|
        if self.info and 'bitsize' in self.info:
 | 
						|
            return int(self.info['bitsize'])
 | 
						|
        return 0
 | 
						|
 | 
						|
    def byte_size(self):
 | 
						|
        '''Get the size in bytes of the register.'''
 | 
						|
        return self.bit_size() / 8
 | 
						|
 | 
						|
    def get_value_from_hex_string(self, hex_str):
 | 
						|
        '''Dump the register value given a native byte order encoded hex ASCII byte string.'''
 | 
						|
        encoding = self.info['encoding']
 | 
						|
        bit_size = self.bit_size()
 | 
						|
        packet = Packet(hex_str)
 | 
						|
        if encoding == 'uint':
 | 
						|
            uval = packet.get_hex_uint(g_byte_order)
 | 
						|
            if bit_size == 8:
 | 
						|
                return '0x%2.2x' % (uval)
 | 
						|
            elif bit_size == 16:
 | 
						|
                return '0x%4.4x' % (uval)
 | 
						|
            elif bit_size == 32:
 | 
						|
                return '0x%8.8x' % (uval)
 | 
						|
            elif bit_size == 64:
 | 
						|
                return '0x%16.16x' % (uval)
 | 
						|
        bytes = list()
 | 
						|
        uval = packet.get_hex_uint8()
 | 
						|
        while uval is not None:
 | 
						|
            bytes.append(uval)
 | 
						|
            uval = packet.get_hex_uint8()
 | 
						|
        value_str = '0x'
 | 
						|
        if g_byte_order == 'little':
 | 
						|
            bytes.reverse()
 | 
						|
        for byte in bytes:
 | 
						|
            value_str += '%2.2x' % byte
 | 
						|
        return '%s' % (value_str)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        '''Dump the register info key/value pairs'''
 | 
						|
        s = ''
 | 
						|
        for key in self.info.keys():
 | 
						|
            if s:
 | 
						|
                s += ', '
 | 
						|
            s += "%s=%s " % (key, self.info[key])
 | 
						|
        return s
 | 
						|
 | 
						|
 | 
						|
class Packet:
 | 
						|
    """Class that represents a packet that contains string data"""
 | 
						|
 | 
						|
    def __init__(self, packet_str):
 | 
						|
        self.str = packet_str
 | 
						|
 | 
						|
    def peek_char(self):
 | 
						|
        ch = 0
 | 
						|
        if self.str:
 | 
						|
            ch = self.str[0]
 | 
						|
        return ch
 | 
						|
 | 
						|
    def get_char(self):
 | 
						|
        ch = 0
 | 
						|
        if self.str:
 | 
						|
            ch = self.str[0]
 | 
						|
            self.str = self.str[1:]
 | 
						|
        return ch
 | 
						|
 | 
						|
    def skip_exact_string(self, s):
 | 
						|
        if self.str and self.str.startswith(s):
 | 
						|
            self.str = self.str[len(s):]
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
 | 
						|
    def get_thread_id(self, fail_value=-1):
 | 
						|
        match = g_number_regex.match(self.str)
 | 
						|
        if match:
 | 
						|
            number_str = match.group(1)
 | 
						|
            self.str = self.str[len(number_str):]
 | 
						|
            return int(number_str, 0)
 | 
						|
        else:
 | 
						|
            return fail_value
 | 
						|
 | 
						|
    def get_hex_uint8(self):
 | 
						|
        if self.str and len(self.str) >= 2 and self.str[
 | 
						|
                0] in string.hexdigits and self.str[1] in string.hexdigits:
 | 
						|
            uval = int(self.str[0:2], 16)
 | 
						|
            self.str = self.str[2:]
 | 
						|
            return uval
 | 
						|
        return None
 | 
						|
 | 
						|
    def get_hex_uint16(self, byte_order):
 | 
						|
        uval = 0
 | 
						|
        if byte_order == 'big':
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
        else:
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
        return uval
 | 
						|
 | 
						|
    def get_hex_uint32(self, byte_order):
 | 
						|
        uval = 0
 | 
						|
        if byte_order == 'big':
 | 
						|
            uval |= self.get_hex_uint8() << 24
 | 
						|
            uval |= self.get_hex_uint8() << 16
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
        else:
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
            uval |= self.get_hex_uint8() << 16
 | 
						|
            uval |= self.get_hex_uint8() << 24
 | 
						|
        return uval
 | 
						|
 | 
						|
    def get_hex_uint64(self, byte_order):
 | 
						|
        uval = 0
 | 
						|
        if byte_order == 'big':
 | 
						|
            uval |= self.get_hex_uint8() << 56
 | 
						|
            uval |= self.get_hex_uint8() << 48
 | 
						|
            uval |= self.get_hex_uint8() << 40
 | 
						|
            uval |= self.get_hex_uint8() << 32
 | 
						|
            uval |= self.get_hex_uint8() << 24
 | 
						|
            uval |= self.get_hex_uint8() << 16
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
        else:
 | 
						|
            uval |= self.get_hex_uint8()
 | 
						|
            uval |= self.get_hex_uint8() << 8
 | 
						|
            uval |= self.get_hex_uint8() << 16
 | 
						|
            uval |= self.get_hex_uint8() << 24
 | 
						|
            uval |= self.get_hex_uint8() << 32
 | 
						|
            uval |= self.get_hex_uint8() << 40
 | 
						|
            uval |= self.get_hex_uint8() << 48
 | 
						|
            uval |= self.get_hex_uint8() << 56
 | 
						|
        return uval
 | 
						|
 | 
						|
    def get_number(self, fail_value=-1):
 | 
						|
        '''Get a number from the packet. The number must be in big endian format and should be parsed
 | 
						|
        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
 | 
						|
        [1-9] means decimal, etc)'''
 | 
						|
        match = g_number_regex.match(self.str)
 | 
						|
        if match:
 | 
						|
            number_str = match.group(1)
 | 
						|
            self.str = self.str[len(number_str):]
 | 
						|
            return int(number_str, 0)
 | 
						|
        else:
 | 
						|
            return fail_value
 | 
						|
 | 
						|
    def get_hex_ascii_str(self, n=0):
 | 
						|
        hex_chars = self.get_hex_chars(n)
 | 
						|
        if hex_chars:
 | 
						|
            return binascii.unhexlify(hex_chars)
 | 
						|
        else:
 | 
						|
            return None
 | 
						|
 | 
						|
    def get_hex_chars(self, n=0):
 | 
						|
        str_len = len(self.str)
 | 
						|
        if n == 0:
 | 
						|
            # n was zero, so we need to determine all hex chars and
 | 
						|
            # stop when we hit the end of the string of a non-hex character
 | 
						|
            while n < str_len and self.str[n] in string.hexdigits:
 | 
						|
                n = n + 1
 | 
						|
        else:
 | 
						|
            if n > str_len:
 | 
						|
                return None  # Not enough chars
 | 
						|
            # Verify all chars are hex if a length was specified
 | 
						|
            for i in range(n):
 | 
						|
                if self.str[i] not in string.hexdigits:
 | 
						|
                    return None  # Not all hex digits
 | 
						|
        if n == 0:
 | 
						|
            return None
 | 
						|
        hex_str = self.str[0:n]
 | 
						|
        self.str = self.str[n:]
 | 
						|
        return hex_str
 | 
						|
 | 
						|
    def get_hex_uint(self, byte_order, n=0):
 | 
						|
        if byte_order == 'big':
 | 
						|
            hex_str = self.get_hex_chars(n)
 | 
						|
            if hex_str is None:
 | 
						|
                return None
 | 
						|
            return int(hex_str, 16)
 | 
						|
        else:
 | 
						|
            uval = self.get_hex_uint8()
 | 
						|
            if uval is None:
 | 
						|
                return None
 | 
						|
            uval_result = 0
 | 
						|
            shift = 0
 | 
						|
            while uval is not None:
 | 
						|
                uval_result |= (uval << shift)
 | 
						|
                shift += 8
 | 
						|
                uval = self.get_hex_uint8()
 | 
						|
            return uval_result
 | 
						|
 | 
						|
    def get_key_value_pairs(self):
 | 
						|
        kvp = list()
 | 
						|
        if ';' in self.str:
 | 
						|
            key_value_pairs = self.str.split(';')
 | 
						|
            for key_value_pair in key_value_pairs:
 | 
						|
                if len(key_value_pair):
 | 
						|
                    kvp.append(key_value_pair.split(':', 1))
 | 
						|
        return kvp
 | 
						|
 | 
						|
    def split(self, ch):
 | 
						|
        return string.split(self.str, ch)
 | 
						|
 | 
						|
    def split_hex(self, ch, byte_order):
 | 
						|
        hex_values = list()
 | 
						|
        strings = string.split(self.str, ch)
 | 
						|
        for str in strings:
 | 
						|
            hex_values.append(Packet(str).get_hex_uint(byte_order))
 | 
						|
        return hex_values
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.str
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        return len(self.str)
 | 
						|
 | 
						|
g_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);')
 | 
						|
 | 
						|
 | 
						|
def get_thread_from_thread_suffix(str):
 | 
						|
    if str:
 | 
						|
        match = g_thread_suffix_regex.match(str)
 | 
						|
        if match:
 | 
						|
            return int(match.group(1), 16)
 | 
						|
    return None
 | 
						|
 | 
						|
 | 
						|
def cmd_qThreadStopInfo(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    tid = packet.get_hex_uint('big')
 | 
						|
    print("get_thread_stop_info  (tid = 0x%x)" % (tid))
 | 
						|
 | 
						|
 | 
						|
def cmd_stop_reply(options, cmd, args):
 | 
						|
    print("get_last_stop_info()")
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_stop_reply(options, cmd, cmd_args, rsp):
 | 
						|
    global g_byte_order
 | 
						|
    packet = Packet(rsp)
 | 
						|
    stop_type = packet.get_char()
 | 
						|
    if stop_type == 'T' or stop_type == 'S':
 | 
						|
        signo = packet.get_hex_uint8()
 | 
						|
        key_value_pairs = packet.get_key_value_pairs()
 | 
						|
        for key_value_pair in key_value_pairs:
 | 
						|
            key = key_value_pair[0]
 | 
						|
            if is_hex_byte(key):
 | 
						|
                reg_num = Packet(key).get_hex_uint8()
 | 
						|
                if reg_num < len(g_register_infos):
 | 
						|
                    reg_info = g_register_infos[reg_num]
 | 
						|
                    key_value_pair[0] = reg_info.name()
 | 
						|
                    key_value_pair[1] = reg_info.get_value_from_hex_string(
 | 
						|
                        key_value_pair[1])
 | 
						|
            elif key == 'jthreads' or key == 'jstopinfo':
 | 
						|
                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
 | 
						|
        key_value_pairs.insert(0, ['signal', signo])
 | 
						|
        print('stop_reply():')
 | 
						|
        dump_key_value_pairs(key_value_pairs)
 | 
						|
    elif stop_type == 'W':
 | 
						|
        exit_status = packet.get_hex_uint8()
 | 
						|
        print('stop_reply(): exit (status=%i)' % exit_status)
 | 
						|
    elif stop_type == 'O':
 | 
						|
        print('stop_reply(): stdout = "%s"' % packet.str)
 | 
						|
 | 
						|
 | 
						|
def cmd_unknown_packet(options, cmd, args):
 | 
						|
    if args:
 | 
						|
        print("cmd: %s, args: %s", cmd, args)
 | 
						|
    else:
 | 
						|
        print("cmd: %s", cmd)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_qSymbol(options, cmd, args):
 | 
						|
    if args == ':':
 | 
						|
        print('ready to serve symbols')
 | 
						|
    else:
 | 
						|
        packet = Packet(args)
 | 
						|
        symbol_addr = packet.get_hex_uint('big')
 | 
						|
        if symbol_addr is None:
 | 
						|
            if packet.skip_exact_string(':'):
 | 
						|
                symbol_name = packet.get_hex_ascii_str()
 | 
						|
                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))
 | 
						|
            else:
 | 
						|
                print('error: bad command format')
 | 
						|
        else:
 | 
						|
            if packet.skip_exact_string(':'):
 | 
						|
                symbol_name = packet.get_hex_ascii_str()
 | 
						|
                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))
 | 
						|
            else:
 | 
						|
                print('error: bad command format')
 | 
						|
 | 
						|
def cmd_QSetWithHexString(options, cmd, args):
 | 
						|
    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))
 | 
						|
 | 
						|
def cmd_QSetWithString(options, cmd, args):
 | 
						|
    print('%s("%s")' % (cmd[:-1], args))
 | 
						|
 | 
						|
def cmd_QSetWithUnsigned(options, cmd, args):
 | 
						|
    print('%s(%i)' % (cmd[:-1], int(args)))
 | 
						|
 | 
						|
def rsp_qSymbol(options, cmd, cmd_args, rsp):
 | 
						|
    if len(rsp) == 0:
 | 
						|
        print("Unsupported")
 | 
						|
    else:
 | 
						|
        if rsp == "OK":
 | 
						|
            print("No more symbols to lookup")
 | 
						|
        else:
 | 
						|
            packet = Packet(rsp)
 | 
						|
            if packet.skip_exact_string("qSymbol:"):
 | 
						|
                symbol_name = packet.get_hex_ascii_str()
 | 
						|
                print('lookup_symbol("%s")' % (symbol_name))
 | 
						|
            else:
 | 
						|
                print('error: response string should start with "qSymbol:": respnse is "%s"' % (rsp))
 | 
						|
 | 
						|
 | 
						|
def cmd_qXfer(options, cmd, args):
 | 
						|
    # $qXfer:features:read:target.xml:0,1ffff#14
 | 
						|
    print("read target special data %s" % (args))
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def rsp_qXfer(options, cmd, cmd_args, rsp):
 | 
						|
    data = cmd_args.split(':')
 | 
						|
    if data[0] == 'features':
 | 
						|
        if data[1] == 'read':
 | 
						|
            filename, extension = os.path.splitext(data[2])
 | 
						|
            if extension == '.xml':
 | 
						|
                response = Packet(rsp)
 | 
						|
                xml_string = response.get_hex_ascii_str()
 | 
						|
                if xml_string:
 | 
						|
                    ch = xml_string[0]
 | 
						|
                    if ch == 'l':
 | 
						|
                        xml_string = xml_string[1:]
 | 
						|
                        xml_root = ET.fromstring(xml_string)
 | 
						|
                        for reg_element in xml_root.findall("./feature/reg"):
 | 
						|
                            if not 'value_regnums' in reg_element.attrib:
 | 
						|
                                reg_info = RegisterInfo([])
 | 
						|
                                if 'name' in reg_element.attrib:
 | 
						|
                                    reg_info.info[
 | 
						|
                                        'name'] = reg_element.attrib['name']
 | 
						|
                                else:
 | 
						|
                                    reg_info.info['name'] = 'unspecified'
 | 
						|
                                if 'encoding' in reg_element.attrib:
 | 
						|
                                    reg_info.info['encoding'] = reg_element.attrib[
 | 
						|
                                        'encoding']
 | 
						|
                                else:
 | 
						|
                                    reg_info.info['encoding'] = 'uint'
 | 
						|
                                if 'offset' in reg_element.attrib:
 | 
						|
                                    reg_info.info[
 | 
						|
                                        'offset'] = reg_element.attrib['offset']
 | 
						|
                                if 'bitsize' in reg_element.attrib:
 | 
						|
                                    reg_info.info[
 | 
						|
                                        'bitsize'] = reg_element.attrib['bitsize']
 | 
						|
                                g_register_infos.append(reg_info)
 | 
						|
                        print('XML for "%s":' % (data[2]))
 | 
						|
                        ET.dump(xml_root)
 | 
						|
 | 
						|
 | 
						|
def cmd_A(options, cmd, args):
 | 
						|
    print('launch process:')
 | 
						|
    packet = Packet(args)
 | 
						|
    while True:
 | 
						|
        arg_len = packet.get_number()
 | 
						|
        if arg_len == -1:
 | 
						|
            break
 | 
						|
        if not packet.skip_exact_string(','):
 | 
						|
            break
 | 
						|
        arg_idx = packet.get_number()
 | 
						|
        if arg_idx == -1:
 | 
						|
            break
 | 
						|
        if not packet.skip_exact_string(','):
 | 
						|
            break
 | 
						|
        arg_value = packet.get_hex_ascii_str(arg_len)
 | 
						|
        print('argv[%u] = "%s"' % (arg_idx, arg_value))
 | 
						|
 | 
						|
 | 
						|
def cmd_qC(options, cmd, args):
 | 
						|
    print("query_current_thread_id()")
 | 
						|
 | 
						|
 | 
						|
def rsp_qC(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(rsp)
 | 
						|
    if packet.skip_exact_string("QC"):
 | 
						|
        tid = packet.get_thread_id()
 | 
						|
        print("current_thread_id = %#x" % (tid))
 | 
						|
    else:
 | 
						|
        print("current_thread_id = old thread ID")
 | 
						|
 | 
						|
 | 
						|
def cmd_query_packet(options, cmd, args):
 | 
						|
    if args:
 | 
						|
        print("%s%s" % (cmd, args))
 | 
						|
    else:
 | 
						|
        print("%s" % (cmd))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_ok_error(rsp):
 | 
						|
    print("rsp: ", rsp)
 | 
						|
 | 
						|
 | 
						|
def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
 | 
						|
    if rsp == 'OK':
 | 
						|
        print("%s%s is supported" % (cmd, cmd_args))
 | 
						|
    elif rsp == '':
 | 
						|
        print("%s%s is not supported" % (cmd, cmd_args))
 | 
						|
    else:
 | 
						|
        print("%s%s -> %s" % (cmd, cmd_args, rsp))
 | 
						|
 | 
						|
 | 
						|
def rsp_ok_means_success(options, cmd, cmd_args, rsp):
 | 
						|
    if rsp == 'OK':
 | 
						|
        print("success")
 | 
						|
    elif rsp == '':
 | 
						|
        print("%s%s is not supported" % (cmd, cmd_args))
 | 
						|
    else:
 | 
						|
        print("%s%s -> %s" % (cmd, cmd_args, rsp))
 | 
						|
 | 
						|
 | 
						|
def dump_key_value_pairs(key_value_pairs):
 | 
						|
    max_key_len = 0
 | 
						|
    for key_value_pair in key_value_pairs:
 | 
						|
        key_len = len(key_value_pair[0])
 | 
						|
        if max_key_len < key_len:
 | 
						|
            max_key_len = key_len
 | 
						|
    for key_value_pair in key_value_pairs:
 | 
						|
        key = key_value_pair[0]
 | 
						|
        value = key_value_pair[1]
 | 
						|
        unhex_value = get_hex_string_if_all_printable(value)
 | 
						|
        if unhex_value:
 | 
						|
            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))
 | 
						|
        else:
 | 
						|
            print("%*s = %s" % (max_key_len, key, value))
 | 
						|
 | 
						|
 | 
						|
def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
 | 
						|
    if rsp:
 | 
						|
        print('%s response:' % (cmd))
 | 
						|
        packet = Packet(rsp)
 | 
						|
        key_value_pairs = packet.get_key_value_pairs()
 | 
						|
        dump_key_value_pairs(key_value_pairs)
 | 
						|
    else:
 | 
						|
        print("not supported")
 | 
						|
 | 
						|
 | 
						|
def cmd_c(options, cmd, args):
 | 
						|
    print("continue()")
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_s(options, cmd, args):
 | 
						|
    print("step()")
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_qSpeedTest(options, cmd, args):
 | 
						|
    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))
 | 
						|
 | 
						|
 | 
						|
def rsp_qSpeedTest(options, cmd, cmd_args, rsp):
 | 
						|
    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))
 | 
						|
 | 
						|
 | 
						|
def cmd_vCont(options, cmd, args):
 | 
						|
    if args == '?':
 | 
						|
        print("%s: get supported extended continue modes" % (cmd))
 | 
						|
    else:
 | 
						|
        got_other_threads = 0
 | 
						|
        s = ''
 | 
						|
        for thread_action in args[1:].split(';'):
 | 
						|
            (short_action, thread) = thread_action.split(':', 1)
 | 
						|
            tid = int(thread, 16)
 | 
						|
            if short_action == 'c':
 | 
						|
                action = 'continue'
 | 
						|
            elif short_action == 's':
 | 
						|
                action = 'step'
 | 
						|
            elif short_action[0] == 'C':
 | 
						|
                action = 'continue with signal 0x%s' % (short_action[1:])
 | 
						|
            elif short_action == 'S':
 | 
						|
                action = 'step with signal 0x%s' % (short_action[1:])
 | 
						|
            else:
 | 
						|
                action = short_action
 | 
						|
            if s:
 | 
						|
                s += ', '
 | 
						|
            if tid == -1:
 | 
						|
                got_other_threads = 1
 | 
						|
                s += 'other-threads:'
 | 
						|
            else:
 | 
						|
                s += 'thread 0x%4.4x: %s' % (tid, action)
 | 
						|
        if got_other_threads:
 | 
						|
            print("extended_continue (%s)" % (s))
 | 
						|
        else:
 | 
						|
            print("extended_continue (%s, other-threads: suspend)" % (s))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_vCont(options, cmd, cmd_args, rsp):
 | 
						|
    if cmd_args == '?':
 | 
						|
        # Skip the leading 'vCont;'
 | 
						|
        rsp = rsp[6:]
 | 
						|
        modes = rsp.split(';')
 | 
						|
        s = "%s: supported extended continue modes include: " % (cmd)
 | 
						|
 | 
						|
        for i, mode in enumerate(modes):
 | 
						|
            if i:
 | 
						|
                s += ', '
 | 
						|
            if mode == 'c':
 | 
						|
                s += 'continue'
 | 
						|
            elif mode == 'C':
 | 
						|
                s += 'continue with signal'
 | 
						|
            elif mode == 's':
 | 
						|
                s += 'step'
 | 
						|
            elif mode == 'S':
 | 
						|
                s += 'step with signal'
 | 
						|
            elif mode == 't':
 | 
						|
                s += 'stop'
 | 
						|
            # else:
 | 
						|
            #     s += 'unrecognized vCont mode: ', str(mode)
 | 
						|
        print(s)
 | 
						|
    elif rsp:
 | 
						|
        if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
 | 
						|
            rsp_stop_reply(options, cmd, cmd_args, rsp)
 | 
						|
            return
 | 
						|
        if rsp[0] == 'O':
 | 
						|
            print("stdout: %s" % (rsp))
 | 
						|
            return
 | 
						|
    else:
 | 
						|
        print("not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp))
 | 
						|
 | 
						|
 | 
						|
def cmd_vAttach(options, cmd, args):
 | 
						|
    (extra_command, args) = string.split(args, ';')
 | 
						|
    if extra_command:
 | 
						|
        print("%s%s(%s)" % (cmd, extra_command, args))
 | 
						|
    else:
 | 
						|
        print("attach(pid = %u)" % int(args, 16))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_qRegisterInfo(options, cmd, args):
 | 
						|
    print('query_register_info(reg_num=%i)' % (int(args, 16)))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
 | 
						|
    global g_max_register_info_name_len
 | 
						|
    print('query_register_info(reg_num=%i):' % (int(cmd_args, 16)), end=' ')
 | 
						|
    if len(rsp) == 3 and rsp[0] == 'E':
 | 
						|
        g_max_register_info_name_len = 0
 | 
						|
        for reg_info in g_register_infos:
 | 
						|
            name_len = len(reg_info.name())
 | 
						|
            if g_max_register_info_name_len < name_len:
 | 
						|
                g_max_register_info_name_len = name_len
 | 
						|
        print(' DONE')
 | 
						|
    else:
 | 
						|
        packet = Packet(rsp)
 | 
						|
        reg_info = RegisterInfo(packet.get_key_value_pairs())
 | 
						|
        g_register_infos.append(reg_info)
 | 
						|
        print(reg_info)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_qThreadInfo(options, cmd, args):
 | 
						|
    if cmd == 'qfThreadInfo':
 | 
						|
        query_type = 'first'
 | 
						|
    else:
 | 
						|
        query_type = 'subsequent'
 | 
						|
    print('get_current_thread_list(type=%s)' % (query_type))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(rsp)
 | 
						|
    response_type = packet.get_char()
 | 
						|
    if response_type == 'm':
 | 
						|
        tids = packet.split_hex(';', 'big')
 | 
						|
        for i, tid in enumerate(tids):
 | 
						|
            if i:
 | 
						|
                print(',', end=' ')
 | 
						|
            print('0x%x' % (tid), end=' ')
 | 
						|
        print()
 | 
						|
    elif response_type == 'l':
 | 
						|
        print('END')
 | 
						|
 | 
						|
 | 
						|
def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
 | 
						|
    if rsp == '':
 | 
						|
        print("%s%s is not supported" % (cmd, cmd_args))
 | 
						|
    else:
 | 
						|
        packet = Packet(rsp)
 | 
						|
        uval = packet.get_hex_uint('big')
 | 
						|
        print('%s: 0x%x' % (cmd, uval))
 | 
						|
 | 
						|
 | 
						|
def cmd_read_mem_bin(options, cmd, args):
 | 
						|
    # x0x7fff5fc39200,0x200
 | 
						|
    packet = Packet(args)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    comma = packet.get_char()
 | 
						|
    size = packet.get_hex_uint('big')
 | 
						|
    print('binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(cmd_args)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    comma = packet.get_char()
 | 
						|
    size = packet.get_hex_uint('big')
 | 
						|
    print('memory:')
 | 
						|
    if size > 0:
 | 
						|
        dump_hex_memory_buffer(addr, rsp)
 | 
						|
 | 
						|
 | 
						|
def cmd_read_memory(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    comma = packet.get_char()
 | 
						|
    size = packet.get_hex_uint('big')
 | 
						|
    print('read_memory (addr = 0x%16.16x, size = %u)' % (addr, size))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def dump_hex_memory_buffer(addr, hex_byte_str):
 | 
						|
    packet = Packet(hex_byte_str)
 | 
						|
    idx = 0
 | 
						|
    ascii = ''
 | 
						|
    uval = packet.get_hex_uint8()
 | 
						|
    while uval is not None:
 | 
						|
        if ((idx % 16) == 0):
 | 
						|
            if ascii:
 | 
						|
                print('  ', ascii)
 | 
						|
                ascii = ''
 | 
						|
            print('0x%x:' % (addr + idx), end=' ')
 | 
						|
        print('%2.2x' % (uval), end=' ')
 | 
						|
        if 0x20 <= uval and uval < 0x7f:
 | 
						|
            ascii += '%c' % uval
 | 
						|
        else:
 | 
						|
            ascii += '.'
 | 
						|
        uval = packet.get_hex_uint8()
 | 
						|
        idx = idx + 1
 | 
						|
    if ascii:
 | 
						|
        print('  ', ascii)
 | 
						|
        ascii = ''
 | 
						|
 | 
						|
 | 
						|
def cmd_write_memory(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    if packet.get_char() != ',':
 | 
						|
        print('error: invalid write memory command (missing comma after address)')
 | 
						|
        return
 | 
						|
    size = packet.get_hex_uint('big')
 | 
						|
    if packet.get_char() != ':':
 | 
						|
        print('error: invalid write memory command (missing colon after size)')
 | 
						|
        return
 | 
						|
    print('write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size))
 | 
						|
    dump_hex_memory_buffer(addr, packet.str)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_alloc_memory(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    byte_size = packet.get_hex_uint('big')
 | 
						|
    if packet.get_char() != ',':
 | 
						|
        print('error: invalid allocate memory command (missing comma after address)')
 | 
						|
        return
 | 
						|
    print('allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_alloc_memory(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(rsp)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    print('addr = 0x%x' % addr)
 | 
						|
 | 
						|
 | 
						|
def cmd_dealloc_memory(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    if packet.get_char() != ',':
 | 
						|
        print('error: invalid allocate memory command (missing comma after address)')
 | 
						|
    else:
 | 
						|
        print('deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_memory_bytes(options, cmd, cmd_args, rsp):
 | 
						|
    addr = Packet(cmd_args).get_hex_uint('big')
 | 
						|
    dump_hex_memory_buffer(addr, rsp)
 | 
						|
 | 
						|
 | 
						|
def get_register_name_equal_value(options, reg_num, hex_value_str):
 | 
						|
    if reg_num < len(g_register_infos):
 | 
						|
        reg_info = g_register_infos[reg_num]
 | 
						|
        value_str = reg_info.get_value_from_hex_string(hex_value_str)
 | 
						|
        s = reg_info.name() + ' = '
 | 
						|
        if options.symbolicator:
 | 
						|
            symbolicated_addresses = options.symbolicator.symbolicate(
 | 
						|
                int(value_str, 0))
 | 
						|
            if symbolicated_addresses:
 | 
						|
                s += options.colors.magenta()
 | 
						|
                s += '%s' % symbolicated_addresses[0]
 | 
						|
                s += options.colors.reset()
 | 
						|
                return s
 | 
						|
        s += value_str
 | 
						|
        return s
 | 
						|
    else:
 | 
						|
        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
 | 
						|
        return 'reg(%u) = 0x%x' % (reg_num, reg_value)
 | 
						|
 | 
						|
 | 
						|
def cmd_read_one_reg(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    reg_num = packet.get_hex_uint('big')
 | 
						|
    tid = get_thread_from_thread_suffix(packet.str)
 | 
						|
    name = None
 | 
						|
    if reg_num < len(g_register_infos):
 | 
						|
        name = g_register_infos[reg_num].name()
 | 
						|
    if packet.str:
 | 
						|
        packet.get_char()  # skip ;
 | 
						|
        thread_info = packet.get_key_value_pairs()
 | 
						|
        tid = int(thread_info[0][1], 16)
 | 
						|
    s = 'read_register (reg_num=%u' % reg_num
 | 
						|
    if name:
 | 
						|
        s += ' (%s)' % (name)
 | 
						|
    if tid is not None:
 | 
						|
        s += ', tid = 0x%4.4x' % (tid)
 | 
						|
    s += ')'
 | 
						|
    print(s)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_read_one_reg(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(cmd_args)
 | 
						|
    reg_num = packet.get_hex_uint('big')
 | 
						|
    print(get_register_name_equal_value(options, reg_num, rsp))
 | 
						|
 | 
						|
 | 
						|
def cmd_write_one_reg(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    reg_num = packet.get_hex_uint('big')
 | 
						|
    if packet.get_char() != '=':
 | 
						|
        print('error: invalid register write packet')
 | 
						|
    else:
 | 
						|
        name = None
 | 
						|
        hex_value_str = packet.get_hex_chars()
 | 
						|
        tid = get_thread_from_thread_suffix(packet.str)
 | 
						|
        s = 'write_register (reg_num=%u' % reg_num
 | 
						|
        if name:
 | 
						|
            s += ' (%s)' % (name)
 | 
						|
        s += ', value = '
 | 
						|
        s += get_register_name_equal_value(options, reg_num, hex_value_str)
 | 
						|
        if tid is not None:
 | 
						|
            s += ', tid = 0x%4.4x' % (tid)
 | 
						|
        s += ')'
 | 
						|
        print(s)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def dump_all_regs(packet):
 | 
						|
    for reg_info in g_register_infos:
 | 
						|
        nibble_size = reg_info.bit_size() / 4
 | 
						|
        hex_value_str = packet.get_hex_chars(nibble_size)
 | 
						|
        if hex_value_str is not None:
 | 
						|
            value = reg_info.get_value_from_hex_string(hex_value_str)
 | 
						|
            print('%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value))
 | 
						|
        else:
 | 
						|
            return
 | 
						|
 | 
						|
 | 
						|
def cmd_read_all_regs(cmd, cmd_args):
 | 
						|
    packet = Packet(cmd_args)
 | 
						|
    packet.get_char()  # toss the 'g' command character
 | 
						|
    tid = get_thread_from_thread_suffix(packet.str)
 | 
						|
    if tid is not None:
 | 
						|
        print('read_all_register(thread = 0x%4.4x)' % tid)
 | 
						|
    else:
 | 
						|
        print('read_all_register()')
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def rsp_read_all_regs(options, cmd, cmd_args, rsp):
 | 
						|
    packet = Packet(rsp)
 | 
						|
    dump_all_regs(packet)
 | 
						|
 | 
						|
 | 
						|
def cmd_write_all_regs(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    print('write_all_registers()')
 | 
						|
    dump_all_regs(packet)
 | 
						|
    return False
 | 
						|
 | 
						|
g_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]
 | 
						|
 | 
						|
 | 
						|
def cmd_bp(options, cmd, args):
 | 
						|
    if cmd == 'Z':
 | 
						|
        s = 'set_'
 | 
						|
    else:
 | 
						|
        s = 'clear_'
 | 
						|
    packet = Packet(args)
 | 
						|
    bp_type = packet.get_hex_uint('big')
 | 
						|
    packet.get_char()  # Skip ,
 | 
						|
    bp_addr = packet.get_hex_uint('big')
 | 
						|
    packet.get_char()  # Skip ,
 | 
						|
    bp_size = packet.get_hex_uint('big')
 | 
						|
    s += g_bp_types[bp_type]
 | 
						|
    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
 | 
						|
    print(s)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_mem_rgn_info(options, cmd, args):
 | 
						|
    packet = Packet(args)
 | 
						|
    packet.get_char()  # skip ':' character
 | 
						|
    addr = packet.get_hex_uint('big')
 | 
						|
    print('get_memory_region_info (addr=0x%x)' % (addr))
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_kill(options, cmd, args):
 | 
						|
    print('kill_process()')
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_jThreadsInfo(options, cmd, args):
 | 
						|
    print('jThreadsInfo()')
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
 | 
						|
    print('jGetLoadedDynamicLibrariesInfos()')
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def decode_packet(s, start_index=0):
 | 
						|
    # print '\ndecode_packet("%s")' % (s[start_index:])
 | 
						|
    index = s.find('}', start_index)
 | 
						|
    have_escapes = index != -1
 | 
						|
    if have_escapes:
 | 
						|
        normal_s = s[start_index:index]
 | 
						|
    else:
 | 
						|
        normal_s = s[start_index:]
 | 
						|
    # print 'normal_s = "%s"' % (normal_s)
 | 
						|
    if have_escapes:
 | 
						|
        escape_char = '%c' % (ord(s[index + 1]) ^ 0x20)
 | 
						|
        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
 | 
						|
        return normal_s + escape_char + decode_packet(s, index + 2)
 | 
						|
    else:
 | 
						|
        return normal_s
 | 
						|
 | 
						|
 | 
						|
def rsp_json(options, cmd, cmd_args, rsp):
 | 
						|
    print('%s() reply:' % (cmd))
 | 
						|
    json_tree = json.loads(rsp)
 | 
						|
    print(json.dumps(json_tree, indent=4, separators=(',', ': ')))
 | 
						|
 | 
						|
 | 
						|
def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
 | 
						|
    if cmd_args:
 | 
						|
        rsp_json(options, cmd, cmd_args, rsp)
 | 
						|
    else:
 | 
						|
        rsp_ok_means_supported(options, cmd, cmd_args, rsp)
 | 
						|
 | 
						|
gdb_remote_commands = {
 | 
						|
    '\\?': {'cmd': cmd_stop_reply, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
 | 
						|
    'qThreadStopInfo': {'cmd': cmd_qThreadStopInfo, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"},
 | 
						|
    'QStartNoAckMode': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if no ack mode is supported"},
 | 
						|
    'QThreadSuffixSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if thread suffix is supported"},
 | 
						|
    'QListThreadsInStopReply': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if threads in stop reply packets are supported"},
 | 
						|
    'QSetDetachOnError:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should detach on error"},
 | 
						|
    'QSetDisableASLR:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should disable ASLR"},
 | 
						|
    'qLaunchSuccess': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_success, 'name': "check on launch success for the A packet"},
 | 
						|
    'A': {'cmd': cmd_A, 'rsp': rsp_ok_means_success, 'name': "launch process"},
 | 
						|
    'QLaunchArch:': {'cmd': cmd_QSetWithString, 'rsp': rsp_ok_means_supported, 'name': "set the arch to launch in case the file contains multiple architectures"},
 | 
						|
    'qVAttachOrWaitSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "set the launch architecture"},
 | 
						|
    'qHostInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get host information"},
 | 
						|
    'qC': {'cmd': cmd_qC, 'rsp': rsp_qC, 'name': "return the current thread ID"},
 | 
						|
    'vCont': {'cmd': cmd_vCont, 'rsp': rsp_vCont, 'name': "extended continue command"},
 | 
						|
    'qSpeedTest': {'cmd':cmd_qSpeedTest, 'rsp': rsp_qSpeedTest, 'name': 'speed test packdet'},
 | 
						|
    'vAttach': {'cmd': cmd_vAttach, 'rsp': rsp_stop_reply, 'name': "attach to process"},
 | 
						|
    'c': {'cmd': cmd_c, 'rsp': rsp_stop_reply, 'name': "continue"},
 | 
						|
    's': {'cmd': cmd_s, 'rsp': rsp_stop_reply, 'name': "step"},
 | 
						|
    'qRegisterInfo': {'cmd': cmd_qRegisterInfo, 'rsp': rsp_qRegisterInfo, 'name': "query register info"},
 | 
						|
    'qfThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
 | 
						|
    'qsThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"},
 | 
						|
    'qShlibInfoAddr': {'cmd': cmd_query_packet, 'rsp': rsp_hex_big_endian, 'name': "get shared library info address"},
 | 
						|
    'qMemoryRegionInfo': {'cmd': cmd_mem_rgn_info, 'rsp': rsp_dump_key_value_pairs, 'name': "get memory region information"},
 | 
						|
    'qProcessInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get process info"},
 | 
						|
    'qSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query supported"},
 | 
						|
    'qXfer:': {'cmd': cmd_qXfer, 'rsp': rsp_qXfer, 'name': "qXfer"},
 | 
						|
    'qSymbol:': {'cmd': cmd_qSymbol, 'rsp': rsp_qSymbol, 'name': "qSymbol"},
 | 
						|
    'QSetSTDIN:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDIN prior to launching with A packet"},
 | 
						|
    'QSetSTDOUT:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDOUT prior to launching with A packet"},
 | 
						|
    'QSetSTDERR:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDERR prior to launching with A packet"},
 | 
						|
    'QEnvironment:' : {'cmd' : cmd_QSetWithString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
 | 
						|
    'QEnvironmentHexEncoded:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"},
 | 
						|
    'x': {'cmd': cmd_read_mem_bin, 'rsp': rsp_mem_bin_bytes, 'name': "read memory binary"},
 | 
						|
    'X': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory binary"},
 | 
						|
    'm': {'cmd': cmd_read_memory, 'rsp': rsp_memory_bytes, 'name': "read memory"},
 | 
						|
    'M': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory"},
 | 
						|
    '_M': {'cmd': cmd_alloc_memory, 'rsp': rsp_alloc_memory, 'name': "allocate memory"},
 | 
						|
    '_m': {'cmd': cmd_dealloc_memory, 'rsp': rsp_ok_means_success, 'name': "deallocate memory"},
 | 
						|
    'p': {'cmd': cmd_read_one_reg, 'rsp': rsp_read_one_reg, 'name': "read single register"},
 | 
						|
    'P': {'cmd': cmd_write_one_reg, 'rsp': rsp_ok_means_success, 'name': "write single register"},
 | 
						|
    'g': {'cmd': cmd_read_all_regs, 'rsp': rsp_read_all_regs, 'name': "read all registers"},
 | 
						|
    'G': {'cmd': cmd_write_all_regs, 'rsp': rsp_ok_means_success, 'name': "write all registers"},
 | 
						|
    'z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "clear breakpoint or watchpoint"},
 | 
						|
    'Z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "set breakpoint or watchpoint"},
 | 
						|
    'k': {'cmd': cmd_kill, 'rsp': rsp_stop_reply, 'name': "kill process"},
 | 
						|
    'jThreadsInfo': {'cmd': cmd_jThreadsInfo, 'rsp': rsp_json, 'name': "JSON get all threads info"},
 | 
						|
    'jGetLoadedDynamicLibrariesInfos:': {'cmd': cmd_jGetLoadedDynamicLibrariesInfos, 'rsp': rsp_jGetLoadedDynamicLibrariesInfos, 'name': 'JSON get loaded dynamic libraries'},
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
def calculate_mean_and_standard_deviation(floats):
 | 
						|
    sum = 0.0
 | 
						|
    count = len(floats)
 | 
						|
    if count == 0:
 | 
						|
        return (0.0, 0.0)
 | 
						|
    for f in floats:
 | 
						|
        sum += f
 | 
						|
    mean = sum / count
 | 
						|
    accum = 0.0
 | 
						|
    for f in floats:
 | 
						|
        delta = f - mean
 | 
						|
        accum += delta * delta
 | 
						|
 | 
						|
    std_dev = math.sqrt(accum / (count - 1))
 | 
						|
    return (mean, std_dev)
 | 
						|
 | 
						|
 | 
						|
def parse_gdb_log_file(path, options):
 | 
						|
    f = open(path)
 | 
						|
    parse_gdb_log(f, options)
 | 
						|
    f.close()
 | 
						|
 | 
						|
 | 
						|
def round_up(n, incr):
 | 
						|
    return float(((int(n) + incr) / incr) * incr)
 | 
						|
 | 
						|
 | 
						|
def plot_latencies(sec_times):
 | 
						|
    # import numpy as np
 | 
						|
    import matplotlib.pyplot as plt
 | 
						|
 | 
						|
    for (i, name) in enumerate(sec_times.keys()):
 | 
						|
        times = sec_times[name]
 | 
						|
        if len(times) <= 1:
 | 
						|
            continue
 | 
						|
        plt.subplot(2, 1, 1)
 | 
						|
        plt.title('Packet "%s" Times' % (name))
 | 
						|
        plt.xlabel('Packet')
 | 
						|
        units = 'ms'
 | 
						|
        adj_times = []
 | 
						|
        max_time = 0.0
 | 
						|
        for time in times:
 | 
						|
            time = time * 1000.0
 | 
						|
            adj_times.append(time)
 | 
						|
            if time > max_time:
 | 
						|
                max_time = time
 | 
						|
        if max_time < 1.0:
 | 
						|
            units = 'us'
 | 
						|
            max_time = 0.0
 | 
						|
            for i in range(len(adj_times)):
 | 
						|
                adj_times[i] *= 1000.0
 | 
						|
                if adj_times[i] > max_time:
 | 
						|
                    max_time = adj_times[i]
 | 
						|
        plt.ylabel('Time (%s)' % (units))
 | 
						|
        max_y = None
 | 
						|
        for i in [5.0, 10.0, 25.0, 50.0]:
 | 
						|
            if max_time < i:
 | 
						|
                max_y = round_up(max_time, i)
 | 
						|
                break
 | 
						|
        if max_y is None:
 | 
						|
            max_y = round_up(max_time, 100.0)
 | 
						|
        plt.ylim(0.0, max_y)
 | 
						|
        plt.plot(adj_times, 'o-')
 | 
						|
        plt.show()
 | 
						|
 | 
						|
 | 
						|
def parse_gdb_log(file, options):
 | 
						|
    '''Parse a GDB log file that was generated by enabling logging with:
 | 
						|
    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
 | 
						|
    This log file will contain timestamps and this function will then normalize
 | 
						|
    those packets to be relative to the first value timestamp that is found and
 | 
						|
    show delta times between log lines and also keep track of how long it takes
 | 
						|
    for GDB remote commands to make a send/receive round trip. This can be
 | 
						|
    handy when trying to figure out why some operation in the debugger is taking
 | 
						|
    a long time during a preset set of debugger commands.'''
 | 
						|
 | 
						|
    tricky_commands = ['qRegisterInfo']
 | 
						|
    timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
 | 
						|
    packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]')
 | 
						|
    packet_transmit_name_regex = re.compile(
 | 
						|
        '(?P<direction>send|read) packet: (?P<packet>.*)')
 | 
						|
    packet_contents_name_regex = re.compile('\$([^#]*)#[0-9a-fA-F]{2}')
 | 
						|
    packet_checksum_regex = re.compile('.*#[0-9a-fA-F]{2}$')
 | 
						|
    packet_names_regex_str = '(' + \
 | 
						|
        '|'.join(gdb_remote_commands.keys()) + ')(.*)'
 | 
						|
    packet_names_regex = re.compile(packet_names_regex_str)
 | 
						|
 | 
						|
    base_time = 0.0
 | 
						|
    last_time = 0.0
 | 
						|
    min_time = 100000000.0
 | 
						|
    packet_total_times = {}
 | 
						|
    all_packet_times = []
 | 
						|
    packet_times = {}
 | 
						|
    packet_counts = {}
 | 
						|
    lines = file.read().splitlines()
 | 
						|
    last_command = None
 | 
						|
    last_command_args = None
 | 
						|
    last_command_packet = None
 | 
						|
    hide_next_response = False
 | 
						|
    num_lines = len(lines)
 | 
						|
    skip_count = 0
 | 
						|
    for (line_index, line) in enumerate(lines):
 | 
						|
        # See if we need to skip any lines
 | 
						|
        if skip_count > 0:
 | 
						|
            skip_count -= 1
 | 
						|
            continue
 | 
						|
        m = packet_transmit_name_regex.search(line)
 | 
						|
        is_command = False
 | 
						|
        direction = None
 | 
						|
        if m:
 | 
						|
            direction = m.group('direction')
 | 
						|
            is_command = direction == 'send'
 | 
						|
            packet = m.group('packet')
 | 
						|
            sys.stdout.write(options.colors.green())
 | 
						|
            if not options.quiet and not hide_next_response:
 | 
						|
                print('#  ', line)
 | 
						|
            sys.stdout.write(options.colors.reset())
 | 
						|
 | 
						|
            # print 'direction = "%s", packet = "%s"' % (direction, packet)
 | 
						|
 | 
						|
            if packet[0] == '+':
 | 
						|
                if is_command:
 | 
						|
                    print('-->', end=' ')
 | 
						|
                else:
 | 
						|
                    print('<--', end=' ')
 | 
						|
                if not options.quiet:
 | 
						|
                    print('ACK')
 | 
						|
                continue
 | 
						|
            elif packet[0] == '-':
 | 
						|
                if is_command:
 | 
						|
                    print('-->', end=' ')
 | 
						|
                else:
 | 
						|
                    print('<--', end=' ')
 | 
						|
                if not options.quiet:
 | 
						|
                    print('NACK')
 | 
						|
                continue
 | 
						|
            elif packet[0] == '$':
 | 
						|
                m = packet_contents_name_regex.match(packet)
 | 
						|
                if not m and packet[0] == '$':
 | 
						|
                    multiline_packet = packet
 | 
						|
                    idx = line_index + 1
 | 
						|
                    while idx < num_lines:
 | 
						|
                        if not options.quiet and not hide_next_response:
 | 
						|
                            print('#  ', lines[idx])
 | 
						|
                        multiline_packet += lines[idx]
 | 
						|
                        m = packet_contents_name_regex.match(multiline_packet)
 | 
						|
                        if m:
 | 
						|
                            packet = multiline_packet
 | 
						|
                            skip_count = idx - line_index
 | 
						|
                            break
 | 
						|
                        else:
 | 
						|
                            idx += 1
 | 
						|
                if m:
 | 
						|
                    if is_command:
 | 
						|
                        print('-->', end=' ')
 | 
						|
                    else:
 | 
						|
                        print('<--', end=' ')
 | 
						|
                    contents = decode_packet(m.group(1))
 | 
						|
                    if is_command:
 | 
						|
                        hide_next_response = False
 | 
						|
                        m = packet_names_regex.match(contents)
 | 
						|
                        if m:
 | 
						|
                            last_command = m.group(1)
 | 
						|
                            if last_command == '?':
 | 
						|
                                last_command = '\\?'
 | 
						|
                            packet_name = last_command
 | 
						|
                            last_command_args = m.group(2)
 | 
						|
                            last_command_packet = contents
 | 
						|
                            hide_next_response = gdb_remote_commands[last_command][
 | 
						|
                                'cmd'](options, last_command, last_command_args)
 | 
						|
                        else:
 | 
						|
                            packet_match = packet_name_regex.match(contents)
 | 
						|
                            if packet_match:
 | 
						|
                                packet_name = packet_match.group(1)
 | 
						|
                                for tricky_cmd in tricky_commands:
 | 
						|
                                    if packet_name.find(tricky_cmd) == 0:
 | 
						|
                                        packet_name = tricky_cmd
 | 
						|
                            else:
 | 
						|
                                packet_name = contents
 | 
						|
                            last_command = None
 | 
						|
                            last_command_args = None
 | 
						|
                            last_command_packet = None
 | 
						|
                    elif last_command:
 | 
						|
                        gdb_remote_commands[last_command]['rsp'](
 | 
						|
                            options, last_command, last_command_args, contents)
 | 
						|
                else:
 | 
						|
                    print('error: invalid packet: "', packet, '"')
 | 
						|
            else:
 | 
						|
                print('???')
 | 
						|
        else:
 | 
						|
            print('## ', line)
 | 
						|
        match = timestamp_regex.match(line)
 | 
						|
        if match:
 | 
						|
            curr_time = float(match.group(2))
 | 
						|
            if last_time and not is_command:
 | 
						|
                delta = curr_time - last_time
 | 
						|
                all_packet_times.append(delta)
 | 
						|
            delta = 0.0
 | 
						|
            if base_time:
 | 
						|
                delta = curr_time - last_time
 | 
						|
            else:
 | 
						|
                base_time = curr_time
 | 
						|
 | 
						|
            if not is_command:
 | 
						|
                if line.find('read packet: $') >= 0 and packet_name:
 | 
						|
                    if packet_name in packet_total_times:
 | 
						|
                        packet_total_times[packet_name] += delta
 | 
						|
                        packet_counts[packet_name] += 1
 | 
						|
                    else:
 | 
						|
                        packet_total_times[packet_name] = delta
 | 
						|
                        packet_counts[packet_name] = 1
 | 
						|
                    if packet_name not in packet_times:
 | 
						|
                        packet_times[packet_name] = []
 | 
						|
                    packet_times[packet_name].append(delta)
 | 
						|
                    packet_name = None
 | 
						|
                if min_time > delta:
 | 
						|
                    min_time = delta
 | 
						|
 | 
						|
            if not options or not options.quiet:
 | 
						|
                print('%s%.6f %+.6f%s' % (match.group(1),
 | 
						|
                                          curr_time - base_time,
 | 
						|
                                          delta,
 | 
						|
                                          match.group(3)))
 | 
						|
            last_time = curr_time
 | 
						|
        # else:
 | 
						|
        #     print line
 | 
						|
    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)
 | 
						|
    if average and std_dev:
 | 
						|
        print('%u packets with average packet time of %f and standard deviation of %f' % (len(all_packet_times), average, std_dev))
 | 
						|
    if packet_total_times:
 | 
						|
        total_packet_time = 0.0
 | 
						|
        total_packet_count = 0
 | 
						|
        for key, vvv in packet_total_times.items():
 | 
						|
            # print '  key = (%s) "%s"' % (type(key), key)
 | 
						|
            # print 'value = (%s) %s' % (type(vvv), vvv)
 | 
						|
            # if type(vvv) == 'float':
 | 
						|
            total_packet_time += vvv
 | 
						|
        for key, vvv in packet_counts.items():
 | 
						|
            total_packet_count += vvv
 | 
						|
 | 
						|
        print('#------------------------------------------------------------')
 | 
						|
        print('# Packet timing summary:')
 | 
						|
        print('# Totals: time = %6f, count = %6d' % (total_packet_time,
 | 
						|
                                                     total_packet_count))
 | 
						|
        print('# Min packet time: time = %6f' % (min_time))
 | 
						|
        print('#------------------------------------------------------------')
 | 
						|
        print('# Packet                   Time (sec)  Percent Count  Latency')
 | 
						|
        print('#------------------------- ----------- ------- ------ -------')
 | 
						|
        if options and options.sort_count:
 | 
						|
            res = sorted(
 | 
						|
                packet_counts,
 | 
						|
                key=packet_counts.__getitem__,
 | 
						|
                reverse=True)
 | 
						|
        else:
 | 
						|
            res = sorted(
 | 
						|
                packet_total_times,
 | 
						|
                key=packet_total_times.__getitem__,
 | 
						|
                reverse=True)
 | 
						|
 | 
						|
        if last_time > 0.0:
 | 
						|
            for item in res:
 | 
						|
                packet_total_time = packet_total_times[item]
 | 
						|
                packet_percent = (
 | 
						|
                    packet_total_time / total_packet_time) * 100.0
 | 
						|
                packet_count = packet_counts[item]
 | 
						|
                print("  %24s %11.6f  %5.2f%% %6d %9.6f" % (
 | 
						|
                        item, packet_total_time, packet_percent, packet_count,
 | 
						|
                        float(packet_total_time) / float(packet_count)))
 | 
						|
        if options.plot:
 | 
						|
            plot_latencies(packet_times)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    usage = "usage: gdbremote [options]"
 | 
						|
    description = '''The command disassembles a GDB remote packet log.'''
 | 
						|
    parser = optparse.OptionParser(
 | 
						|
        description=description,
 | 
						|
        prog='gdbremote',
 | 
						|
        usage=usage)
 | 
						|
    parser.add_option(
 | 
						|
        '-v',
 | 
						|
        '--verbose',
 | 
						|
        action='store_true',
 | 
						|
        dest='verbose',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '--plot',
 | 
						|
        action='store_true',
 | 
						|
        dest='plot',
 | 
						|
        help='plot packet latencies by packet type',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-q',
 | 
						|
        '--quiet',
 | 
						|
        action='store_true',
 | 
						|
        dest='quiet',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-C',
 | 
						|
        '--color',
 | 
						|
        action='store_true',
 | 
						|
        dest='color',
 | 
						|
        help='add terminal colors',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '-c',
 | 
						|
        '--sort-by-count',
 | 
						|
        action='store_true',
 | 
						|
        dest='sort_count',
 | 
						|
        help='display verbose debug info',
 | 
						|
        default=False)
 | 
						|
    parser.add_option(
 | 
						|
        '--crashlog',
 | 
						|
        type='string',
 | 
						|
        dest='crashlog',
 | 
						|
        help='symbolicate using a darwin crash log file',
 | 
						|
        default=False)
 | 
						|
    try:
 | 
						|
        (options, args) = parser.parse_args(sys.argv[1:])
 | 
						|
    except:
 | 
						|
        print('error: argument error')
 | 
						|
        sys.exit(1)
 | 
						|
 | 
						|
    options.colors = TerminalColors(options.color)
 | 
						|
    options.symbolicator = None
 | 
						|
    if options.crashlog:
 | 
						|
        import lldb
 | 
						|
        lldb.debugger = lldb.SBDebugger.Create()
 | 
						|
        import lldb.macosx.crashlog
 | 
						|
        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
 | 
						|
        print('%s' % (options.symbolicator))
 | 
						|
 | 
						|
    # This script is being run from the command line, create a debugger in case we are
 | 
						|
    # going to use any debugger functions in our function.
 | 
						|
    if len(args):
 | 
						|
        for file in args:
 | 
						|
            print('#----------------------------------------------------------------------')
 | 
						|
            print("# GDB remote log file: '%s'" % file)
 | 
						|
            print('#----------------------------------------------------------------------')
 | 
						|
            parse_gdb_log_file(file, options)
 | 
						|
        if options.symbolicator:
 | 
						|
            print('%s' % (options.symbolicator))
 | 
						|
    else:
 | 
						|
        parse_gdb_log(sys.stdin, options)
 | 
						|
 | 
						|
else:
 | 
						|
    import lldb
 | 
						|
    if lldb.debugger:
 | 
						|
        # This initializer is being run from LLDB in the embedded command interpreter
 | 
						|
        # Add any commands contained in this module to LLDB
 | 
						|
        lldb.debugger.HandleCommand(
 | 
						|
            'command script add -f gdbremote.start_gdb_log start_gdb_log')
 | 
						|
        lldb.debugger.HandleCommand(
 | 
						|
            'command script add -f gdbremote.stop_gdb_log stop_gdb_log')
 | 
						|
        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')
 |