Cleaned up some stuff in symbolication where we can now lazily get images when symbolicating after loading a crash log file.

Added colorization to the gdbremote.py output and also added the ability to symbolicate the addresses in registers.

llvm-svn: 157965
This commit is contained in:
Greg Clayton 2012-06-04 23:22:17 +00:00
parent b90827e66c
commit f51a23fb6f
3 changed files with 201 additions and 135 deletions

View File

@ -118,9 +118,11 @@ class CrashLog(symbolication.Symbolicator):
self.version = version self.version = version
def locate_module_and_debug_symbols(self): def locate_module_and_debug_symbols(self):
if self.resolved_path: # Don't load a module twice...
# Don't load a module twice... if self.resolved:
return True return True
# Mark this as resolved so we don't keep trying
self.resolved = True
uuid_str = self.get_normalized_uuid_string() uuid_str = self.get_normalized_uuid_string()
print 'Getting symbols for %s %s...' % (uuid_str, self.path), print 'Getting symbols for %s %s...' % (uuid_str, self.path),
if os.path.exists(self.dsymForUUIDBinary): if os.path.exists(self.dsymForUUIDBinary):
@ -150,7 +152,8 @@ class CrashLog(symbolication.Symbolicator):
self.arch = match.group(2) self.arch = match.group(2)
break; break;
if not self.resolved_path: if not self.resolved_path:
print "error: file %s '%s' doesn't match the UUID in the installed file" % (uuid_str, self.path) self.unavailable = True
print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str)
return False return False
if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)): if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)):
print 'ok' print 'ok'
@ -159,6 +162,8 @@ class CrashLog(symbolication.Symbolicator):
# if self.symfile: # if self.symfile:
# print ' dsym = "%s"' % self.symfile # print ' dsym = "%s"' % self.symfile
return True return True
else:
self.unavailable = True
return False return False
@ -313,7 +318,7 @@ class CrashLog(symbolication.Symbolicator):
elif parse_mode == PARSE_MODE_SYSTEM: elif parse_mode == PARSE_MODE_SYSTEM:
self.system_profile.append(line) self.system_profile.append(line)
f.close() f.close()
def dump(self): def dump(self):
print "Crash Log File: %s" % (self.path) print "Crash Log File: %s" % (self.path)
print "\nThreads:" print "\nThreads:"
@ -351,7 +356,7 @@ class CrashLog(symbolication.Symbolicator):
print 'crashlog.create_target()...4' print 'crashlog.create_target()...4'
print 'error: unable to locate any executables from the crash log' print 'error: unable to locate any executables from the crash log'
return None return None
def usage(): def usage():
print "Usage: lldb-symbolicate.py [-n name] executable-image" print "Usage: lldb-symbolicate.py [-n name] executable-image"
@ -477,7 +482,6 @@ def interactive_crashlogs(options, args):
def Symbolicate(debugger, command, result, dict): def Symbolicate(debugger, command, result, dict):
print 'def Symbolicate(debugger, command, result, dict): called with "%s"' % (command)
try: try:
SymbolicateCrashLogs (shlex.split(command)) SymbolicateCrashLogs (shlex.split(command))
except: except:
@ -610,7 +614,7 @@ be disassembled and lookups can be performed using the addresses found in the cr
interactive_crashlogs(options, args) interactive_crashlogs(options, args)
else: else:
for crash_log_file in args: for crash_log_file in args:
crash_log = CrashLog(crash_log_file) crash_log = CrashLog(crash_log_file)
SymbolicateCrashLog (crash_log, options) SymbolicateCrashLog (crash_log, options)
if __name__ == '__main__': if __name__ == '__main__':
# Create a new debugger instance # Create a new debugger instance

View File

