summaryrefslogtreecommitdiff
path: root/examples/python/gdbremote.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/python/gdbremote.py')
-rwxr-xr-xexamples/python/gdbremote.py1630
1 files changed, 0 insertions, 1630 deletions
diff --git a/examples/python/gdbremote.py b/examples/python/gdbremote.py
deleted file mode 100755
index 4ca8a1b82e84..000000000000
--- a/examples/python/gdbremote.py
+++ /dev/null
@@ -1,1630 +0,0 @@
-#!/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.
-#----------------------------------------------------------------------
-
-import binascii
-import commands
-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)
- if all(c in string.printable for c in s):
- return s
- except TypeError:
- 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 = string.split(self.str, ';')
- for key_value_pair in key_value_pairs:
- if len(key_value_pair):
- kvp.append(string.split(key_value_pair, ':'))
- 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 = string.split(cmd_args, ':')
- 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 string.split(args[1:], ';'):
- (short_action, thread) = string.split(thread_action, ':')
- 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 = string.split(rsp, ';')
- 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)),
- 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 ',',
- print '0x%x' % (tid),
- 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),
- print '%2.2x' % (uval),
- 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 '-->',
- else:
- print '<--',
- if not options.quiet:
- print 'ACK'
- continue
- elif packet[0] == '-':
- if is_command:
- print '-->',
- else:
- print '<--',
- 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 '-->',
- else:
- print '<--',
- 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'