brintos

brintos / llvm-project-archived public Read only

0
0
Text · 58.6 KiB · 0bbfc1a Raw
1836 lines · python
1#!/usr/bin/env python2 3# ----------------------------------------------------------------------4# This module will enable GDB remote packet logging when the5# 'start_gdb_log' command is called with a filename to log to. When the6# 'stop_gdb_log' command is called, it will disable the logging and7# print out statistics about how long commands took to execute and also8# will primnt ou9# Be sure to add the python path that points to the LLDB shared library.10#11# To use this in the embedded python interpreter using "lldb" just12# import it with the full path using the "command script import"13# command. This can be done from the LLDB command line:14#   (lldb) command script import /path/to/gdbremote.py15# Or it can be added to your ~/.lldbinit file so this module is always16# available.17# ----------------------------------------------------------------------18 19import binascii20import subprocess21import json22import math23import optparse24import os25import re26import shlex27import string28import sys29import tempfile30import xml.etree.ElementTree as ET31 32# ----------------------------------------------------------------------33# Global variables34# ----------------------------------------------------------------------35g_log_file = ""36g_byte_order = "little"37g_number_regex = re.compile("^(0x[0-9a-fA-F]+|[0-9]+)")38g_thread_id_regex = re.compile("^(-1|[0-9a-fA-F]+|0)")39 40 41class TerminalColors:42    """Simple terminal colors class"""43 44    def __init__(self, enabled=True):45        # TODO: discover terminal type from "file" and disable if46        # it can't handle the color codes47        self.enabled = enabled48 49    def reset(self):50        """Reset all terminal colors and formatting."""51        if self.enabled:52            return "\x1b[0m"53        return ""54 55    def bold(self, on=True):56        """Enable or disable bold depending on the "on" parameter."""57        if self.enabled:58            if on:59                return "\x1b[1m"60            else:61                return "\x1b[22m"62        return ""63 64    def italics(self, on=True):65        """Enable or disable italics depending on the "on" parameter."""66        if self.enabled:67            if on:68                return "\x1b[3m"69            else:70                return "\x1b[23m"71        return ""72 73    def underline(self, on=True):74        """Enable or disable underline depending on the "on" parameter."""75        if self.enabled:76            if on:77                return "\x1b[4m"78            else:79                return "\x1b[24m"80        return ""81 82    def inverse(self, on=True):83        """Enable or disable inverse depending on the "on" parameter."""84        if self.enabled:85            if on:86                return "\x1b[7m"87            else:88                return "\x1b[27m"89        return ""90 91    def strike(self, on=True):92        """Enable or disable strike through depending on the "on" parameter."""93        if self.enabled:94            if on:95                return "\x1b[9m"96            else:97                return "\x1b[29m"98        return ""99 100    def black(self, fg=True):101        """Set the foreground or background color to black.102        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.103        """104        if self.enabled:105            if fg:106                return "\x1b[30m"107            else:108                return "\x1b[40m"109        return ""110 111    def red(self, fg=True):112        """Set the foreground or background color to red.113        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.114        """115        if self.enabled:116            if fg:117                return "\x1b[31m"118            else:119                return "\x1b[41m"120        return ""121 122    def green(self, fg=True):123        """Set the foreground or background color to green.124        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.125        """126        if self.enabled:127            if fg:128                return "\x1b[32m"129            else:130                return "\x1b[42m"131        return ""132 133    def yellow(self, fg=True):134        """Set the foreground or background color to yellow.135        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.136        """137        if self.enabled:138            if fg:139                return "\x1b[33m"140            else:141                return "\x1b[43m"142        return ""143 144    def blue(self, fg=True):145        """Set the foreground or background color to blue.146        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.147        """148        if self.enabled:149            if fg:150                return "\x1b[34m"151            else:152                return "\x1b[44m"153        return ""154 155    def magenta(self, fg=True):156        """Set the foreground or background color to magenta.157        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.158        """159        if self.enabled:160            if fg:161                return "\x1b[35m"162            else:163                return "\x1b[45m"164        return ""165 166    def cyan(self, fg=True):167        """Set the foreground or background color to cyan.168        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.169        """170        if self.enabled:171            if fg:172                return "\x1b[36m"173            else:174                return "\x1b[46m"175        return ""176 177    def white(self, fg=True):178        """Set the foreground or background color to white.179        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.180        """181        if self.enabled:182            if fg:183                return "\x1b[37m"184            else:185                return "\x1b[47m"186        return ""187 188    def default(self, fg=True):189        """Set the foreground or background color to the default.190        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.191        """192        if self.enabled:193            if fg:194                return "\x1b[39m"195            else:196                return "\x1b[49m"197        return ""198 199 200def start_gdb_log(debugger, command, result, dict):201    """Start logging GDB remote packets by enabling logging with timestamps and202    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"203    in order to dump out the commands."""204    global g_log_file205    command_args = shlex.split(command)206    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"207    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 will208    be aggregated and displayed."""209    parser = optparse.OptionParser(210        description=description, prog="start_gdb_log", usage=usage211    )212    parser.add_option(213        "-v",214        "--verbose",215        action="store_true",216        dest="verbose",217        help="display verbose debug info",218        default=False,219    )220    try:221        (options, args) = parser.parse_args(command_args)222    except:223        return224 225    if g_log_file:226        result.PutCString(227            'error: logging is already in progress with file "%s"' % g_log_file228        )229    else:230        args_len = len(args)231        if args_len == 0:232            g_log_file = tempfile.mktemp()233        elif len(args) == 1:234            g_log_file = args[0]235 236        if g_log_file:237            debugger.HandleCommand(238                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets'239                % g_log_file240            )241            result.PutCString(242                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics."243                % g_log_file244            )245            return246 247        result.PutCString("error: invalid log file path")248    result.PutCString(usage)249 250 251def stop_gdb_log(debugger, command, result, dict):252    """Stop logging GDB remote packets to the file that was specified in a call253    to "start_gdb_log" and normalize the timestamps to be relative to the first254    timestamp in the log file. Also print out statistics for how long each255    command took to allow performance bottlenecks to be determined."""256    global g_log_file257    # Any commands whose names might be followed by more valid C identifier258    # characters must be listed here259    command_args = shlex.split(command)260    usage = "usage: stop_gdb_log [options]"261    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."""262    parser = optparse.OptionParser(263        description=description, prog="stop_gdb_log", usage=usage264    )265    parser.add_option(266        "-v",267        "--verbose",268        action="store_true",269        dest="verbose",270        help="display verbose debug info",271        default=False,272    )273    parser.add_option(274        "--plot",275        action="store_true",276        dest="plot",277        help="plot packet latencies by packet type",278        default=False,279    )280    parser.add_option(281        "-q",282        "--quiet",283        action="store_true",284        dest="quiet",285        help="display verbose debug info",286        default=False,287    )288    parser.add_option(289        "-C",290        "--color",291        action="store_true",292        dest="color",293        help="add terminal colors",294        default=False,295    )296    parser.add_option(297        "-c",298        "--sort-by-count",299        action="store_true",300        dest="sort_count",301        help="display verbose debug info",302        default=False,303    )304    parser.add_option(305        "-s",306        "--symbolicate",307        action="store_true",308        dest="symbolicate",309        help='symbolicate addresses in log using current "lldb.target"',310        default=False,311    )312    try:313        (options, args) = parser.parse_args(command_args)314    except:315        return316    options.colors = TerminalColors(options.color)317    options.symbolicator = None318    if options.symbolicate:319        if lldb.target:320            import lldb.utils.symbolication321 322            options.symbolicator = lldb.utils.symbolication.Symbolicator()323            options.symbolicator.target = lldb.target324        else:325            print("error: can't symbolicate without a target")326 327    if not g_log_file:328        result.PutCString(329            'error: logging must have been previously enabled with a call to "stop_gdb_log"'330        )331    elif os.path.exists(g_log_file):332        if len(args) == 0:333            debugger.HandleCommand("log disable gdb-remote packets")334            result.PutCString(335                "GDB packet logging disabled. Logged packets are in '%s'" % g_log_file336            )337            parse_gdb_log_file(g_log_file, options)338        else:339            result.PutCString(usage)340    else:341        print('error: the GDB packet log file "%s" does not exist' % g_log_file)342 343 344def is_hex_byte(str):345    if len(str) == 2:346        return str[0] in string.hexdigits and str[1] in string.hexdigits347    return False348 349 350def get_hex_string_if_all_printable(str):351    try:352        s = binascii.unhexlify(str).decode()353        if all(c in string.printable for c in s):354            return s355    except (TypeError, binascii.Error, UnicodeDecodeError):356        pass357    return None358 359 360# global register info list361g_register_infos = list()362g_max_register_info_name_len = 0363 364 365class RegisterInfo:366    """Class that represents register information"""367 368    def __init__(self, kvp):369        self.info = dict()370        for kv in kvp:371            key = kv[0]372            value = kv[1]373            self.info[key] = value374 375    def name(self):376        """Get the name of the register."""377        if self.info and "name" in self.info:378            return self.info["name"]379        return None380 381    def bit_size(self):382        """Get the size in bits of the register."""383        if self.info and "bitsize" in self.info:384            return int(self.info["bitsize"])385        return 0386 387    def byte_size(self):388        """Get the size in bytes of the register."""389        return self.bit_size() / 8390 391    def get_value_from_hex_string(self, hex_str):392        """Dump the register value given a native byte order encoded hex ASCII byte string."""393        encoding = self.info["encoding"]394        bit_size = self.bit_size()395        packet = Packet(hex_str)396        if encoding == "uint":397            uval = packet.get_hex_uint(g_byte_order)398            if bit_size == 8:399                return "0x%2.2x" % (uval)400            elif bit_size == 16:401                return "0x%4.4x" % (uval)402            elif bit_size == 32:403                return "0x%8.8x" % (uval)404            elif bit_size == 64:405                return "0x%16.16x" % (uval)406        bytes = list()407        uval = packet.get_hex_uint8()408        while uval is not None:409            bytes.append(uval)410            uval = packet.get_hex_uint8()411        value_str = "0x"412        if g_byte_order == "little":413            bytes.reverse()414        for byte in bytes:415            value_str += "%2.2x" % byte416        return "%s" % (value_str)417 418    def __str__(self):419        """Dump the register info key/value pairs"""420        s = ""421        for key in self.info.keys():422            if s:423                s += ", "424            s += "%s=%s " % (key, self.info[key])425        return s426 427 428class Packet:429    """Class that represents a packet that contains string data"""430 431    def __init__(self, packet_str):432        self.str = packet_str433 434    def peek_char(self):435        ch = 0436        if self.str:437            ch = self.str[0]438        return ch439 440    def get_char(self):441        ch = 0442        if self.str:443            ch = self.str[0]444            self.str = self.str[1:]445        return ch446 447    def skip_exact_string(self, s):448        if self.str and self.str.startswith(s):449            self.str = self.str[len(s) :]450            return True451        else:452            return False453 454    def get_thread_id(self, fail_value=-1):455        match = g_number_regex.match(self.str)456        if match:457            number_str = match.group(1)458            self.str = self.str[len(number_str) :]459            return int(number_str, 0)460        else:461            return fail_value462 463    def get_hex_uint8(self):464        if (465            self.str466            and len(self.str) >= 2467            and self.str[0] in string.hexdigits468            and self.str[1] in string.hexdigits469        ):470            uval = int(self.str[0:2], 16)471            self.str = self.str[2:]472            return uval473        return None474 475    def get_hex_uint16(self, byte_order):476        uval = 0477        if byte_order == "big":478            uval |= self.get_hex_uint8() << 8479            uval |= self.get_hex_uint8()480        else:481            uval |= self.get_hex_uint8()482            uval |= self.get_hex_uint8() << 8483        return uval484 485    def get_hex_uint32(self, byte_order):486        uval = 0487        if byte_order == "big":488            uval |= self.get_hex_uint8() << 24489            uval |= self.get_hex_uint8() << 16490            uval |= self.get_hex_uint8() << 8491            uval |= self.get_hex_uint8()492        else:493            uval |= self.get_hex_uint8()494            uval |= self.get_hex_uint8() << 8495            uval |= self.get_hex_uint8() << 16496            uval |= self.get_hex_uint8() << 24497        return uval498 499    def get_hex_uint64(self, byte_order):500        uval = 0501        if byte_order == "big":502            uval |= self.get_hex_uint8() << 56503            uval |= self.get_hex_uint8() << 48504            uval |= self.get_hex_uint8() << 40505            uval |= self.get_hex_uint8() << 32506            uval |= self.get_hex_uint8() << 24507            uval |= self.get_hex_uint8() << 16508            uval |= self.get_hex_uint8() << 8509            uval |= self.get_hex_uint8()510        else:511            uval |= self.get_hex_uint8()512            uval |= self.get_hex_uint8() << 8513            uval |= self.get_hex_uint8() << 16514            uval |= self.get_hex_uint8() << 24515            uval |= self.get_hex_uint8() << 32516            uval |= self.get_hex_uint8() << 40517            uval |= self.get_hex_uint8() << 48518            uval |= self.get_hex_uint8() << 56519        return uval520 521    def get_number(self, fail_value=-1):522        """Get a number from the packet. The number must be in big endian format and should be parsed523        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with524        [1-9] means decimal, etc)"""525        match = g_number_regex.match(self.str)526        if match:527            number_str = match.group(1)528            self.str = self.str[len(number_str) :]529            return int(number_str, 0)530        else:531            return fail_value532 533    def get_hex_ascii_str(self, n=0):534        hex_chars = self.get_hex_chars(n)535        if hex_chars:536            return binascii.unhexlify(hex_chars)537        else:538            return None539 540    def get_hex_chars(self, n=0):541        str_len = len(self.str)542        if n == 0:543            # n was zero, so we need to determine all hex chars and544            # stop when we hit the end of the string of a non-hex character545            while n < str_len and self.str[n] in string.hexdigits:546                n = n + 1547        else:548            if n > str_len:549                return None  # Not enough chars550            # Verify all chars are hex if a length was specified551            for i in range(n):552                if self.str[i] not in string.hexdigits:553                    return None  # Not all hex digits554        if n == 0:555            return None556        hex_str = self.str[0:n]557        self.str = self.str[n:]558        return hex_str559 560    def get_hex_uint(self, byte_order, n=0):561        if byte_order == "big":562            hex_str = self.get_hex_chars(n)563            if hex_str is None:564                return None565            return int(hex_str, 16)566        else:567            uval = self.get_hex_uint8()568            if uval is None:569                return None570            uval_result = 0571            shift = 0572            while uval is not None:573                uval_result |= uval << shift574                shift += 8575                uval = self.get_hex_uint8()576            return uval_result577 578    def get_key_value_pairs(self):579        kvp = list()580        if ";" in self.str:581            key_value_pairs = self.str.split(";")582            for key_value_pair in key_value_pairs:583                if len(key_value_pair):584                    kvp.append(key_value_pair.split(":", 1))585        return kvp586 587    def split(self, ch):588        return self.str.split(ch)589 590    def split_hex(self, ch, byte_order):591        hex_values = list()592        strings = self.str.split(ch)593        for str in strings:594            hex_values.append(Packet(str).get_hex_uint(byte_order))595        return hex_values596 597    def __str__(self):598        return self.str599 600    def __len__(self):601        return len(self.str)602 603 604g_thread_suffix_regex = re.compile(";thread:([0-9a-fA-F]+);")605 606 607def get_thread_from_thread_suffix(str):608    if str:609        match = g_thread_suffix_regex.match(str)610        if match:611            return int(match.group(1), 16)612    return None613 614 615def cmd_qThreadStopInfo(options, cmd, args):616    packet = Packet(args)617    tid = packet.get_hex_uint("big")618    print("get_thread_stop_info  (tid = 0x%x)" % (tid))619 620 621def cmd_stop_reply(options, cmd, args):622    print("get_last_stop_info()")623    return False624 625 626def rsp_stop_reply(options, cmd, cmd_args, rsp):627    global g_byte_order628    packet = Packet(rsp)629    stop_type = packet.get_char()630    if stop_type == "T" or stop_type == "S":631        signo = packet.get_hex_uint8()632        key_value_pairs = packet.get_key_value_pairs()633        for key_value_pair in key_value_pairs:634            key = key_value_pair[0]635            if is_hex_byte(key):636                reg_num = Packet(key).get_hex_uint8()637                if reg_num < len(g_register_infos):638                    reg_info = g_register_infos[reg_num]639                    key_value_pair[0] = reg_info.name()640                    key_value_pair[1] = reg_info.get_value_from_hex_string(641                        key_value_pair[1]642                    )643            elif key == "jthreads" or key == "jstopinfo":644                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])645        key_value_pairs.insert(0, ["signal", signo])646        print("stop_reply():")647        dump_key_value_pairs(key_value_pairs)648    elif stop_type == "W":649        exit_status = packet.get_hex_uint8()650        print("stop_reply(): exit (status=%i)" % exit_status)651    elif stop_type == "O":652        print('stop_reply(): stdout = "%s"' % packet.str)653 654 655def cmd_unknown_packet(options, cmd, args):656    if args:657        print("cmd: %s, args: %s", cmd, args)658    else:659        print("cmd: %s", cmd)660    return False661 662 663def cmd_qSymbol(options, cmd, args):664    if args == ":":665        print("ready to serve symbols")666    else:667        packet = Packet(args)668        symbol_addr = packet.get_hex_uint("big")669        if symbol_addr is None:670            if packet.skip_exact_string(":"):671                symbol_name = packet.get_hex_ascii_str()672                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))673            else:674                print("error: bad command format")675        else:676            if packet.skip_exact_string(":"):677                symbol_name = packet.get_hex_ascii_str()678                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))679            else:680                print("error: bad command format")681 682 683def cmd_QSetWithHexString(options, cmd, args):684    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))685 686 687def cmd_QSetWithString(options, cmd, args):688    print('%s("%s")' % (cmd[:-1], args))689 690 691def cmd_QSetWithUnsigned(options, cmd, args):692    print("%s(%i)" % (cmd[:-1], int(args)))693 694 695def rsp_qSymbol(options, cmd, cmd_args, rsp):696    if len(rsp) == 0:697        print("Unsupported")698    else:699        if rsp == "OK":700            print("No more symbols to lookup")701        else:702            packet = Packet(rsp)703            if packet.skip_exact_string("qSymbol:"):704                symbol_name = packet.get_hex_ascii_str()705                print('lookup_symbol("%s")' % (symbol_name))706            else:707                print(708                    'error: response string should start with "qSymbol:": respnse is "%s"'709                    % (rsp)710                )711 712 713def cmd_qXfer(options, cmd, args):714    # $qXfer:features:read:target.xml:0,1ffff#14715    print("read target special data %s" % (args))716    return True717 718 719def rsp_qXfer(options, cmd, cmd_args, rsp):720    data = cmd_args.split(":")721    if data[0] == "features":722        if data[1] == "read":723            filename, extension = os.path.splitext(data[2])724            if extension == ".xml":725                response = Packet(rsp)726                xml_string = response.get_hex_ascii_str()727                if xml_string:728                    ch = xml_string[0]729                    if ch == "l":730                        xml_string = xml_string[1:]731                        xml_root = ET.fromstring(xml_string)732                        for reg_element in xml_root.findall("./feature/reg"):733                            if not "value_regnums" in reg_element.attrib:734                                reg_info = RegisterInfo([])735                                if "name" in reg_element.attrib:736                                    reg_info.info["name"] = reg_element.attrib["name"]737                                else:738                                    reg_info.info["name"] = "unspecified"739                                if "encoding" in reg_element.attrib:740                                    reg_info.info["encoding"] = reg_element.attrib[741                                        "encoding"742                                    ]743                                else:744                                    reg_info.info["encoding"] = "uint"745                                if "offset" in reg_element.attrib:746                                    reg_info.info["offset"] = reg_element.attrib[747                                        "offset"748                                    ]749                                if "bitsize" in reg_element.attrib:750                                    reg_info.info["bitsize"] = reg_element.attrib[751                                        "bitsize"752                                    ]753                                g_register_infos.append(reg_info)754                        print('XML for "%s":' % (data[2]))755                        ET.dump(xml_root)756 757 758def cmd_A(options, cmd, args):759    print("launch process:")760    packet = Packet(args)761    while True:762        arg_len = packet.get_number()763        if arg_len == -1:764            break765        if not packet.skip_exact_string(","):766            break767        arg_idx = packet.get_number()768        if arg_idx == -1:769            break770        if not packet.skip_exact_string(","):771            break772        arg_value = packet.get_hex_ascii_str(arg_len)773        print('argv[%u] = "%s"' % (arg_idx, arg_value))774 775 776def cmd_qC(options, cmd, args):777    print("query_current_thread_id()")778 779 780def rsp_qC(options, cmd, cmd_args, rsp):781    packet = Packet(rsp)782    if packet.skip_exact_string("QC"):783        tid = packet.get_thread_id()784        print("current_thread_id = %#x" % (tid))785    else:786        print("current_thread_id = old thread ID")787 788 789def cmd_query_packet(options, cmd, args):790    if args:791        print("%s%s" % (cmd, args))792    else:793        print("%s" % (cmd))794    return False795 796 797def rsp_ok_error(rsp):798    print("rsp: ", rsp)799 800 801def rsp_ok_means_supported(options, cmd, cmd_args, rsp):802    if rsp == "OK":803        print("%s%s is supported" % (cmd, cmd_args))804    elif rsp == "":805        print("%s%s is not supported" % (cmd, cmd_args))806    else:807        print("%s%s -> %s" % (cmd, cmd_args, rsp))808 809 810def rsp_ok_means_success(options, cmd, cmd_args, rsp):811    if rsp == "OK":812        print("success")813    elif rsp == "":814        print("%s%s is not supported" % (cmd, cmd_args))815    else:816        print("%s%s -> %s" % (cmd, cmd_args, rsp))817 818 819def dump_key_value_pairs(key_value_pairs):820    max_key_len = 0821    for key_value_pair in key_value_pairs:822        key_len = len(key_value_pair[0])823        if max_key_len < key_len:824            max_key_len = key_len825    for key_value_pair in key_value_pairs:826        key = key_value_pair[0]827        value = key_value_pair[1]828        unhex_value = get_hex_string_if_all_printable(value)829        if unhex_value:830            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))831        else:832            print("%*s = %s" % (max_key_len, key, value))833 834 835def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):836    if rsp:837        print("%s response:" % (cmd))838        packet = Packet(rsp)839        key_value_pairs = packet.get_key_value_pairs()840        dump_key_value_pairs(key_value_pairs)841    else:842        print("not supported")843 844 845def cmd_c(options, cmd, args):846    print("continue()")847    return False848 849 850def cmd_s(options, cmd, args):851    print("step()")852    return False853 854 855def cmd_qSpeedTest(options, cmd, args):856    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))857 858 859def rsp_qSpeedTest(options, cmd, cmd_args, rsp):860    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))861 862 863def cmd_vCont(options, cmd, args):864    if args == "?":865        print("%s: get supported extended continue modes" % (cmd))866    else:867        got_other_threads = 0868        s = ""869        for thread_action in args[1:].split(";"):870            (short_action, thread) = thread_action.split(":", 1)871            tid = int(thread, 16)872            if short_action == "c":873                action = "continue"874            elif short_action == "s":875                action = "step"876            elif short_action[0] == "C":877                action = "continue with signal 0x%s" % (short_action[1:])878            elif short_action == "S":879                action = "step with signal 0x%s" % (short_action[1:])880            else:881                action = short_action882            if s:883                s += ", "884            if tid == -1:885                got_other_threads = 1886                s += "other-threads:"887            else:888                s += "thread 0x%4.4x: %s" % (tid, action)889        if got_other_threads:890            print("extended_continue (%s)" % (s))891        else:892            print("extended_continue (%s, other-threads: suspend)" % (s))893    return False894 895 896def rsp_vCont(options, cmd, cmd_args, rsp):897    if cmd_args == "?":898        # Skip the leading 'vCont;'899        rsp = rsp[6:]900        modes = rsp.split(";")901        s = "%s: supported extended continue modes include: " % (cmd)902 903        for i, mode in enumerate(modes):904            if i:905                s += ", "906            if mode == "c":907                s += "continue"908            elif mode == "C":909                s += "continue with signal"910            elif mode == "s":911                s += "step"912            elif mode == "S":913                s += "step with signal"914            elif mode == "t":915                s += "stop"916            # else:917            #     s += 'unrecognized vCont mode: ', str(mode)918        print(s)919    elif rsp:920        if rsp[0] == "T" or rsp[0] == "S" or rsp[0] == "W" or rsp[0] == "X":921            rsp_stop_reply(options, cmd, cmd_args, rsp)922            return923        if rsp[0] == "O":924            print("stdout: %s" % (rsp))925            return926    else:927        print(928            "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)929        )930 931 932def cmd_vAttach(options, cmd, args):933    (extra_command, args) = args.split(";")934    if extra_command:935        print("%s%s(%s)" % (cmd, extra_command, args))936    else:937        print("attach(pid = %u)" % int(args, 16))938    return False939 940 941def cmd_qRegisterInfo(options, cmd, args):942    print("query_register_info(reg_num=%i)" % (int(args, 16)))943    return False944 945 946def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):947    global g_max_register_info_name_len948    print("query_register_info(reg_num=%i):" % (int(cmd_args, 16)), end=" ")949    if len(rsp) == 3 and rsp[0] == "E":950        g_max_register_info_name_len = 0951        for reg_info in g_register_infos:952            name_len = len(reg_info.name())953            if g_max_register_info_name_len < name_len:954                g_max_register_info_name_len = name_len955        print(" DONE")956    else:957        packet = Packet(rsp)958        reg_info = RegisterInfo(packet.get_key_value_pairs())959        g_register_infos.append(reg_info)960        print(reg_info)961    return False962 963 964def cmd_qThreadInfo(options, cmd, args):965    if cmd == "qfThreadInfo":966        query_type = "first"967    else:968        query_type = "subsequent"969    print("get_current_thread_list(type=%s)" % (query_type))970    return False971 972 973def rsp_qThreadInfo(options, cmd, cmd_args, rsp):974    packet = Packet(rsp)975    response_type = packet.get_char()976    if response_type == "m":977        tids = packet.split_hex(";", "big")978        for i, tid in enumerate(tids):979            if i:980                print(",", end=" ")981            print("0x%x" % (tid), end=" ")982        print()983    elif response_type == "l":984        print("END")985 986 987def rsp_hex_big_endian(options, cmd, cmd_args, rsp):988    if rsp == "":989        print("%s%s is not supported" % (cmd, cmd_args))990    else:991        packet = Packet(rsp)992        uval = packet.get_hex_uint("big")993        print("%s: 0x%x" % (cmd, uval))994 995 996def cmd_read_mem_bin(options, cmd, args):997    # x0x7fff5fc39200,0x200998    packet = Packet(args)999    addr = packet.get_hex_uint("big")1000    comma = packet.get_char()1001    size = packet.get_hex_uint("big")1002    print("binary_read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))1003    return False1004 1005 1006def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):1007    packet = Packet(cmd_args)1008    addr = packet.get_hex_uint("big")1009    comma = packet.get_char()1010    size = packet.get_hex_uint("big")1011    print("memory:")1012    if size > 0:1013        dump_hex_memory_buffer(addr, rsp)1014 1015 1016def cmd_read_memory(options, cmd, args):1017    packet = Packet(args)1018    addr = packet.get_hex_uint("big")1019    comma = packet.get_char()1020    size = packet.get_hex_uint("big")1021    print("read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))1022    return False1023 1024 1025def dump_hex_memory_buffer(addr, hex_byte_str):1026    packet = Packet(hex_byte_str)1027    idx = 01028    ascii = ""1029    uval = packet.get_hex_uint8()1030    while uval is not None:1031        if (idx % 16) == 0:1032            if ascii:1033                print("  ", ascii)1034                ascii = ""1035            print("0x%x:" % (addr + idx), end=" ")1036        print("%2.2x" % (uval), end=" ")1037        if 0x20 <= uval and uval < 0x7F:1038            ascii += "%c" % uval1039        else:1040            ascii += "."1041        uval = packet.get_hex_uint8()1042        idx = idx + 11043    if ascii:1044        print("  ", ascii)1045        ascii = ""1046 1047 1048def cmd_write_memory(options, cmd, args):1049    packet = Packet(args)1050    addr = packet.get_hex_uint("big")1051    if packet.get_char() != ",":1052        print("error: invalid write memory command (missing comma after address)")1053        return1054    size = packet.get_hex_uint("big")1055    if packet.get_char() != ":":1056        print("error: invalid write memory command (missing colon after size)")1057        return1058    print("write_memory (addr = 0x%16.16x, size = %u, data:" % (addr, size))1059    dump_hex_memory_buffer(addr, packet.str)1060    return False1061 1062 1063def cmd_alloc_memory(options, cmd, args):1064    packet = Packet(args)1065    byte_size = packet.get_hex_uint("big")1066    if packet.get_char() != ",":1067        print("error: invalid allocate memory command (missing comma after address)")1068        return1069    print(1070        "allocate_memory (byte-size = %u (0x%x), permissions = %s)"1071        % (byte_size, byte_size, packet.str)1072    )1073    return False1074 1075 1076def rsp_alloc_memory(options, cmd, cmd_args, rsp):1077    packet = Packet(rsp)1078    addr = packet.get_hex_uint("big")1079    print("addr = 0x%x" % addr)1080 1081 1082def cmd_dealloc_memory(options, cmd, args):1083    packet = Packet(args)1084    addr = packet.get_hex_uint("big")1085    if packet.get_char() != ",":1086        print("error: invalid allocate memory command (missing comma after address)")1087    else:1088        print("deallocate_memory (addr = 0x%x, permissions = %s)" % (addr, packet.str))1089    return False1090 1091 1092def rsp_memory_bytes(options, cmd, cmd_args, rsp):1093    addr = Packet(cmd_args).get_hex_uint("big")1094    dump_hex_memory_buffer(addr, rsp)1095 1096 1097def get_register_name_equal_value(options, reg_num, hex_value_str):1098    if reg_num < len(g_register_infos):1099        reg_info = g_register_infos[reg_num]1100        value_str = reg_info.get_value_from_hex_string(hex_value_str)1101        s = reg_info.name() + " = "1102        if options.symbolicator:1103            symbolicated_addresses = options.symbolicator.symbolicate(int(value_str, 0))1104            if symbolicated_addresses:1105                s += options.colors.magenta()1106                s += "%s" % symbolicated_addresses[0]1107                s += options.colors.reset()1108                return s1109        s += value_str1110        return s1111    else:1112        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)1113        return "reg(%u) = 0x%x" % (reg_num, reg_value)1114 1115 1116def cmd_read_one_reg(options, cmd, args):1117    packet = Packet(args)1118    reg_num = packet.get_hex_uint("big")1119    tid = get_thread_from_thread_suffix(packet.str)1120    name = None1121    if reg_num < len(g_register_infos):1122        name = g_register_infos[reg_num].name()1123    if packet.str:1124        packet.get_char()  # skip ;1125        thread_info = packet.get_key_value_pairs()1126        tid = int(thread_info[0][1], 16)1127    s = "read_register (reg_num=%u" % reg_num1128    if name:1129        s += " (%s)" % (name)1130    if tid is not None:1131        s += ", tid = 0x%4.4x" % (tid)1132    s += ")"1133    print(s)1134    return False1135 1136 1137def rsp_read_one_reg(options, cmd, cmd_args, rsp):1138    packet = Packet(cmd_args)1139    reg_num = packet.get_hex_uint("big")1140    print(get_register_name_equal_value(options, reg_num, rsp))1141 1142 1143def cmd_write_one_reg(options, cmd, args):1144    packet = Packet(args)1145    reg_num = packet.get_hex_uint("big")1146    if packet.get_char() != "=":1147        print("error: invalid register write packet")1148    else:1149        name = None1150        hex_value_str = packet.get_hex_chars()1151        tid = get_thread_from_thread_suffix(packet.str)1152        s = "write_register (reg_num=%u" % reg_num1153        if name:1154            s += " (%s)" % (name)1155        s += ", value = "1156        s += get_register_name_equal_value(options, reg_num, hex_value_str)1157        if tid is not None:1158            s += ", tid = 0x%4.4x" % (tid)1159        s += ")"1160        print(s)1161    return False1162 1163 1164def dump_all_regs(packet):1165    for reg_info in g_register_infos:1166        nibble_size = reg_info.bit_size() / 41167        hex_value_str = packet.get_hex_chars(nibble_size)1168        if hex_value_str is not None:1169            value = reg_info.get_value_from_hex_string(hex_value_str)1170            print("%*s = %s" % (g_max_register_info_name_len, reg_info.name(), value))1171        else:1172            return1173 1174 1175def cmd_read_all_regs(cmd, cmd_args):1176    packet = Packet(cmd_args)1177    packet.get_char()  # toss the 'g' command character1178    tid = get_thread_from_thread_suffix(packet.str)1179    if tid is not None:1180        print("read_all_register(thread = 0x%4.4x)" % tid)1181    else:1182        print("read_all_register()")1183    return False1184 1185 1186def rsp_read_all_regs(options, cmd, cmd_args, rsp):1187    packet = Packet(rsp)1188    dump_all_regs(packet)1189 1190 1191def cmd_write_all_regs(options, cmd, args):1192    packet = Packet(args)1193    print("write_all_registers()")1194    dump_all_regs(packet)1195    return False1196 1197 1198g_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]1199 1200 1201def cmd_bp(options, cmd, args):1202    if cmd == "Z":1203        s = "set_"1204    else:1205        s = "clear_"1206    packet = Packet(args)1207    bp_type = packet.get_hex_uint("big")1208    packet.get_char()  # Skip ,1209    bp_addr = packet.get_hex_uint("big")1210    packet.get_char()  # Skip ,1211    bp_size = packet.get_hex_uint("big")1212    s += g_bp_types[bp_type]1213    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)1214    print(s)1215    return False1216 1217 1218def cmd_mem_rgn_info(options, cmd, args):1219    packet = Packet(args)1220    packet.get_char()  # skip ':' character1221    addr = packet.get_hex_uint("big")1222    print("get_memory_region_info (addr=0x%x)" % (addr))1223    return False1224 1225 1226def cmd_kill(options, cmd, args):1227    print("kill_process()")1228    return False1229 1230 1231def cmd_jThreadsInfo(options, cmd, args):1232    print("jThreadsInfo()")1233    return False1234 1235 1236def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):1237    print("jGetLoadedDynamicLibrariesInfos()")1238    return False1239 1240 1241def decode_packet(s, start_index=0):1242    # print '\ndecode_packet("%s")' % (s[start_index:])1243    index = s.find("}", start_index)1244    have_escapes = index != -11245    if have_escapes:1246        normal_s = s[start_index:index]1247    else:1248        normal_s = s[start_index:]1249    # print 'normal_s = "%s"' % (normal_s)1250    if have_escapes:1251        escape_char = "%c" % (ord(s[index + 1]) ^ 0x20)1252        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)1253        return normal_s + escape_char + decode_packet(s, index + 2)1254    else:1255        return normal_s1256 1257 1258def rsp_json(options, cmd, cmd_args, rsp):1259    print("%s() reply:" % (cmd))1260    if not rsp:1261        return1262    try:1263        json_tree = json.loads(rsp)1264        print(json.dumps(json_tree, indent=4, separators=(",", ": ")))1265    except json.JSONDecodeError:1266        return1267 1268 1269def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):1270    if cmd_args:1271        rsp_json(options, cmd, cmd_args, rsp)1272    else:1273        rsp_ok_means_supported(options, cmd, cmd_args, rsp)1274 1275 1276gdb_remote_commands = {1277    "\\?": {"cmd": cmd_stop_reply, "rsp": rsp_stop_reply, "name": "stop reply pacpket"},1278    "qThreadStopInfo": {1279        "cmd": cmd_qThreadStopInfo,1280        "rsp": rsp_stop_reply,1281        "name": "stop reply pacpket",1282    },1283    "QStartNoAckMode": {1284        "cmd": cmd_query_packet,1285        "rsp": rsp_ok_means_supported,1286        "name": "query if no ack mode is supported",1287    },1288    "QThreadSuffixSupported": {1289        "cmd": cmd_query_packet,1290        "rsp": rsp_ok_means_supported,1291        "name": "query if thread suffix is supported",1292    },1293    "QListThreadsInStopReply": {1294        "cmd": cmd_query_packet,1295        "rsp": rsp_ok_means_supported,1296        "name": "query if threads in stop reply packets are supported",1297    },1298    "QSetDetachOnError:": {1299        "cmd": cmd_QSetWithUnsigned,1300        "rsp": rsp_ok_means_success,1301        "name": "set if we should detach on error",1302    },1303    "QSetDisableASLR:": {1304        "cmd": cmd_QSetWithUnsigned,1305        "rsp": rsp_ok_means_success,1306        "name": "set if we should disable ASLR",1307    },1308    "qLaunchSuccess": {1309        "cmd": cmd_query_packet,1310        "rsp": rsp_ok_means_success,1311        "name": "check on launch success for the A packet",1312    },1313    "A": {"cmd": cmd_A, "rsp": rsp_ok_means_success, "name": "launch process"},1314    "QLaunchArch:": {1315        "cmd": cmd_QSetWithString,1316        "rsp": rsp_ok_means_supported,1317        "name": "set the arch to launch in case the file contains multiple architectures",1318    },1319    "qVAttachOrWaitSupported": {1320        "cmd": cmd_query_packet,1321        "rsp": rsp_ok_means_supported,1322        "name": "set the launch architecture",1323    },1324    "qHostInfo": {1325        "cmd": cmd_query_packet,1326        "rsp": rsp_dump_key_value_pairs,1327        "name": "get host information",1328    },1329    "qC": {"cmd": cmd_qC, "rsp": rsp_qC, "name": "return the current thread ID"},1330    "vCont": {"cmd": cmd_vCont, "rsp": rsp_vCont, "name": "extended continue command"},1331    "qSpeedTest": {1332        "cmd": cmd_qSpeedTest,1333        "rsp": rsp_qSpeedTest,1334        "name": "speed test packdet",1335    },1336    "vAttach": {"cmd": cmd_vAttach, "rsp": rsp_stop_reply, "name": "attach to process"},1337    "c": {"cmd": cmd_c, "rsp": rsp_stop_reply, "name": "continue"},1338    "s": {"cmd": cmd_s, "rsp": rsp_stop_reply, "name": "step"},1339    "qRegisterInfo": {1340        "cmd": cmd_qRegisterInfo,1341        "rsp": rsp_qRegisterInfo,1342        "name": "query register info",1343    },1344    "qfThreadInfo": {1345        "cmd": cmd_qThreadInfo,1346        "rsp": rsp_qThreadInfo,1347        "name": "get current thread list",1348    },1349    "qsThreadInfo": {1350        "cmd": cmd_qThreadInfo,1351        "rsp": rsp_qThreadInfo,1352        "name": "get current thread list",1353    },1354    "qShlibInfoAddr": {1355        "cmd": cmd_query_packet,1356        "rsp": rsp_hex_big_endian,1357        "name": "get shared library info address",1358    },1359    "qMemoryRegionInfo": {1360        "cmd": cmd_mem_rgn_info,1361        "rsp": rsp_dump_key_value_pairs,1362        "name": "get memory region information",1363    },1364    "qProcessInfo": {1365        "cmd": cmd_query_packet,1366        "rsp": rsp_dump_key_value_pairs,1367        "name": "get process info",1368    },1369    "qSupported": {1370        "cmd": cmd_query_packet,1371        "rsp": rsp_ok_means_supported,1372        "name": "query supported",1373    },1374    "qXfer:": {"cmd": cmd_qXfer, "rsp": rsp_qXfer, "name": "qXfer"},1375    "qSymbol:": {"cmd": cmd_qSymbol, "rsp": rsp_qSymbol, "name": "qSymbol"},1376    "QSetSTDIN:": {1377        "cmd": cmd_QSetWithHexString,1378        "rsp": rsp_ok_means_success,1379        "name": "set STDIN prior to launching with A packet",1380    },1381    "QSetSTDOUT:": {1382        "cmd": cmd_QSetWithHexString,1383        "rsp": rsp_ok_means_success,1384        "name": "set STDOUT prior to launching with A packet",1385    },1386    "QSetSTDERR:": {1387        "cmd": cmd_QSetWithHexString,1388        "rsp": rsp_ok_means_success,1389        "name": "set STDERR prior to launching with A packet",1390    },1391    "QEnvironment:": {1392        "cmd": cmd_QSetWithString,1393        "rsp": rsp_ok_means_success,1394        "name": "set an environment variable prior to launching with A packet",1395    },1396    "QEnvironmentHexEncoded:": {1397        "cmd": cmd_QSetWithHexString,1398        "rsp": rsp_ok_means_success,1399        "name": "set an environment variable prior to launching with A packet",1400    },1401    "x": {1402        "cmd": cmd_read_mem_bin,1403        "rsp": rsp_mem_bin_bytes,1404        "name": "read memory binary",1405    },1406    "X": {1407        "cmd": cmd_write_memory,1408        "rsp": rsp_ok_means_success,1409        "name": "write memory binary",1410    },1411    "m": {"cmd": cmd_read_memory, "rsp": rsp_memory_bytes, "name": "read memory"},1412    "M": {"cmd": cmd_write_memory, "rsp": rsp_ok_means_success, "name": "write memory"},1413    "_M": {"cmd": cmd_alloc_memory, "rsp": rsp_alloc_memory, "name": "allocate memory"},1414    "_m": {1415        "cmd": cmd_dealloc_memory,1416        "rsp": rsp_ok_means_success,1417        "name": "deallocate memory",1418    },1419    "p": {1420        "cmd": cmd_read_one_reg,1421        "rsp": rsp_read_one_reg,1422        "name": "read single register",1423    },1424    "P": {1425        "cmd": cmd_write_one_reg,1426        "rsp": rsp_ok_means_success,1427        "name": "write single register",1428    },1429    "g": {1430        "cmd": cmd_read_all_regs,1431        "rsp": rsp_read_all_regs,1432        "name": "read all registers",1433    },1434    "G": {1435        "cmd": cmd_write_all_regs,1436        "rsp": rsp_ok_means_success,1437        "name": "write all registers",1438    },1439    "z": {1440        "cmd": cmd_bp,1441        "rsp": rsp_ok_means_success,1442        "name": "clear breakpoint or watchpoint",1443    },1444    "Z": {1445        "cmd": cmd_bp,1446        "rsp": rsp_ok_means_success,1447        "name": "set breakpoint or watchpoint",1448    },1449    "k": {"cmd": cmd_kill, "rsp": rsp_stop_reply, "name": "kill process"},1450    "jThreadsInfo": {1451        "cmd": cmd_jThreadsInfo,1452        "rsp": rsp_json,1453        "name": "JSON get all threads info",1454    },1455    "jGetLoadedDynamicLibrariesInfos:": {1456        "cmd": cmd_jGetLoadedDynamicLibrariesInfos,1457        "rsp": rsp_jGetLoadedDynamicLibrariesInfos,1458        "name": "JSON get loaded dynamic libraries",1459    },1460}1461 1462 1463def calculate_mean_and_standard_deviation(floats):1464    sum = 0.01465    count = len(floats)1466    if count == 0:1467        return (0.0, 0.0)1468    for f in floats:1469        sum += f1470    mean = sum / count1471    accum = 0.01472    for f in floats:1473        delta = f - mean1474        accum += delta * delta1475 1476    std_dev = math.sqrt(accum / (count - 1))1477    return (mean, std_dev)1478 1479 1480def parse_gdb_log_file(path, options):1481    f = open(path)1482    parse_gdb_log(f, options)1483    f.close()1484 1485 1486def round_up(n, incr):1487    return float(((int(n) + incr) / incr) * incr)1488 1489 1490def plot_latencies(sec_times):1491    # import numpy as np1492    import matplotlib.pyplot as plt1493 1494    for i, name in enumerate(sec_times.keys()):1495        times = sec_times[name]1496        if len(times) <= 1:1497            continue1498        plt.subplot(2, 1, 1)1499        plt.title('Packet "%s" Times' % (name))1500        plt.xlabel("Packet")1501        units = "ms"1502        adj_times = []1503        max_time = 0.01504        for time in times:1505            time = time * 1000.01506            adj_times.append(time)1507            if time > max_time:1508                max_time = time1509        if max_time < 1.0:1510            units = "us"1511            max_time = 0.01512            for i in range(len(adj_times)):1513                adj_times[i] *= 1000.01514                if adj_times[i] > max_time:1515                    max_time = adj_times[i]1516        plt.ylabel("Time (%s)" % (units))1517        max_y = None1518        for i in [5.0, 10.0, 25.0, 50.0]:1519            if max_time < i:1520                max_y = round_up(max_time, i)1521                break1522        if max_y is None:1523            max_y = round_up(max_time, 100.0)1524        plt.ylim(0.0, max_y)1525        plt.plot(adj_times, "o-")1526        plt.show()1527 1528 1529def parse_gdb_log(file, options):1530    """Parse a GDB log file that was generated by enabling logging with:1531    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets1532    This log file will contain timestamps and this function will then normalize1533    those packets to be relative to the first value timestamp that is found and1534    show delta times between log lines and also keep track of how long it takes1535    for GDB remote commands to make a send/receive round trip. This can be1536    handy when trying to figure out why some operation in the debugger is taking1537    a long time during a preset set of debugger commands."""1538 1539    tricky_commands = ["qRegisterInfo"]1540    timestamp_regex = re.compile(r"(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$")1541    packet_name_regex = re.compile("([A-Za-z_]+)[^a-z]")1542    packet_transmit_name_regex = re.compile(1543        "(?P<direction>send|read) packet: (?P<packet>.*)"1544    )1545    packet_contents_name_regex = re.compile(r"\$([^#]*)#[0-9a-fA-F]{2}")1546    packet_checksum_regex = re.compile(".*#[0-9a-fA-F]{2}$")1547    packet_names_regex_str = "(" + "|".join(gdb_remote_commands.keys()) + ")(.*)"1548    packet_names_regex = re.compile(packet_names_regex_str)1549 1550    base_time = 0.01551    last_time = 0.01552    min_time = 100000000.01553    packet_total_times = {}1554    all_packet_times = []1555    packet_times = {}1556    packet_counts = {}1557    lines = file.read().splitlines()1558    last_command = None1559    last_command_args = None1560    last_command_packet = None1561    hide_next_response = False1562    num_lines = len(lines)1563    skip_count = 01564    for line_index, line in enumerate(lines):1565        # See if we need to skip any lines1566        if skip_count > 0:1567            skip_count -= 11568            continue1569        m = packet_transmit_name_regex.search(line)1570        is_command = False1571        direction = None1572        if m:1573            direction = m.group("direction")1574            is_command = direction == "send"1575            packet = m.group("packet")1576            sys.stdout.write(options.colors.green())1577            if not options.quiet and not hide_next_response:1578                print("#  ", line)1579            sys.stdout.write(options.colors.reset())1580 1581            # print 'direction = "%s", packet = "%s"' % (direction, packet)1582 1583            if packet[0] == "+":1584                if is_command:1585                    print("-->", end=" ")1586                else:1587                    print("<--", end=" ")1588                if not options.quiet:1589                    print("ACK")1590                continue1591            elif packet[0] == "-":1592                if is_command:1593                    print("-->", end=" ")1594                else:1595                    print("<--", end=" ")1596                if not options.quiet:1597                    print("NACK")1598                continue1599            elif packet[0] == "$":1600                m = packet_contents_name_regex.match(packet)1601                if not m and packet[0] == "$":1602                    multiline_packet = packet1603                    idx = line_index + 11604                    while idx < num_lines:1605                        if not options.quiet and not hide_next_response:1606                            print("#  ", lines[idx])1607                        multiline_packet += lines[idx]1608                        m = packet_contents_name_regex.match(multiline_packet)1609                        if m:1610                            packet = multiline_packet1611                            skip_count = idx - line_index1612                            break1613                        else:1614                            idx += 11615                if m:1616                    if is_command:1617                        print("-->", end=" ")1618                    else:1619                        print("<--", end=" ")1620                    contents = decode_packet(m.group(1))1621                    if is_command:1622                        hide_next_response = False1623                        m = packet_names_regex.match(contents)1624                        if m:1625                            last_command = m.group(1)1626                            if last_command == "?":1627                                last_command = "\\?"1628                            packet_name = last_command1629                            last_command_args = m.group(2)1630                            last_command_packet = contents1631                            hide_next_response = gdb_remote_commands[last_command][1632                                "cmd"1633                            ](options, last_command, last_command_args)1634                        else:1635                            packet_match = packet_name_regex.match(contents)1636                            if packet_match:1637                                packet_name = packet_match.group(1)1638                                for tricky_cmd in tricky_commands:1639                                    if packet_name.find(tricky_cmd) == 0:1640                                        packet_name = tricky_cmd1641                            else:1642                                packet_name = contents1643                            last_command = None1644                            last_command_args = None1645                            last_command_packet = None1646                    elif last_command:1647                        gdb_remote_commands[last_command]["rsp"](1648                            options, last_command, last_command_args, contents1649                        )1650                else:1651                    print('error: invalid packet: "', packet, '"')1652            else:1653                print("???")1654        else:1655            print("## ", line)1656        match = timestamp_regex.match(line)1657        if match:1658            curr_time = float(match.group(2))1659            if last_time and not is_command:1660                delta = curr_time - last_time1661                all_packet_times.append(delta)1662            delta = 0.01663            if base_time:1664                delta = curr_time - last_time1665            else:1666                base_time = curr_time1667 1668            if not is_command:1669                if line.find("read packet: $") >= 0 and packet_name:1670                    if packet_name in packet_total_times:1671                        packet_total_times[packet_name] += delta1672                        packet_counts[packet_name] += 11673                    else:1674                        packet_total_times[packet_name] = delta1675                        packet_counts[packet_name] = 11676                    if packet_name not in packet_times:1677                        packet_times[packet_name] = []1678                    packet_times[packet_name].append(delta)1679                    packet_name = None1680                if min_time > delta:1681                    min_time = delta1682 1683            if not options or not options.quiet:1684                print(1685                    "%s%.6f %+.6f%s"1686                    % (match.group(1), curr_time - base_time, delta, match.group(3))1687                )1688            last_time = curr_time1689        # else:1690        #     print line1691    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)1692    if average and std_dev:1693        print(1694            "%u packets with average packet time of %f and standard deviation of %f"1695            % (len(all_packet_times), average, std_dev)1696        )1697    if packet_total_times:1698        total_packet_time = 0.01699        total_packet_count = 01700        for key, vvv in packet_total_times.items():1701            # print '  key = (%s) "%s"' % (type(key), key)1702            # print 'value = (%s) %s' % (type(vvv), vvv)1703            # if type(vvv) == 'float':1704            total_packet_time += vvv1705        for key, vvv in packet_counts.items():1706            total_packet_count += vvv1707 1708        print("#------------------------------------------------------------")1709        print("# Packet timing summary:")1710        print(1711            "# Totals: time = %6f, count = %6d"1712            % (total_packet_time, total_packet_count)1713        )1714        print("# Min packet time: time = %6f" % (min_time))1715        print("#------------------------------------------------------------")1716        print("# Packet                   Time (sec)  Percent Count  Latency")1717        print("#------------------------- ----------- ------- ------ -------")1718        if options and options.sort_count:1719            res = sorted(packet_counts, key=packet_counts.__getitem__, reverse=True)1720        else:1721            res = sorted(1722                packet_total_times, key=packet_total_times.__getitem__, reverse=True1723            )1724 1725        if last_time > 0.0:1726            for item in res:1727                packet_total_time = packet_total_times[item]1728                packet_percent = (packet_total_time / total_packet_time) * 100.01729                packet_count = packet_counts[item]1730                print(1731                    "  %24s %11.6f  %5.2f%% %6d %9.6f"1732                    % (1733                        item,1734                        packet_total_time,1735                        packet_percent,1736                        packet_count,1737                        float(packet_total_time) / float(packet_count),1738                    )1739                )1740        if options and options.plot:1741            plot_latencies(packet_times)1742 1743 1744if __name__ == "__main__":1745    usage = "usage: gdbremote [options]"1746    description = """The command disassembles a GDB remote packet log."""1747    parser = optparse.OptionParser(1748        description=description, prog="gdbremote", usage=usage1749    )1750    parser.add_option(1751        "-v",1752        "--verbose",1753        action="store_true",1754        dest="verbose",1755        help="display verbose debug info",1756        default=False,1757    )1758    parser.add_option(1759        "-q",1760        "--quiet",1761        action="store_true",1762        dest="quiet",1763        help="display verbose debug info",1764        default=False,1765    )1766    parser.add_option(1767        "-C",1768        "--color",1769        action="store_true",1770        dest="color",1771        help="add terminal colors",1772        default=False,1773    )1774    parser.add_option(1775        "-c",1776        "--sort-by-count",1777        action="store_true",1778        dest="sort_count",1779        help="display verbose debug info",1780        default=False,1781    )1782    parser.add_option(1783        "--crashlog",1784        type="string",1785        dest="crashlog",1786        help="symbolicate using a darwin crash log file",1787        default=False,1788    )1789    try:1790        (options, args) = parser.parse_args(sys.argv[1:])1791    except:1792        print("error: argument error")1793        sys.exit(1)1794 1795    options.colors = TerminalColors(options.color)1796    options.symbolicator = None1797    if options.crashlog:1798        import lldb1799 1800        lldb.debugger = lldb.SBDebugger.Create()1801        import lldb.macosx.crashlog1802 1803        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)1804        print("%s" % (options.symbolicator))1805 1806    # This script is being run from the command line, create a debugger in case we are1807    # going to use any debugger functions in our function.1808    if len(args):1809        for file in args:1810            print(1811                "#----------------------------------------------------------------------"1812            )1813            print("# GDB remote log file: '%s'" % file)1814            print(1815                "#----------------------------------------------------------------------"1816            )1817            parse_gdb_log_file(file, options)1818        if options.symbolicator:1819            print("%s" % (options.symbolicator))1820    else:1821        parse_gdb_log(sys.stdin, options)1822 1823 1824def __lldb_init_module(debugger, internal_dict):1825    # This initializer is being run from LLDB in the embedded command interpreter1826    # Add any commands contained in this module to LLDB1827    debugger.HandleCommand(1828        "command script add -o -f gdbremote.start_gdb_log start_gdb_log"1829    )1830    debugger.HandleCommand(1831        "command script add -o -f gdbremote.stop_gdb_log stop_gdb_log"1832    )1833    print(1834        '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'1835    )1836