@ -25,10 +25,15 @@ import string
import sys import sys
import tempfile import tempfile
#----------------------------------------------------------------------
# Global variables
#----------------------------------------------------------------------
g_log_file = ''
g_byte_order = 'little'
class TerminalColors: class TerminalColors:
'''Simple terminal colors class''' '''Simple terminal colors class'''
def __init__(self, file = sys.stdout, enabled = True): def __init__(self, enabled = True):
self.file = file
# TODO: discover terminal type from "file" and disable if # TODO: discover terminal type from "file" and disable if
# it can't handle the color codes # it can't handle the color codes
self.enabled = enabled self.enabled = enabled
@ -36,133 +41,144 @@ class TerminalColors:
def reset(self): def reset(self):
'''Reset all terminal colors and formatting.''' '''Reset all terminal colors and formatting.'''
if self.enabled: if self.enabled:
self.file.write("\x1b[0m"); return "\x1b[0m";
return ''
def bold(self, on = True): def bold(self, on = True):
'''Enable or disable bold depending on the "on" paramter.''' '''Enable or disable bold depending on the "on" paramter.'''
if self.enabled: if self.enabled:
if on: if on:
self.file.write("\x1b[1m"); return "\x1b[1m";
else: else:
self.file.write("\x1b[22m"); return "\x1b[22m";
return ''
def italics(self, on = True): def italics(self, on = True):
'''Enable or disable italics depending on the "on" paramter.''' '''Enable or disable italics depending on the "on" paramter.'''
if self.enabled: if self.enabled:
if on: if on:
self.file.write("\x1b[3m"); return "\x1b[3m";
else: else:
self.file.write("\x1b[23m"); return "\x1b[23m";
return ''
def underline(self, on = True): def underline(self, on = True):
'''Enable or disable underline depending on the "on" paramter.''' '''Enable or disable underline depending on the "on" paramter.'''
if self.enabled: if self.enabled:
if on: if on:
self.file.write("\x1b[4m"); return "\x1b[4m";
else: else:
self.file.write("\x1b[24m"); return "\x1b[24m";
return ''
def inverse(self, on = True): def inverse(self, on = True):
'''Enable or disable inverse depending on the "on" paramter.''' '''Enable or disable inverse depending on the "on" paramter.'''
if self.enabled: if self.enabled:
if on: if on:
self.file.write("\x1b[7m"); return "\x1b[7m";
else: else:
self.file.write("\x1b[27m"); return "\x1b[27m";
return ''
def strike(self, on = True): def strike(self, on = True):
'''Enable or disable strike through depending on the "on" paramter.''' '''Enable or disable strike through depending on the "on" paramter.'''
if self.enabled: if self.enabled:
if on: if on:
self.file.write("\x1b[9m"); return "\x1b[9m";
else: else:
self.file.write("\x1b[29m"); return "\x1b[29m";
return ''
def black(self, fg = True): def black(self, fg = True):
'''Set the foreground or background color to black. '''Set the foreground or background color to black.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[30m"); return "\x1b[30m";
else: else:
self.file.write("\x1b[40m"); return "\x1b[40m";
return ''
def red(self, fg = True): def red(self, fg = True):
'''Set the foreground or background color to red. '''Set the foreground or background color to red.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[31m"); return "\x1b[31m";
else: else:
self.file.write("\x1b[41m"); return "\x1b[41m";
return ''
def green(self, fg = True): def green(self, fg = True):
'''Set the foreground or background color to green. '''Set the foreground or background color to green.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[32m"); return "\x1b[32m";
else: else:
self.file.write("\x1b[42m"); return "\x1b[42m";
return ''
def yellow(self, fg = True): def yellow(self, fg = True):
'''Set the foreground or background color to yellow. '''Set the foreground or background color to yellow.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[43m"); return "\x1b[43m";
else: else:
self.file.write("\x1b[33m"); return "\x1b[33m";
return ''
def blue(self, fg = True): def blue(self, fg = True):
'''Set the foreground or background color to blue. '''Set the foreground or background color to blue.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[34m"); return "\x1b[34m";
else: else:
self.file.write("\x1b[44m"); return "\x1b[44m";
return ''
def magenta(self, fg = True): def magenta(self, fg = True):
'''Set the foreground or background color to magenta. '''Set the foreground or background color to magenta.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[35m"); return "\x1b[35m";
else: else:
self.file.write("\x1b[45m"); return "\x1b[45m";
return ''
def cyan(self, fg = True): def cyan(self, fg = True):
'''Set the foreground or background color to cyan. '''Set the foreground or background color to cyan.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[36m"); return "\x1b[36m";
else: else:
self.file.write("\x1b[46m"); return "\x1b[46m";
return ''
def white(self, fg = True): def white(self, fg = True):
'''Set the foreground or background color to white. '''Set the foreground or background color to white.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[37m"); return "\x1b[37m";
else: else:
self.file.write("\x1b[47m"); return "\x1b[47m";
return ''
def default(self, fg = True): def default(self, fg = True):
'''Set the foreground or background color to the default. '''Set the foreground or background color to the default.
The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
if self.enabled: if self.enabled:
if fg: if fg:
self.file.write("\x1b[39m"); return "\x1b[39m";
else: else:
self.file.write("\x1b[49m"); return "\x1b[49m";
return ''
#----------------------------------------------------------------------
# Global variables
#----------------------------------------------------------------------
g_log_file = ''
g_byte_order = 'little'
def start_gdb_log(debugger, command, result, dict): def start_gdb_log(debugger, command, result, dict):
'''Start logging GDB remote packets by enabling logging with timestamps and '''Start logging GDB remote packets by enabling logging with timestamps and
@ -211,11 +227,22 @@ def stop_gdb_log(debugger, command, result, dict):
parser = optparse.OptionParser(description=description, prog='stop_gdb_log',usage=usage) parser = optparse.OptionParser(description=description, prog='stop_gdb_log',usage=usage)
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False) parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False)
parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False) parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
parser.add_option('-s', '--symbolicate', action='store_true', dest='symbolicate', help='symbolicate addresses in log using current "lldb.target"', default=False)
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
options.colors = TerminalColors(options.color)
options.symbolicator = None
if options.symbolicate:
if lldb.target:
import lldb.utils.symbolication
options.symbolicator = lldb.utils.symbolication.Symbolicator()
options.symbolicator.target = lldb.target
else:
print "error: can't symbolicate without a target"
if not g_log_file: if not g_log_file:
result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"') result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"')
@ -224,7 +251,6 @@ def stop_gdb_log(debugger, command, result, dict):
debugger.HandleCommand('log disable gdb-remote packets'); debugger.HandleCommand('log disable gdb-remote packets');
result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % g_log_file) result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % g_log_file)
parse_gdb_log_file (g_log_file, options) parse_gdb_log_file (g_log_file, options)
g_log_file = None
else: else:
result.PutCString (usage) result.PutCString (usage)
else: else:
@ -440,10 +466,10 @@ def get_thread_from_thread_suffix(str):
return int(match.group(1), 16) return int(match.group(1), 16)
return None return None
def cmd_stop_reply(command, args): def cmd_stop_reply(options, cmd, args):
print "get_last_stop_info()" print "get_last_stop_info()"
def rsp_stop_reply(cmd, cmd_args, rsp): def rsp_stop_reply(options, cmd, cmd_args, rsp):
global g_byte_order global g_byte_order
packet = Packet(rsp) packet = Packet(rsp)
stop_type = packet.get_char() stop_type = packet.get_char()
@ -456,12 +482,7 @@ def rsp_stop_reply(cmd, cmd_args, rsp):
value = key_value_pair[1] value = key_value_pair[1]
if is_hex_byte(key): if is_hex_byte(key):
reg_num = Packet(key).get_hex_uint8() reg_num = Packet(key).get_hex_uint8()
if reg_num < len(g_register_infos): print ' ' + get_register_name_equal_value (options, reg_num, value)
reg_info = g_register_infos[reg_num]
print ' ' + reg_info.name() + ' = ' + reg_info.get_value_from_hex_string (value)
else:
reg_value = Packet(value).get_hex_uint(g_byte_order)
print ' reg(%u) = 0x%x' % (reg_num, reg_value)
else: else:
print ' %s = %s' % (key, value) print ' %s = %s' % (key, value)
elif stop_type == 'W': elif stop_type == 'W':
@ -471,22 +492,22 @@ def rsp_stop_reply(cmd, cmd_args, rsp):
print 'stdout = %s' % packet.str print 'stdout = %s' % packet.str
def cmd_unknown_packet(cmd, args): def cmd_unknown_packet(options, cmd, args):
if args: if args:
print "cmd: %s, args: %s", cmd, args print "cmd: %s, args: %s", cmd, args
else: else:
print "cmd: %s", cmd print "cmd: %s", cmd
def cmd_query_packet(command, args): def cmd_query_packet(options, cmd, args):
if args: if args:
print "query: %s, args: %s" % (command, args) print "query: %s, args: %s" % (cmd, args)
else: else:
print "query: %s" % (command) print "query: %s" % (cmd)
def rsp_ok_error(rsp): def rsp_ok_error(rsp):
print "rsp: ", rsp print "rsp: ", rsp
def rsp_ok_means_supported(cmd, cmd_args, rsp): def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
if rsp == 'OK': if rsp == 'OK':
print "%s%s is supported" % (cmd, cmd_args) print "%s%s is supported" % (cmd, cmd_args)
elif rsp == '': elif rsp == '':
@ -494,7 +515,7 @@ def rsp_ok_means_supported(cmd, cmd_args, rsp):
else: else:
print "%s%s -> %s" % (cmd, cmd_args, rsp) print "%s%s -> %s" % (cmd, cmd_args, rsp)
def rsp_ok_means_success(cmd, cmd_args, rsp): def rsp_ok_means_success(options, cmd, cmd_args, rsp):
if rsp == 'OK': if rsp == 'OK':
print "success" print "success"
elif rsp == '': elif rsp == '':
@ -502,7 +523,7 @@ def rsp_ok_means_success(cmd, cmd_args, rsp):
else: else:
print "%s%s -> %s" % (cmd, cmd_args, rsp) print "%s%s -> %s" % (cmd, cmd_args, rsp)
def rsp_dump_key_value_pairs(cmd, cmd_args, rsp): def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
if rsp: if rsp:
packet = Packet(rsp) packet = Packet(rsp)
key_value_pairs = packet.get_key_value_pairs() key_value_pairs = packet.get_key_value_pairs()
@ -513,7 +534,7 @@ def rsp_dump_key_value_pairs(cmd, cmd_args, rsp):
else: else:
print "not supported" print "not supported"
def cmd_vCont(cmd, args): def cmd_vCont(options, cmd, args):
if args == '?': if args == '?':
print "%s: get supported extended continue modes" % (cmd) print "%s: get supported extended continue modes" % (cmd)
else: else:
@ -544,7 +565,7 @@ def cmd_vCont(cmd, args):
else: else:
print "extended_continue (%s, other-threads: suspend)" % (s) print "extended_continue (%s, other-threads: suspend)" % (s)
def rsp_vCont(cmd, cmd_args, rsp): def rsp_vCont(options, cmd, cmd_args, rsp):
if cmd_args == '?': if cmd_args == '?':
# Skip the leading 'vCont;' # Skip the leading 'vCont;'
rsp = rsp[6:] rsp = rsp[6:]
@ -567,7 +588,7 @@ def rsp_vCont(cmd, cmd_args, rsp):
print s print s
elif rsp: elif rsp:
if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X': if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
rsp_stop_reply (cmd, cmd_args, rsp) rsp_stop_reply (options, cmd, cmd_args, rsp)
return return
if rsp[0] == 'O': if rsp[0] == 'O':
print "stdout: %s" % (rsp) print "stdout: %s" % (rsp)
@ -575,17 +596,17 @@ def rsp_vCont(cmd, cmd_args, rsp):
else: else:
print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp) print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
def cmd_vAttach(cmd, args): def cmd_vAttach(options, cmd, args):
(extra_command, args) = string.split(args, ';') (extra_command, args) = string.split(args, ';')
if extra_command: if extra_command:
print "%s%s(%s)" % (cmd, extra_command, args) print "%s%s(%s)" % (cmd, extra_command, args)
else: else:
print "attach_pid(%s)" % args print "attach_pid(%s)" % args
def cmd_qRegisterInfo(cmd, args): def cmd_qRegisterInfo(options, cmd, args):
print 'query_register_info(reg_num=%i)' % (int(args, 16)) print 'query_register_info(reg_num=%i)' % (int(args, 16))
def rsp_qRegisterInfo(cmd, cmd_args, rsp): def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
global g_max_register_info_name_len global g_max_register_info_name_len
print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)), print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)),
if len(rsp) == 3 and rsp[0] == 'E': if len(rsp) == 3 and rsp[0] == 'E':
@ -602,14 +623,14 @@ def rsp_qRegisterInfo(cmd, cmd_args, rsp):
print reg_info print reg_info
def cmd_qThreadInfo(cmd, args): def cmd_qThreadInfo(options, cmd, args):
if cmd == 'qfThreadInfo': if cmd == 'qfThreadInfo':
query_type = 'first' query_type = 'first'
else: else:
query_type = 'subsequent' query_type = 'subsequent'
print 'get_current_thread_list(type=%s)' % (query_type) print 'get_current_thread_list(type=%s)' % (query_type)
def rsp_qThreadInfo(cmd, cmd_args, rsp): def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
packet = Packet(rsp) packet = Packet(rsp)
response_type = packet.get_char() response_type = packet.get_char()
if response_type == 'm': if response_type == 'm':
@ -622,12 +643,12 @@ def rsp_qThreadInfo(cmd, cmd_args, rsp):
elif response_type == 'l': elif response_type == 'l':
print 'END' print 'END'
def rsp_hex_big_endian(cmd, cmd_args, rsp): def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
packet = Packet(rsp) packet = Packet(rsp)
uval = packet.get_hex_uint('big') uval = packet.get_hex_uint('big')
print '%s: 0x%x' % (cmd, uval) print '%s: 0x%x' % (cmd, uval)
def cmd_read_memory(cmd, args): def cmd_read_memory(options, cmd, args):
packet = Packet(args) packet = Packet(args)
addr = packet.get_hex_uint('big') addr = packet.get_hex_uint('big')
comma = packet.get_char() comma = packet.get_char()
@ -656,7 +677,7 @@ def dump_hex_memory_buffer(addr, hex_byte_str):
print ' ', ascii print ' ', ascii
ascii = '' ascii = ''
def cmd_write_memory(cmd, args): def cmd_write_memory(options, cmd, args):
packet = Packet(args) packet = Packet(args)
addr = packet.get_hex_uint('big') addr = packet.get_hex_uint('big')
if packet.get_char() != ',': if packet.get_char() != ',':
@ -669,7 +690,7 @@ def cmd_write_memory(cmd, args):
print 'write_memory (addr = 0x%x, size = %u, data:' % (addr, size) print 'write_memory (addr = 0x%x, size = %u, data:' % (addr, size)
dump_hex_memory_buffer (addr, packet.str) dump_hex_memory_buffer (addr, packet.str)
def cmd_alloc_memory(cmd, args): def cmd_alloc_memory(options, cmd, args):
packet = Packet(args) packet = Packet(args)
byte_size = packet.get_hex_uint('big') byte_size = packet.get_hex_uint('big')
if packet.get_char() != ',': if packet.get_char() != ',':
@ -677,12 +698,12 @@ def cmd_alloc_memory(cmd, args):
return return
print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str) print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str)
def rsp_alloc_memory(cmd, cmd_args, rsp): def rsp_alloc_memory(options, cmd, cmd_args, rsp):
packet = Packet(rsp) packet = Packet(rsp)
addr = packet.get_hex_uint('big') addr = packet.get_hex_uint('big')
print 'addr = 0x%x' % addr print 'addr = 0x%x' % addr
def cmd_dealloc_memory(cmd, args): def cmd_dealloc_memory(options, cmd, args):
packet = Packet(args) packet = Packet(args)
addr = packet.get_hex_uint('big') addr = packet.get_hex_uint('big')
if packet.get_char() != ',': if packet.get_char() != ',':
@ -690,19 +711,29 @@ def cmd_dealloc_memory(cmd, args):
return return
print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str) print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str)
def rsp_memory_bytes(cmd, cmd_args, rsp): def rsp_memory_bytes(options, cmd, cmd_args, rsp):
addr = Packet(cmd_args).get_hex_uint('big') addr = Packet(cmd_args).get_hex_uint('big')
dump_hex_memory_buffer (addr, rsp) dump_hex_memory_buffer (addr, rsp)
def get_register_name_equal_value(reg_num, hex_value_str): def get_register_name_equal_value(options, reg_num, hex_value_str):
if reg_num < len(g_register_infos): if reg_num < len(g_register_infos):
reg_info = g_register_infos[reg_num] reg_info = g_register_infos[reg_num]
return reg_info.name() + ' = ' + reg_info.get_value_from_hex_string (hex_value_str) value_str = reg_info.get_value_from_hex_string (hex_value_str)
s = reg_info.name() + ' = '
if options.symbolicator:
symbolicated_addresses = options.symbolicator.symbolicate (int(value_str, 0))
if symbolicated_addresses:
s += options.colors.magenta()
s += '%s' % symbolicated_addresses[0]
s += options.colors.reset()
return s
s += value_str
return s
else: else:
reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order) reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
return 'reg(%u) = 0x%x' % (reg_num, reg_value) return 'reg(%u) = 0x%x' % (reg_num, reg_value)
def cmd_read_one_reg(cmd, args): def cmd_read_one_reg(options, cmd, args):
packet = Packet(args) packet = Packet(args)
reg_num = packet.get_hex_uint('big') reg_num = packet.get_hex_uint('big')
tid = get_thread_from_thread_suffix (packet.str) tid = get_thread_from_thread_suffix (packet.str)
@ -721,12 +752,12 @@ def cmd_read_one_reg(cmd, args):
s += ')' s += ')'
print s print s
def rsp_read_one_reg(cmd, cmd_args, rsp): def rsp_read_one_reg(options, cmd, cmd_args, rsp):
packet = Packet(cmd_args) packet = Packet(cmd_args)
reg_num = packet.get_hex_uint('big') reg_num = packet.get_hex_uint('big')
print get_register_name_equal_value (reg_num, rsp) print get_register_name_equal_value (options, reg_num, rsp)
def cmd_write_one_reg(cmd, args): def cmd_write_one_reg(options, cmd, args):
packet = Packet(args) packet = Packet(args)
reg_num = packet.get_hex_uint('big') reg_num = packet.get_hex_uint('big')
if packet.get_char() != '=': if packet.get_char() != '=':
@ -739,7 +770,7 @@ def cmd_write_one_reg(cmd, args):
if name: if name:
s += ' (%s)' % (name) s += ' (%s)' % (name)
s += ', value = ' s += ', value = '
s += get_register_name_equal_value(reg_num, hex_value_str) s += get_register_name_equal_value(options, reg_num, hex_value_str)
if tid != None: if tid != None:
s += ', tid = 0x%4.4x' % (tid) s += ', tid = 0x%4.4x' % (tid)
s += ')' s += ')'
@ -764,18 +795,18 @@ def cmd_read_all_regs(cmd, cmd_args):
else: else:
print 'read_all_register()' print 'read_all_register()'
def rsp_read_all_regs(cmd, cmd_args, rsp): def rsp_read_all_regs(options, cmd, cmd_args, rsp):
packet = Packet(rsp) packet = Packet(rsp)
dump_all_regs (packet) dump_all_regs (packet)
def cmd_write_all_regs(cmd, args): def cmd_write_all_regs(options, cmd, args):
packet = Packet(args) packet = Packet(args)
print 'write_all_registers()' print 'write_all_registers()'
dump_all_regs (packet) dump_all_regs (packet)
g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ] g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ]
def cmd_bp(cmd, args): def cmd_bp(options, cmd, args):
if cmd == 'Z': if cmd == 'Z':
s = 'set_' s = 'set_'
else: else:
@ -790,13 +821,13 @@ def cmd_bp(cmd, args):
s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size) s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
print s print s
def cmd_mem_rgn_info(cmd, args): def cmd_mem_rgn_info(options, cmd, args):
packet = Packet(args) packet = Packet(args)
packet.get_char() # skip ':' character packet.get_char() # skip ':' character
addr = packet.get_hex_uint('big') addr = packet.get_hex_uint('big')
print 'get_memory_region_info (addr=0x%x)' % (addr) print 'get_memory_region_info (addr=0x%x)' % (addr)
def cmd_kill(cmd, args): def cmd_kill(options, cmd, args):
print 'kill_process()' print 'kill_process()'
gdb_remote_commands = { gdb_remote_commands = {
@ -845,7 +876,6 @@ def parse_gdb_log_file(file, options):
base_time = 0.0 base_time = 0.0
last_time = 0.0 last_time = 0.0
packet_send_time = 0.0 packet_send_time = 0.0
packet_name = None
packet_total_times = {} packet_total_times = {}
packet_count = {} packet_count = {}
file = open(file) file = open(file)
@ -854,12 +884,14 @@ def parse_gdb_log_file(file, options):
last_command_args = None last_command_args = None
last_command_packet = None last_command_packet = None
for line in lines: for line in lines:
packet_name = None
m = packet_transmit_name_regex.search(line) m = packet_transmit_name_regex.search(line)
is_command = False
if m: if m:
direction = m.group('direction') direction = m.group('direction')
is_command = direction == 'send' is_command = direction == 'send'
packet = m.group('packet') packet = m.group('packet')
options.colors.green() sys.stdout.write(options.colors.green())
if options.quiet: if options.quiet:
if is_command: if is_command:
print '-->', packet print '-->', packet
@ -867,7 +899,7 @@ def parse_gdb_log_file(file, options):
print '<--', packet print '<--', packet
else: else:
print '# ', line print '# ', line
options.colors.reset() sys.stdout.write(options.colors.reset())
#print 'direction = "%s", packet = "%s"' % (direction, packet) #print 'direction = "%s", packet = "%s"' % (direction, packet)
@ -883,15 +915,24 @@ def parse_gdb_log_file(file, options):
m = packet_names_regex.match (contents) m = packet_names_regex.match (contents)
if m: if m:
last_command = m.group(1) last_command = m.group(1)
packet_name = last_command
last_command_args = m.group(2) last_command_args = m.group(2)
last_command_packet = contents last_command_packet = contents
gdb_remote_commands[last_command]['cmd'](last_command, last_command_args) gdb_remote_commands[last_command]['cmd'](options, last_command, last_command_args)
else: else:
packet_match = packet_name_regex.match (line[idx+14:])
if packet_match:
packet_name = packet_match.group(1)
for tricky_cmd in tricky_commands:
if packet_name.find (tricky_cmd) == 0:
packet_name = tricky_cmd
else:
packet_name = contents
last_command = None last_command = None
last_command_args = None last_command_args = None
last_command_packet = None last_command_packet = None
elif last_command: elif last_command:
gdb_remote_commands[last_command]['rsp'](last_command, last_command_args, contents) gdb_remote_commands[last_command]['rsp'](options, last_command, last_command_args, contents)
else: else:
print 'error: invalid packet: "', packet, '"' print 'error: invalid packet: "', packet, '"'
else: else:
@ -906,15 +947,9 @@ def parse_gdb_log_file(file, options):
delta = curr_time - last_time delta = curr_time - last_time
else: else:
base_time = curr_time base_time = curr_time
idx = line.find('send packet: $')
if idx >= 0: if is_command:
packet_send_time = curr_time packet_send_time = curr_time
packet_match = packet_name_regex.match (line[idx+14:])
if packet_match:
packet_name = packet_match.group(1)
for tricky_cmd in tricky_commands:
if packet_name.find (tricky_cmd) == 0:
packet_name = tricky_cmd
elif line.find('read packet: $') >= 0 and packet_name: elif line.find('read packet: $') >= 0 and packet_name:
if packet_name in packet_total_times: if packet_name in packet_total_times:
packet_total_times[packet_name] += delta packet_total_times[packet_name] += delta
@ -963,7 +998,6 @@ def parse_gdb_log_file(file, options):
if __name__ == '__main__': if __name__ == '__main__':
import sys
usage = "usage: gdbremote [options]" usage = "usage: gdbremote [options]"
description='''The command disassembles a GDB remote packet log.''' description='''The command disassembles a GDB remote packet log.'''
parser = optparse.OptionParser(description=description, prog='gdbremote',usage=usage) parser = optparse.OptionParser(description=description, prog='gdbremote',usage=usage)
@ -971,13 +1005,21 @@ if __name__ == '__main__':
parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False) parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False)
parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False) parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False) parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
parser.add_option('--crashlog', type='string', dest='crashlog', help='symbolicate using a darwin crash log file', default=False)
try: try:
(options, args) = parser.parse_args(sys.argv[1:]) (options, args) = parser.parse_args(sys.argv[1:])
except: except:
print 'error: argument error' print 'error: argument error'
sys.exit(1) sys.exit(1)
options.colors = TerminalColors(sys.stdout, options.color) options.colors = TerminalColors(options.color)
options.symbolicator = None
if options.crashlog:
import lldb
lldb.debugger = lldb.SBDebugger.Create()
import lldb.macosx.crashlog
options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
print '%s' % (options.symbolicator)
# This script is being run from the command line, create a debugger in case we are # This script is being run from the command line, create a debugger in case we are
# going to use any debugger functions in our function. # going to use any debugger functions in our function.
@ -986,6 +1028,9 @@ if __name__ == '__main__':
print "# GDB remote log file: '%s'" % file print "# GDB remote log file: '%s'" % file
print '#----------------------------------------------------------------------' print '#----------------------------------------------------------------------'
parse_gdb_log_file (file, options) parse_gdb_log_file (file, options)
if options.symbolicator:
print '%s' % (options.symbolicator)
else: else:
import lldb import lldb
if lldb.debugger: if lldb.debugger:

