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