1#!/usr/bin/python 2 3#---------------------------------------------------------------------- 4# This module will enable GDB remote packet logging when the 5# 'start_gdb_log' command is called with a filename to log to. When the 6# 'stop_gdb_log' command is called, it will disable the logging and 7# print out statistics about how long commands took to execute and also 8# will primnt ou 9# 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" just 12# 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.py 15# Or it can be added to your ~/.lldbinit file so this module is always 16# available. 17#---------------------------------------------------------------------- 18 19import binascii 20import commands 21import math 22import optparse 23import os 24import re 25import shlex 26import string 27import sys 28import tempfile 29import xml.etree.ElementTree as ET 30 31#---------------------------------------------------------------------- 32# Global variables 33#---------------------------------------------------------------------- 34g_log_file = '' 35g_byte_order = 'little' 36g_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)') 37g_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)') 38 39class TerminalColors: 40 '''Simple terminal colors class''' 41 def __init__(self, enabled = True): 42 # TODO: discover terminal type from "file" and disable if 43 # it can't handle the color codes 44 self.enabled = enabled 45 46 def reset(self): 47 '''Reset all terminal colors and formatting.''' 48 if self.enabled: 49 return "\x1b[0m"; 50 return '' 51 52 def bold(self, on = True): 53 '''Enable or disable bold depending on the "on" parameter.''' 54 if self.enabled: 55 if on: 56 return "\x1b[1m"; 57 else: 58 return "\x1b[22m"; 59 return '' 60 61 def italics(self, on = True): 62 '''Enable or disable italics depending on the "on" parameter.''' 63 if self.enabled: 64 if on: 65 return "\x1b[3m"; 66 else: 67 return "\x1b[23m"; 68 return '' 69 70 def underline(self, on = True): 71 '''Enable or disable underline depending on the "on" parameter.''' 72 if self.enabled: 73 if on: 74 return "\x1b[4m"; 75 else: 76 return "\x1b[24m"; 77 return '' 78 79 def inverse(self, on = True): 80 '''Enable or disable inverse depending on the "on" parameter.''' 81 if self.enabled: 82 if on: 83 return "\x1b[7m"; 84 else: 85 return "\x1b[27m"; 86 return '' 87 88 def strike(self, on = True): 89 '''Enable or disable strike through depending on the "on" parameter.''' 90 if self.enabled: 91 if on: 92 return "\x1b[9m"; 93 else: 94 return "\x1b[29m"; 95 return '' 96 97 def black(self, fg = True): 98 '''Set the foreground or background color to black. 99 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 100 if self.enabled: 101 if fg: 102 return "\x1b[30m"; 103 else: 104 return "\x1b[40m"; 105 return '' 106 107 def red(self, fg = True): 108 '''Set the foreground or background color to red. 109 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 110 if self.enabled: 111 if fg: 112 return "\x1b[31m"; 113 else: 114 return "\x1b[41m"; 115 return '' 116 117 def green(self, fg = True): 118 '''Set the foreground or background color to green. 119 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 120 if self.enabled: 121 if fg: 122 return "\x1b[32m"; 123 else: 124 return "\x1b[42m"; 125 return '' 126 127 def yellow(self, fg = True): 128 '''Set the foreground or background color to yellow. 129 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 130 if self.enabled: 131 if fg: 132 return "\x1b[33m"; 133 else: 134 return "\x1b[43m"; 135 return '' 136 137 def blue(self, fg = True): 138 '''Set the foreground or background color to blue. 139 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 140 if self.enabled: 141 if fg: 142 return "\x1b[34m"; 143 else: 144 return "\x1b[44m"; 145 return '' 146 147 def magenta(self, fg = True): 148 '''Set the foreground or background color to magenta. 149 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 150 if self.enabled: 151 if fg: 152 return "\x1b[35m"; 153 else: 154 return "\x1b[45m"; 155 return '' 156 157 def cyan(self, fg = True): 158 '''Set the foreground or background color to cyan. 159 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 160 if self.enabled: 161 if fg: 162 return "\x1b[36m"; 163 else: 164 return "\x1b[46m"; 165 return '' 166 167 def white(self, fg = True): 168 '''Set the foreground or background color to white. 169 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 170 if self.enabled: 171 if fg: 172 return "\x1b[37m"; 173 else: 174 return "\x1b[47m"; 175 return '' 176 177 def default(self, fg = True): 178 '''Set the foreground or background color to the default. 179 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 180 if self.enabled: 181 if fg: 182 return "\x1b[39m"; 183 else: 184 return "\x1b[49m"; 185 return '' 186 187 188def start_gdb_log(debugger, command, result, dict): 189 '''Start logging GDB remote packets by enabling logging with timestamps and 190 thread safe logging. Follow a call to this function with a call to "stop_gdb_log" 191 in order to dump out the commands.''' 192 global g_log_file 193 command_args = shlex.split(command) 194 usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]" 195 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 196 be aggregated and displayed.''' 197 parser = optparse.OptionParser(description=description, prog='start_gdb_log',usage=usage) 198 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) 199 try: 200 (options, args) = parser.parse_args(command_args) 201 except: 202 return 203 204 if g_log_file: 205 result.PutCString ('error: logging is already in progress with file "%s"', g_log_file) 206 else: 207 args_len = len(args) 208 if args_len == 0: 209 g_log_file = tempfile.mktemp() 210 elif len(args) == 1: 211 g_log_file = args[0] 212 213 if g_log_file: 214 debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % g_log_file); 215 result.PutCString ("GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % g_log_file) 216 return 217 218 result.PutCString ('error: invalid log file path') 219 result.PutCString (usage) 220 221def stop_gdb_log(debugger, command, result, dict): 222 '''Stop logging GDB remote packets to the file that was specified in a call 223 to "start_gdb_log" and normalize the timestamps to be relative to the first 224 timestamp in the log file. Also print out statistics for how long each 225 command took to allow performance bottlenecks to be determined.''' 226 global g_log_file 227 # Any commands whose names might be followed by more valid C identifier 228 # characters must be listed here 229 command_args = shlex.split(command) 230 usage = "usage: stop_gdb_log [options]" 231 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.''' 232 parser = optparse.OptionParser(description=description, prog='stop_gdb_log',usage=usage) 233 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) 234 parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False) 235 parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False) 236 parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False) 237 parser.add_option('-s', '--symbolicate', action='store_true', dest='symbolicate', help='symbolicate addresses in log using current "lldb.target"', default=False) 238 try: 239 (options, args) = parser.parse_args(command_args) 240 except: 241 return 242 options.colors = TerminalColors(options.color) 243 options.symbolicator = None 244 if options.symbolicate: 245 if lldb.target: 246 import lldb.utils.symbolication 247 options.symbolicator = lldb.utils.symbolication.Symbolicator() 248 options.symbolicator.target = lldb.target 249 else: 250 print "error: can't symbolicate without a target" 251 252 if not g_log_file: 253 result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"') 254 elif os.path.exists (g_log_file): 255 if len(args) == 0: 256 debugger.HandleCommand('log disable gdb-remote packets'); 257 result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % g_log_file) 258 parse_gdb_log_file (g_log_file, options) 259 else: 260 result.PutCString (usage) 261 else: 262 print 'error: the GDB packet log file "%s" does not exist' % g_log_file 263 264def is_hex_byte(str): 265 if len(str) == 2: 266 return str[0] in string.hexdigits and str[1] in string.hexdigits; 267 return False 268 269# global register info list 270g_register_infos = list() 271g_max_register_info_name_len = 0 272 273class RegisterInfo: 274 """Class that represents register information""" 275 def __init__(self, kvp): 276 self.info = dict() 277 for kv in kvp: 278 key = kv[0] 279 value = kv[1] 280 self.info[key] = value 281 def name(self): 282 '''Get the name of the register.''' 283 if self.info and 'name' in self.info: 284 return self.info['name'] 285 return None 286 287 def bit_size(self): 288 '''Get the size in bits of the register.''' 289 if self.info and 'bitsize' in self.info: 290 return int(self.info['bitsize']) 291 return 0 292 293 def byte_size(self): 294 '''Get the size in bytes of the register.''' 295 return self.bit_size() / 8 296 297 def get_value_from_hex_string(self, hex_str): 298 '''Dump the register value given a native byte order encoded hex ASCII byte string.''' 299 encoding = self.info['encoding'] 300 bit_size = self.bit_size() 301 packet = Packet(hex_str) 302 if encoding == 'uint': 303 uval = packet.get_hex_uint(g_byte_order) 304 if bit_size == 8: 305 return '0x%2.2x' % (uval) 306 elif bit_size == 16: 307 return '0x%4.4x' % (uval) 308 elif bit_size == 32: 309 return '0x%8.8x' % (uval) 310 elif bit_size == 64: 311 return '0x%16.16x' % (uval) 312 bytes = list(); 313 uval = packet.get_hex_uint8() 314 while uval != None: 315 bytes.append(uval) 316 uval = packet.get_hex_uint8() 317 value_str = '0x' 318 if g_byte_order == 'little': 319 bytes.reverse() 320 for byte in bytes: 321 value_str += '%2.2x' % byte 322 return '%s' % (value_str) 323 324 def __str__(self): 325 '''Dump the register info key/value pairs''' 326 s = '' 327 for key in self.info.keys(): 328 if s: 329 s += ', ' 330 s += "%s=%s " % (key, self.info[key]) 331 return s 332 333class Packet: 334 """Class that represents a packet that contains string data""" 335 def __init__(self, packet_str): 336 self.str = packet_str 337 338 def peek_char(self): 339 ch = 0 340 if self.str: 341 ch = self.str[0] 342 return ch 343 344 def get_char(self): 345 ch = 0 346 if self.str: 347 ch = self.str[0] 348 self.str = self.str[1:] 349 return ch 350 351 def skip_exact_string(self, s): 352 if self.str and self.str.startswith(s): 353 self.str = self.str[len(s):] 354 return True 355 else: 356 return False 357 358 def get_thread_id(self, fail_value = -1): 359 match = g_number_regex.match (self.str) 360 if match: 361 number_str = match.group(1) 362 self.str = self.str[len(number_str):] 363 return int(number_str, 0) 364 else: 365 return fail_value 366 367 def get_hex_uint8(self): 368 if self.str and len(self.str) >= 2 and self.str[0] in string.hexdigits and self.str[1] in string.hexdigits: 369 uval = int(self.str[0:2], 16) 370 self.str = self.str[2:] 371 return uval 372 return None 373 374 def get_hex_uint16(self, byte_order): 375 uval = 0 376 if byte_order == 'big': 377 uval |= self.get_hex_uint8() << 8 378 uval |= self.get_hex_uint8() 379 else: 380 uval |= self.get_hex_uint8() 381 uval |= self.get_hex_uint8() << 8 382 return uval 383 384 def get_hex_uint32(self, byte_order): 385 uval = 0 386 if byte_order == 'big': 387 uval |= self.get_hex_uint8() << 24 388 uval |= self.get_hex_uint8() << 16 389 uval |= self.get_hex_uint8() << 8 390 uval |= self.get_hex_uint8() 391 else: 392 uval |= self.get_hex_uint8() 393 uval |= self.get_hex_uint8() << 8 394 uval |= self.get_hex_uint8() << 16 395 uval |= self.get_hex_uint8() << 24 396 return uval 397 398 def get_hex_uint64(self, byte_order): 399 uval = 0 400 if byte_order == 'big': 401 uval |= self.get_hex_uint8() << 56 402 uval |= self.get_hex_uint8() << 48 403 uval |= self.get_hex_uint8() << 40 404 uval |= self.get_hex_uint8() << 32 405 uval |= self.get_hex_uint8() << 24 406 uval |= self.get_hex_uint8() << 16 407 uval |= self.get_hex_uint8() << 8 408 uval |= self.get_hex_uint8() 409 else: 410 uval |= self.get_hex_uint8() 411 uval |= self.get_hex_uint8() << 8 412 uval |= self.get_hex_uint8() << 16 413 uval |= self.get_hex_uint8() << 24 414 uval |= self.get_hex_uint8() << 32 415 uval |= self.get_hex_uint8() << 40 416 uval |= self.get_hex_uint8() << 48 417 uval |= self.get_hex_uint8() << 56 418 return uval 419 420 def get_number(self, fail_value=-1): 421 '''Get a number from the packet. The number must be in big endian format and should be parsed 422 according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with 423 [1-9] means decimal, etc)''' 424 match = g_number_regex.match (self.str) 425 if match: 426 number_str = match.group(1) 427 self.str = self.str[len(number_str):] 428 return int(number_str, 0) 429 else: 430 return fail_value 431 432 433 def get_hex_ascii_str(self, n=0): 434 hex_chars = self.get_hex_chars(n) 435 if hex_chars: 436 return binascii.unhexlify(hex_chars) 437 else: 438 return None 439 440 def get_hex_chars(self, n = 0): 441 str_len = len(self.str) 442 if n == 0: 443 # n was zero, so we need to determine all hex chars and 444 # stop when we hit the end of the string of a non-hex character 445 while n < str_len and self.str[n] in string.hexdigits: 446 n = n + 1 447 else: 448 if n > str_len: 449 return None # Not enough chars 450 # Verify all chars are hex if a length was specified 451 for i in range(n): 452 if self.str[i] not in string.hexdigits: 453 return None # Not all hex digits 454 if n == 0: 455 return None 456 hex_str = self.str[0:n] 457 self.str = self.str[n:] 458 return hex_str 459 460 def get_hex_uint(self, byte_order, n = 0): 461 if byte_order == 'big': 462 hex_str = self.get_hex_chars(n) 463 if hex_str == None: 464 return None 465 return int(hex_str, 16) 466 else: 467 uval = self.get_hex_uint8() 468 if uval == None: 469 return None 470 uval_result = 0 471 shift = 0 472 while uval != None: 473 uval_result |= (uval << shift) 474 shift += 8 475 uval = self.get_hex_uint8() 476 return uval_result 477 478 def get_key_value_pairs(self): 479 kvp = list() 480 if ';' in self.str: 481 key_value_pairs = string.split(self.str, ';') 482 for key_value_pair in key_value_pairs: 483 if len(key_value_pair): 484 kvp.append(string.split(key_value_pair, ':')) 485 return kvp 486 487 def split(self, ch): 488 return string.split(self.str, ch) 489 490 def split_hex(self, ch, byte_order): 491 hex_values = list() 492 strings = string.split(self.str, ch) 493 for str in strings: 494 hex_values.append(Packet(str).get_hex_uint(byte_order)) 495 return hex_values 496 497 def __str__(self): 498 return self.str 499 500 def __len__(self): 501 return len(self.str) 502 503g_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);') 504def get_thread_from_thread_suffix(str): 505 if str: 506 match = g_thread_suffix_regex.match (str) 507 if match: 508 return int(match.group(1), 16) 509 return None 510 511def cmd_qThreadStopInfo(options, cmd, args): 512 packet = Packet(args) 513 tid = packet.get_hex_uint('big') 514 print "get_thread_stop_info (tid = 0x%x)" % (tid) 515 516def cmd_stop_reply(options, cmd, args): 517 print "get_last_stop_info()" 518 return False 519 520def rsp_stop_reply(options, cmd, cmd_args, rsp): 521 global g_byte_order 522 packet = Packet(rsp) 523 stop_type = packet.get_char() 524 if stop_type == 'T' or stop_type == 'S': 525 signo = packet.get_hex_uint8() 526 key_value_pairs = packet.get_key_value_pairs() 527 for key_value_pair in key_value_pairs: 528 key = key_value_pair[0] 529 if is_hex_byte(key): 530 reg_num = Packet(key).get_hex_uint8() 531 if reg_num < len(g_register_infos): 532 reg_info = g_register_infos[reg_num] 533 key_value_pair[0] = reg_info.name() 534 key_value_pair[1] = reg_info.get_value_from_hex_string (key_value_pair[1]) 535 elif key == 'jthreads' or key == 'jstopinfo': 536 key_value_pair[1] = binascii.unhexlify(key_value_pair[1]) 537 key_value_pairs.insert(0, ['signal', signo]) 538 print 'Stop reply:' 539 dump_key_value_pairs (key_value_pairs) 540 elif stop_type == 'W': 541 exit_status = packet.get_hex_uint8() 542 print 'exit (status=%i)' % exit_status 543 elif stop_type == 'O': 544 print 'stdout = %s' % packet.str 545 546 547def cmd_unknown_packet(options, cmd, args): 548 if args: 549 print "cmd: %s, args: %s", cmd, args 550 else: 551 print "cmd: %s", cmd 552 return False 553 554def cmd_qSymbol(options, cmd, args): 555 if args == ':': 556 print 'ready to serve symbols' 557 else: 558 packet = Packet(args) 559 symbol_addr = packet.get_hex_uint('big') 560 if symbol_addr is None: 561 if packet.skip_exact_string(':'): 562 symbol_name = packet.get_hex_ascii_str() 563 print 'lookup_symbol("%s") -> symbol not available yet' % (symbol_name) 564 else: 565 print 'error: bad command format' 566 else: 567 if packet.skip_exact_string(':'): 568 symbol_name = packet.get_hex_ascii_str() 569 print 'lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr) 570 else: 571 print 'error: bad command format' 572 573def rsp_qSymbol(options, cmd, cmd_args, rsp): 574 if len(rsp) == 0: 575 print "Unsupported" 576 else: 577 if rsp == "OK": 578 print "No more symbols to lookup" 579 else: 580 packet = Packet(rsp) 581 if packet.skip_exact_string("qSymbol:"): 582 symbol_name = packet.get_hex_ascii_str() 583 print 'lookup_symbol("%s")' % (symbol_name) 584 else: 585 print 'error: response string should start with "qSymbol:": respnse is "%s"' % (rsp) 586 587def cmd_qXfer(options, cmd, args): 588 # $qXfer:features:read:target.xml:0,1ffff#14 589 print "read target special data %s" % (args) 590 return True 591 592def rsp_qXfer(options, cmd, cmd_args, rsp): 593 data = string.split(cmd_args, ':') 594 if data[0] == 'features': 595 if data[1] == 'read': 596 filename, extension = os.path.splitext(data[2]) 597 if extension == '.xml': 598 response = Packet(rsp) 599 xml_string = response.get_hex_ascii_str() 600 ch = xml_string[0] 601 if ch == 'l': 602 xml_string = xml_string[1:] 603 xml_root = ET.fromstring(xml_string) 604 for reg_element in xml_root.findall("./feature/reg"): 605 if not 'value_regnums' in reg_element.attrib: 606 reg_info = RegisterInfo([]) 607 if 'name' in reg_element.attrib: 608 reg_info.info['name'] = reg_element.attrib['name'] 609 else: 610 reg_info.info['name'] = 'unspecified' 611 if 'encoding' in reg_element.attrib: 612 reg_info.info['encoding'] = reg_element.attrib['encoding'] 613 else: 614 reg_info.info['encoding'] = 'uint' 615 if 'offset' in reg_element.attrib: 616 reg_info.info['offset'] = reg_element.attrib['offset'] 617 if 'bitsize' in reg_element.attrib: 618 reg_info.info['bitsize'] = reg_element.attrib['bitsize'] 619 g_register_infos.append(reg_info) 620 print 'XML for "%s":' % (data[2]) 621 ET.dump(xml_root) 622 623def cmd_A(options, cmd, args): 624 print 'launch process:' 625 packet = Packet(args) 626 while 1: 627 arg_len = packet.get_number() 628 if arg_len == -1: 629 break 630 if not packet.skip_exact_string(','): 631 break 632 arg_idx = packet.get_number() 633 if arg_idx == -1: 634 break 635 if not packet.skip_exact_string(','): 636 break; 637 arg_value = packet.get_hex_ascii_str(arg_len) 638 print 'argv[%u] = "%s"' % (arg_idx, arg_value) 639 640def cmd_qC(options, cmd, args): 641 print "query_current_thread_id()" 642 643def rsp_qC(options, cmd, cmd_args, rsp): 644 packet = Packet(rsp) 645 if packet.skip_exact_string("QC"): 646 tid = packet.get_thread_id() 647 print "current_thread_id = %#x" % (tid) 648 else: 649 print "current_thread_id = old thread ID" 650 651def cmd_query_packet(options, cmd, args): 652 if args: 653 print "%s%s" % (cmd, args) 654 else: 655 print "%s" % (cmd) 656 return False 657 658def rsp_ok_error(rsp): 659 print "rsp: ", rsp 660 661def rsp_ok_means_supported(options, cmd, cmd_args, rsp): 662 if rsp == 'OK': 663 print "%s%s is supported" % (cmd, cmd_args) 664 elif rsp == '': 665 print "%s%s is not supported" % (cmd, cmd_args) 666 else: 667 print "%s%s -> %s" % (cmd, cmd_args, rsp) 668 669def rsp_ok_means_success(options, cmd, cmd_args, rsp): 670 if rsp == 'OK': 671 print "success" 672 elif rsp == '': 673 print "%s%s is not supported" % (cmd, cmd_args) 674 else: 675 print "%s%s -> %s" % (cmd, cmd_args, rsp) 676 677def dump_key_value_pairs(key_value_pairs): 678 max_key_len = 0 679 for key_value_pair in key_value_pairs: 680 key_len = len(key_value_pair[0]) 681 if max_key_len < key_len: 682 max_key_len = key_len 683 for key_value_pair in key_value_pairs: 684 key = key_value_pair[0] 685 value = key_value_pair[1] 686 print "%*s = %s" % (max_key_len, key, value) 687 688def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp): 689 if rsp: 690 print '%s response:' % (cmd) 691 packet = Packet(rsp) 692 key_value_pairs = packet.get_key_value_pairs() 693 dump_key_value_pairs(key_value_pairs) 694 else: 695 print "not supported" 696 697def cmd_c(options, cmd, args): 698 print "continue()" 699 return False 700 701def cmd_s(options, cmd, args): 702 print "step()" 703 return False 704 705def cmd_vCont(options, cmd, args): 706 if args == '?': 707 print "%s: get supported extended continue modes" % (cmd) 708 else: 709 got_other_threads = 0 710 s = '' 711 for thread_action in string.split(args[1:], ';'): 712 (short_action, thread) = string.split(thread_action, ':') 713 tid = int(thread, 16) 714 if short_action == 'c': 715 action = 'continue' 716 elif short_action == 's': 717 action = 'step' 718 elif short_action[0] == 'C': 719 action = 'continue with signal 0x%s' % (short_action[1:]) 720 elif short_action == 'S': 721 action = 'step with signal 0x%s' % (short_action[1:]) 722 else: 723 action = short_action 724 if s: 725 s += ', ' 726 if tid == -1: 727 got_other_threads = 1 728 s += 'other-threads:' 729 else: 730 s += 'thread 0x%4.4x: %s' % (tid, action) 731 if got_other_threads: 732 print "extended_continue (%s)" % (s) 733 else: 734 print "extended_continue (%s, other-threads: suspend)" % (s) 735 return False 736 737def rsp_vCont(options, cmd, cmd_args, rsp): 738 if cmd_args == '?': 739 # Skip the leading 'vCont;' 740 rsp = rsp[6:] 741 modes = string.split(rsp, ';') 742 s = "%s: supported extended continue modes include: " % (cmd) 743 744 for i, mode in enumerate(modes): 745 if i: 746 s += ', ' 747 if mode == 'c': 748 s += 'continue' 749 elif mode == 'C': 750 s += 'continue with signal' 751 elif mode == 's': 752 s += 'step' 753 elif mode == 'S': 754 s += 'step with signal' 755 else: 756 s += 'unrecognized vCont mode: ', mode 757 print s 758 elif rsp: 759 if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X': 760 rsp_stop_reply (options, cmd, cmd_args, rsp) 761 return 762 if rsp[0] == 'O': 763 print "stdout: %s" % (rsp) 764 return 765 else: 766 print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp) 767 768def cmd_vAttach(options, cmd, args): 769 (extra_command, args) = string.split(args, ';') 770 if extra_command: 771 print "%s%s(%s)" % (cmd, extra_command, args) 772 else: 773 print "attach(pid = %u)" % int(args, 16) 774 return False 775 776 777def cmd_qRegisterInfo(options, cmd, args): 778 print 'query_register_info(reg_num=%i)' % (int(args, 16)) 779 return False 780 781def rsp_qRegisterInfo(options, cmd, cmd_args, rsp): 782 global g_max_register_info_name_len 783 print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)), 784 if len(rsp) == 3 and rsp[0] == 'E': 785 g_max_register_info_name_len = 0 786 for reg_info in g_register_infos: 787 name_len = len(reg_info.name()) 788 if g_max_register_info_name_len < name_len: 789 g_max_register_info_name_len = name_len 790 print' DONE' 791 else: 792 packet = Packet(rsp) 793 reg_info = RegisterInfo(packet.get_key_value_pairs()) 794 g_register_infos.append(reg_info) 795 print reg_info 796 return False 797 798def cmd_qThreadInfo(options, cmd, args): 799 if cmd == 'qfThreadInfo': 800 query_type = 'first' 801 else: 802 query_type = 'subsequent' 803 print 'get_current_thread_list(type=%s)' % (query_type) 804 return False 805 806def rsp_qThreadInfo(options, cmd, cmd_args, rsp): 807 packet = Packet(rsp) 808 response_type = packet.get_char() 809 if response_type == 'm': 810 tids = packet.split_hex(';', 'big') 811 for i, tid in enumerate(tids): 812 if i: 813 print ',', 814 print '0x%x' % (tid), 815 print 816 elif response_type == 'l': 817 print 'END' 818 819def rsp_hex_big_endian(options, cmd, cmd_args, rsp): 820 packet = Packet(rsp) 821 uval = packet.get_hex_uint('big') 822 print '%s: 0x%x' % (cmd, uval) 823 824def cmd_read_mem_bin(options, cmd, args): 825 # x0x7fff5fc39200,0x200 826 packet = Packet(args) 827 addr = packet.get_number() 828 comma = packet.get_char() 829 size = packet.get_number() 830 print 'binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size) 831 return False 832 833def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp): 834 packet = Packet(cmd_args) 835 addr = packet.get_number() 836 comma = packet.get_char() 837 size = packet.get_number() 838 print 'memory:' 839 if size > 0: 840 dump_hex_memory_buffer (addr, rsp) 841 842def cmd_read_memory(options, cmd, args): 843 packet = Packet(args) 844 addr = packet.get_hex_uint('big') 845 comma = packet.get_char() 846 size = packet.get_hex_uint('big') 847 print 'read_memory (addr = 0x%16.16x, size = %u)' % (addr, size) 848 return False 849 850def dump_hex_memory_buffer(addr, hex_byte_str): 851 packet = Packet(hex_byte_str) 852 idx = 0 853 ascii = '' 854 uval = packet.get_hex_uint8() 855 while uval != None: 856 if ((idx % 16) == 0): 857 if ascii: 858 print ' ', ascii 859 ascii = '' 860 print '0x%x:' % (addr + idx), 861 print '%2.2x' % (uval), 862 if 0x20 <= uval and uval < 0x7f: 863 ascii += '%c' % uval 864 else: 865 ascii += '.' 866 uval = packet.get_hex_uint8() 867 idx = idx + 1 868 if ascii: 869 print ' ', ascii 870 ascii = '' 871 872def cmd_write_memory(options, cmd, args): 873 packet = Packet(args) 874 addr = packet.get_hex_uint('big') 875 if packet.get_char() != ',': 876 print 'error: invalid write memory command (missing comma after address)' 877 return 878 size = packet.get_hex_uint('big') 879 if packet.get_char() != ':': 880 print 'error: invalid write memory command (missing colon after size)' 881 return 882 print 'write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size) 883 dump_hex_memory_buffer (addr, packet.str) 884 return False 885 886def cmd_alloc_memory(options, cmd, args): 887 packet = Packet(args) 888 byte_size = packet.get_hex_uint('big') 889 if packet.get_char() != ',': 890 print 'error: invalid allocate memory command (missing comma after address)' 891 return 892 print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str) 893 return False 894 895def rsp_alloc_memory(options, cmd, cmd_args, rsp): 896 packet = Packet(rsp) 897 addr = packet.get_hex_uint('big') 898 print 'addr = 0x%x' % addr 899 900def cmd_dealloc_memory(options, cmd, args): 901 packet = Packet(args) 902 addr = packet.get_hex_uint('big') 903 if packet.get_char() != ',': 904 print 'error: invalid allocate memory command (missing comma after address)' 905 else: 906 print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str) 907 return False 908def rsp_memory_bytes(options, cmd, cmd_args, rsp): 909 addr = Packet(cmd_args).get_hex_uint('big') 910 dump_hex_memory_buffer (addr, rsp) 911 912def get_register_name_equal_value(options, reg_num, hex_value_str): 913 if reg_num < len(g_register_infos): 914 reg_info = g_register_infos[reg_num] 915 value_str = reg_info.get_value_from_hex_string (hex_value_str) 916 s = reg_info.name() + ' = ' 917 if options.symbolicator: 918 symbolicated_addresses = options.symbolicator.symbolicate (int(value_str, 0)) 919 if symbolicated_addresses: 920 s += options.colors.magenta() 921 s += '%s' % symbolicated_addresses[0] 922 s += options.colors.reset() 923 return s 924 s += value_str 925 return s 926 else: 927 reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order) 928 return 'reg(%u) = 0x%x' % (reg_num, reg_value) 929 930def cmd_read_one_reg(options, cmd, args): 931 packet = Packet(args) 932 reg_num = packet.get_hex_uint('big') 933 tid = get_thread_from_thread_suffix (packet.str) 934 name = None 935 if reg_num < len(g_register_infos): 936 name = g_register_infos[reg_num].name () 937 if packet.str: 938 packet.get_char() # skip ; 939 thread_info = packet.get_key_value_pairs() 940 tid = int(thread_info[0][1], 16) 941 s = 'read_register (reg_num=%u' % reg_num 942 if name: 943 s += ' (%s)' % (name) 944 if tid != None: 945 s += ', tid = 0x%4.4x' % (tid) 946 s += ')' 947 print s 948 return False 949 950def rsp_read_one_reg(options, cmd, cmd_args, rsp): 951 packet = Packet(cmd_args) 952 reg_num = packet.get_hex_uint('big') 953 print get_register_name_equal_value (options, reg_num, rsp) 954 955def cmd_write_one_reg(options, cmd, args): 956 packet = Packet(args) 957 reg_num = packet.get_hex_uint('big') 958 if packet.get_char() != '=': 959 print 'error: invalid register write packet' 960 else: 961 name = None 962 hex_value_str = packet.get_hex_chars() 963 tid = get_thread_from_thread_suffix (packet.str) 964 s = 'write_register (reg_num=%u' % reg_num 965 if name: 966 s += ' (%s)' % (name) 967 s += ', value = ' 968 s += get_register_name_equal_value(options, reg_num, hex_value_str) 969 if tid != None: 970 s += ', tid = 0x%4.4x' % (tid) 971 s += ')' 972 print s 973 return False 974 975def dump_all_regs(packet): 976 for reg_info in g_register_infos: 977 nibble_size = reg_info.bit_size() / 4 978 hex_value_str = packet.get_hex_chars(nibble_size) 979 if hex_value_str != None: 980 value = reg_info.get_value_from_hex_string (hex_value_str) 981 print '%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value) 982 else: 983 return 984 985def cmd_read_all_regs(cmd, cmd_args): 986 packet = Packet(cmd_args) 987 packet.get_char() # toss the 'g' command character 988 tid = get_thread_from_thread_suffix (packet.str) 989 if tid != None: 990 print 'read_all_register(thread = 0x%4.4x)' % tid 991 else: 992 print 'read_all_register()' 993 return False 994 995def rsp_read_all_regs(options, cmd, cmd_args, rsp): 996 packet = Packet(rsp) 997 dump_all_regs (packet) 998 999def cmd_write_all_regs(options, cmd, args): 1000 packet = Packet(args) 1001 print 'write_all_registers()' 1002 dump_all_regs (packet) 1003 return False 1004 1005g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ] 1006 1007def cmd_bp(options, cmd, args): 1008 if cmd == 'Z': 1009 s = 'set_' 1010 else: 1011 s = 'clear_' 1012 packet = Packet (args) 1013 bp_type = packet.get_hex_uint('big') 1014 packet.get_char() # Skip , 1015 bp_addr = packet.get_hex_uint('big') 1016 packet.get_char() # Skip , 1017 bp_size = packet.get_hex_uint('big') 1018 s += g_bp_types[bp_type] 1019 s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size) 1020 print s 1021 return False 1022 1023def cmd_mem_rgn_info(options, cmd, args): 1024 packet = Packet(args) 1025 packet.get_char() # skip ':' character 1026 addr = packet.get_hex_uint('big') 1027 print 'get_memory_region_info (addr=0x%x)' % (addr) 1028 return False 1029 1030def cmd_kill(options, cmd, args): 1031 print 'kill_process()' 1032 return False 1033 1034gdb_remote_commands = { 1035 '\\?' : { 'cmd' : cmd_stop_reply , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"}, 1036 'qThreadStopInfo' : { 'cmd' : cmd_qThreadStopInfo , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"}, 1037 'QStartNoAckMode' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if no ack mode is supported"}, 1038 'QThreadSuffixSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if thread suffix is supported" }, 1039 'QListThreadsInStopReply' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if threads in stop reply packets are supported" }, 1040 'QSetDetachOnError' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "set if we should detach on error" }, 1041 'QSetDisableASLR' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "set if we should disable ASLR" }, 1042 'qLaunchSuccess' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "check on launch success for the A packet" }, 1043 'A' : { 'cmd' : cmd_A , 'rsp' : rsp_ok_means_success , 'name' : "launch process" }, 1044 'QLaunchArch' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "set if we should disable ASLR" }, 1045 'qVAttachOrWaitSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "set the launch architecture" }, 1046 'qHostInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get host information" }, 1047 'qC' : { 'cmd' : cmd_qC , 'rsp' : rsp_qC , 'name' : "return the current thread ID" }, 1048 'vCont' : { 'cmd' : cmd_vCont , 'rsp' : rsp_vCont , 'name' : "extended continue command" }, 1049 'vAttach' : { 'cmd' : cmd_vAttach , 'rsp' : rsp_stop_reply , 'name' : "attach to process" }, 1050 'c' : { 'cmd' : cmd_c , 'rsp' : rsp_stop_reply , 'name' : "continue" }, 1051 's' : { 'cmd' : cmd_s , 'rsp' : rsp_stop_reply , 'name' : "step" }, 1052 'qRegisterInfo' : { 'cmd' : cmd_qRegisterInfo , 'rsp' : rsp_qRegisterInfo , 'name' : "query register info" }, 1053 'qfThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" }, 1054 'qsThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" }, 1055 'qShlibInfoAddr' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_hex_big_endian , 'name' : "get shared library info address" }, 1056 'qMemoryRegionInfo' : { 'cmd' : cmd_mem_rgn_info , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get memory region information" }, 1057 'qProcessInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get process info" }, 1058 'qSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query supported" }, 1059 'qXfer:' : { 'cmd' : cmd_qXfer , 'rsp' : rsp_qXfer , 'name' : "qXfer" }, 1060 'qSymbol:' : { 'cmd' : cmd_qSymbol , 'rsp' : rsp_qSymbol , 'name' : "qSymbol" }, 1061 'x' : { 'cmd' : cmd_read_mem_bin , 'rsp' : rsp_mem_bin_bytes , 'name' : "read memory binary" }, 1062 'X' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory binary" }, 1063 'm' : { 'cmd' : cmd_read_memory , 'rsp' : rsp_memory_bytes , 'name' : "read memory" }, 1064 'M' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory" }, 1065 '_M' : { 'cmd' : cmd_alloc_memory , 'rsp' : rsp_alloc_memory , 'name' : "allocate memory" }, 1066 '_m' : { 'cmd' : cmd_dealloc_memory , 'rsp' : rsp_ok_means_success , 'name' : "deallocate memory" }, 1067 'p' : { 'cmd' : cmd_read_one_reg , 'rsp' : rsp_read_one_reg , 'name' : "read single register" }, 1068 'P' : { 'cmd' : cmd_write_one_reg , 'rsp' : rsp_ok_means_success , 'name' : "write single register" }, 1069 'g' : { 'cmd' : cmd_read_all_regs , 'rsp' : rsp_read_all_regs , 'name' : "read all registers" }, 1070 'G' : { 'cmd' : cmd_write_all_regs , 'rsp' : rsp_ok_means_success , 'name' : "write all registers" }, 1071 'z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "clear breakpoint or watchpoint" }, 1072 'Z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "set breakpoint or watchpoint" }, 1073 'k' : { 'cmd' : cmd_kill , 'rsp' : rsp_stop_reply , 'name' : "kill process" }, 1074} 1075 1076def calculate_mean_and_standard_deviation(floats): 1077 sum = 0.0 1078 count = len(floats) 1079 if count == 0: 1080 return (0.0, 0.0) 1081 for f in floats: 1082 sum += f 1083 mean = sum / count 1084 accum = 0.0 1085 for f in floats: 1086 delta = f - mean 1087 accum += delta * delta 1088 1089 std_dev = math.sqrt(accum / (count-1)); 1090 return (mean, std_dev) 1091 1092def parse_gdb_log_file(path, options): 1093 f = open(path) 1094 parse_gdb_log(f, options) 1095 f.close() 1096 1097def parse_gdb_log(file, options): 1098 '''Parse a GDB log file that was generated by enabling logging with: 1099 (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets 1100 This log file will contain timestamps and this function will then normalize 1101 those packets to be relative to the first value timestamp that is found and 1102 show delta times between log lines and also keep track of how long it takes 1103 for GDB remote commands to make a send/receive round trip. This can be 1104 handy when trying to figure out why some operation in the debugger is taking 1105 a long time during a preset set of debugger commands.''' 1106 1107 tricky_commands = [ 'qRegisterInfo' ] 1108 timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') 1109 packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]') 1110 packet_transmit_name_regex = re.compile('(?P<direction>send|read) packet: (?P<packet>.*)') 1111 packet_contents_name_regex = re.compile('\$([^#]+)#[0-9a-fA-F]{2}') 1112 packet_names_regex_str = '(' + '|'.join(gdb_remote_commands.keys()) + ')(.*)'; 1113 packet_names_regex = re.compile(packet_names_regex_str); 1114 1115 base_time = 0.0 1116 last_time = 0.0 1117 packet_send_time = 0.0 1118 packet_total_times = {} 1119 packet_times = [] 1120 packet_count = {} 1121 lines = file.read().splitlines() 1122 last_command = None 1123 last_command_args = None 1124 last_command_packet = None 1125 hide_next_response = False 1126 for line in lines: 1127 m = packet_transmit_name_regex.search(line) 1128 is_command = False 1129 direction = None 1130 if m: 1131 direction = m.group('direction') 1132 is_command = direction == 'send' 1133 packet = m.group('packet') 1134 sys.stdout.write(options.colors.green()) 1135 if not options.quiet and not hide_next_response: 1136 print '# ', line 1137 sys.stdout.write(options.colors.reset()) 1138 1139 #print 'direction = "%s", packet = "%s"' % (direction, packet) 1140 1141 if is_command: 1142 print '-->', 1143 else: 1144 print '<--', 1145 1146 if packet[0] == '+': 1147 if not options.quiet: print 'ACK' 1148 continue 1149 elif packet[0] == '-': 1150 if not options.quiet: print 'NACK' 1151 continue 1152 elif packet[0] == '$': 1153 m = packet_contents_name_regex.match(packet) 1154 if m: 1155 contents = m.group(1) 1156 if is_command: 1157 hide_next_response = False 1158 m = packet_names_regex.match (contents) 1159 if m: 1160 last_command = m.group(1) 1161 if last_command == '?': 1162 last_command = '\\?' 1163 packet_name = last_command 1164 last_command_args = m.group(2) 1165 last_command_packet = contents 1166 hide_next_response = gdb_remote_commands[last_command]['cmd'](options, last_command, last_command_args) 1167 else: 1168 packet_match = packet_name_regex.match (contents) 1169 if packet_match: 1170 packet_name = packet_match.group(1) 1171 for tricky_cmd in tricky_commands: 1172 if packet_name.find (tricky_cmd) == 0: 1173 packet_name = tricky_cmd 1174 else: 1175 packet_name = contents 1176 last_command = None 1177 last_command_args = None 1178 last_command_packet = None 1179 elif last_command: 1180 gdb_remote_commands[last_command]['rsp'](options, last_command, last_command_args, contents) 1181 else: 1182 print 'error: invalid packet: "', packet, '"' 1183 else: 1184 print '???' 1185 else: 1186 print '## ', line 1187 match = timestamp_regex.match (line) 1188 if match: 1189 curr_time = float (match.group(2)) 1190 if last_time and not is_command: 1191 delta = curr_time - last_time 1192 packet_times.append(delta) 1193 delta = 0.0 1194 if base_time: 1195 delta = curr_time - last_time 1196 else: 1197 base_time = curr_time 1198 1199 if is_command: 1200 packet_send_time = curr_time 1201 elif line.find('read packet: $') >= 0 and packet_name: 1202 if packet_name in packet_total_times: 1203 packet_total_times[packet_name] += delta 1204 packet_count[packet_name] += 1 1205 else: 1206 packet_total_times[packet_name] = delta 1207 packet_count[packet_name] = 1 1208 packet_name = None 1209 1210 if not options or not options.quiet: 1211 print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) 1212 last_time = curr_time 1213 # else: 1214 # print line 1215 (average, std_dev) = calculate_mean_and_standard_deviation(packet_times) 1216 if average and std_dev: 1217 print '%u packets with average packet time of %f and standard deviation of %f' % (len(packet_times), average, std_dev) 1218 if packet_total_times: 1219 total_packet_time = 0.0 1220 total_packet_count = 0 1221 for key, vvv in packet_total_times.items(): 1222 # print ' key = (%s) "%s"' % (type(key), key) 1223 # print 'value = (%s) %s' % (type(vvv), vvv) 1224 # if type(vvv) == 'float': 1225 total_packet_time += vvv 1226 for key, vvv in packet_count.items(): 1227 total_packet_count += vvv 1228 1229 print '#---------------------------------------------------' 1230 print '# Packet timing summary:' 1231 print '# Totals: time = %6f, count = %6d' % (total_packet_time, total_packet_count) 1232 print '#---------------------------------------------------' 1233 print '# Packet Time (sec) Percent Count ' 1234 print '#------------------------- ---------- ------- ------' 1235 if options and options.sort_count: 1236 res = sorted(packet_count, key=packet_count.__getitem__, reverse=True) 1237 else: 1238 res = sorted(packet_total_times, key=packet_total_times.__getitem__, reverse=True) 1239 1240 if last_time > 0.0: 1241 for item in res: 1242 packet_total_time = packet_total_times[item] 1243 packet_percent = (packet_total_time / total_packet_time)*100.0 1244 if packet_percent >= 10.0: 1245 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) 1246 else: 1247 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) 1248 1249 1250 1251if __name__ == '__main__': 1252 usage = "usage: gdbremote [options]" 1253 description='''The command disassembles a GDB remote packet log.''' 1254 parser = optparse.OptionParser(description=description, prog='gdbremote',usage=usage) 1255 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) 1256 parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False) 1257 parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False) 1258 parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False) 1259 parser.add_option('--crashlog', type='string', dest='crashlog', help='symbolicate using a darwin crash log file', default=False) 1260 try: 1261 (options, args) = parser.parse_args(sys.argv[1:]) 1262 except: 1263 print 'error: argument error' 1264 sys.exit(1) 1265 1266 options.colors = TerminalColors(options.color) 1267 options.symbolicator = None 1268 if options.crashlog: 1269 import lldb 1270 lldb.debugger = lldb.SBDebugger.Create() 1271 import lldb.macosx.crashlog 1272 options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog) 1273 print '%s' % (options.symbolicator) 1274 1275 # This script is being run from the command line, create a debugger in case we are 1276 # going to use any debugger functions in our function. 1277 if len(args): 1278 for file in args: 1279 print '#----------------------------------------------------------------------' 1280 print "# GDB remote log file: '%s'" % file 1281 print '#----------------------------------------------------------------------' 1282 parse_gdb_log_file (file, options) 1283 if options.symbolicator: 1284 print '%s' % (options.symbolicator) 1285 else: 1286 parse_gdb_log(sys.stdin, options) 1287 1288else: 1289 import lldb 1290 if lldb.debugger: 1291 # This initializer is being run from LLDB in the embedded command interpreter 1292 # Add any commands contained in this module to LLDB 1293 lldb.debugger.HandleCommand('command script add -f gdbremote.start_gdb_log start_gdb_log') 1294 lldb.debugger.HandleCommand('command script add -f gdbremote.stop_gdb_log stop_gdb_log') 1295 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' 1296