View File

@ -193,6 +193,8 @@ class Image:
def __init__(self, path, uuid = None): def __init__(self, path, uuid = None):
self.path = path self.path = path
self.resolved_path = None self.resolved_path = None
self.resolved = False
self.unavailable = False
self.uuid = uuid self.uuid = uuid
self.section_infos = list() self.section_infos = list()
self.identifier = None self.identifier = None
@ -245,6 +247,8 @@ class Image:
return self.section_infos or self.slide != None return self.section_infos or self.slide != None
def load_module(self, target): def load_module(self, target):
if self.unavailable:
return None # We already warned that we couldn't find this module, so don't return an error string
# Load this module into "target" using the section infos to # Load this module into "target" using the section infos to
# set the section load addresses # set the section load addresses
if self.has_section_load_info(): if self.has_section_load_info():
@ -288,6 +292,8 @@ class Image:
self.module = target.AddModule (None, None, uuid_str) self.module = target.AddModule (None, None, uuid_str)
if not self.module: if not self.module:
self.locate_module_and_debug_symbols () self.locate_module_and_debug_symbols ()
if self.unavailable:
return None
resolved_path = self.get_resolved_path() resolved_path = self.get_resolved_path()
self.module = target.AddModule (resolved_path, self.arch, uuid_str, self.symfile) self.module = target.AddModule (resolved_path, self.arch, uuid_str, self.symfile)
if not self.module: if not self.module:
@ -306,6 +312,7 @@ class Image:
# self.module # self.module
# self.symfile # self.symfile
# Subclasses can inherit from this class and override this function # Subclasses can inherit from this class and override this function
self.resolved = True
return True return True
def get_uuid(self): def get_uuid(self):
@ -320,6 +327,9 @@ class Image:
def create_target(self): def create_target(self):
'''Create a target using the information in this Image object.''' '''Create a target using the information in this Image object.'''
if self.unavailable:
return None
if self.locate_module_and_debug_symbols (): if self.locate_module_and_debug_symbols ():
resolved_path = self.get_resolved_path(); resolved_path = self.get_resolved_path();
path_spec = lldb.SBFileSpec (resolved_path) path_spec = lldb.SBFileSpec (resolved_path)
@ -368,7 +378,7 @@ class Symbolicator:
def find_image_containing_load_addr(self, load_addr): def find_image_containing_load_addr(self, load_addr):
for image in self.images: for image in self.images:
if image.contains_addr (load_addr): if image.get_section_containing_load_addr (load_addr):
return image return image
return None return None
@ -384,32 +394,39 @@ class Symbolicator:
return None return None
def symbolicate(self, load_addr): def symbolicate(self, load_addr):
if not self.target:
self.create_target()
if self.target: if self.target:
symbolicated_address = Address(self.target, load_addr) image = self.find_image_containing_load_addr (load_addr)
if symbolicated_address.symbolicate (): if image:
image.add_module (self.target)
symbolicated_address = Address(self.target, load_addr)
if symbolicated_address.symbolicate ():
if symbolicated_address.so_addr: if symbolicated_address.so_addr:
symbolicated_addresses = list() symbolicated_addresses = list()
symbolicated_addresses.append(symbolicated_address) symbolicated_addresses.append(symbolicated_address)
# See if we were able to reconstruct anything? # See if we were able to reconstruct anything?
while 1: while 1:
inlined_parent_so_addr = lldb.SBAddress() inlined_parent_so_addr = lldb.SBAddress()
inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope (symbolicated_address.so_addr, inlined_parent_so_addr) inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope (symbolicated_address.so_addr, inlined_parent_so_addr)
if not inlined_parent_sym_ctx: if not inlined_parent_sym_ctx:
break break
if not inlined_parent_so_addr: if not inlined_parent_so_addr:
break break
symbolicated_address = Address(self.target, inlined_parent_so_addr.GetLoadAddress(self.target)) symbolicated_address = Address(self.target, inlined_parent_so_addr.GetLoadAddress(self.target))
symbolicated_address.sym_ctx = inlined_parent_sym_ctx symbolicated_address.sym_ctx = inlined_parent_sym_ctx
symbolicated_address.so_addr = inlined_parent_so_addr symbolicated_address.so_addr = inlined_parent_so_addr
symbolicated_address.symbolicate () symbolicated_address.symbolicate ()
# push the new frame onto the new frame stack # push the new frame onto the new frame stack
symbolicated_addresses.append (symbolicated_address) symbolicated_addresses.append (symbolicated_address)
if symbolicated_addresses: if symbolicated_addresses:
return symbolicated_addresses return symbolicated_addresses
else:
print 'error: no target in Symbolicator'
return None return None