diff options
Diffstat (limited to 'examples/python/gdbremote.py')
-rwxr-xr-x | examples/python/gdbremote.py | 1630 |
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' |